editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//!
   11//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   12//!
   13//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   14pub mod actions;
   15mod blink_manager;
   16mod clangd_ext;
   17pub mod code_context_menus;
   18pub mod display_map;
   19mod editor_settings;
   20mod element;
   21mod git;
   22mod highlight_matching_bracket;
   23mod hover_links;
   24pub mod hover_popover;
   25mod indent_guides;
   26mod inlays;
   27pub mod items;
   28mod jsx_tag_auto_close;
   29mod linked_editing_ranges;
   30mod lsp_colors;
   31mod lsp_ext;
   32mod mouse_context_menu;
   33pub mod movement;
   34mod persistence;
   35mod rust_analyzer_ext;
   36pub mod scroll;
   37mod selections_collection;
   38pub mod tasks;
   39
   40#[cfg(test)]
   41mod code_completion_tests;
   42#[cfg(test)]
   43mod edit_prediction_tests;
   44#[cfg(test)]
   45mod editor_tests;
   46mod signature_help;
   47#[cfg(any(test, feature = "test-support"))]
   48pub mod test;
   49
   50pub(crate) use actions::*;
   51pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   52pub use edit_prediction::Direction;
   53pub use editor_settings::{
   54    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   55    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
   56};
   57pub use element::{
   58    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   59};
   60pub use git::blame::BlameRenderer;
   61pub use hover_popover::hover_markdown_style;
   62pub use inlays::Inlay;
   63pub use items::MAX_TAB_TITLE_LEN;
   64pub use lsp::CompletionContext;
   65pub use lsp_ext::lsp_tasks;
   66pub use multi_buffer::{
   67    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
   68    RowInfo, ToOffset, ToPoint,
   69};
   70pub use text::Bias;
   71
   72use ::git::{
   73    Restore,
   74    blame::{BlameEntry, ParsedCommitMessage},
   75    status::FileStatus,
   76};
   77use aho_corasick::AhoCorasick;
   78use anyhow::{Context as _, Result, anyhow};
   79use blink_manager::BlinkManager;
   80use buffer_diff::DiffHunkStatus;
   81use client::{Collaborator, ParticipantIndex, parse_zed_link};
   82use clock::ReplicaId;
   83use code_context_menus::{
   84    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   85    CompletionsMenu, ContextMenuOrigin,
   86};
   87use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   88use convert_case::{Case, Casing};
   89use dap::TelemetrySpawnLocation;
   90use display_map::*;
   91use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};
   92use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   93use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   94use futures::{
   95    FutureExt, StreamExt as _,
   96    future::{self, Shared, join},
   97    stream::FuturesUnordered,
   98};
   99use fuzzy::{StringMatch, StringMatchCandidate};
  100use git::blame::{GitBlame, GlobalBlameRenderer};
  101use gpui::{
  102    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  103    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  104    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  105    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  106    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
  107    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
  108    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
  109    div, point, prelude::*, pulsating_between, px, relative, size,
  110};
  111use hover_links::{HoverLink, HoveredLinkState, find_file};
  112use hover_popover::{HoverState, hide_hover};
  113use indent_guides::ActiveIndentGuidesState;
  114use inlays::{InlaySplice, inlay_hints::InlayHintRefreshReason};
  115use itertools::{Either, Itertools};
  116use language::{
  117    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  118    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  119    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  120    IndentSize, Language, OffsetRangeExt, Point, Runnable, RunnableRange, Selection, SelectionGoal,
  121    TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  122    language_settings::{
  123        self, LspInsertMode, RewrapBehavior, WordsCompletionMode, all_language_settings,
  124        language_settings,
  125    },
  126    point_from_lsp, point_to_lsp, text_diff_with_options,
  127};
  128use linked_editing_ranges::refresh_linked_ranges;
  129use lsp::{
  130    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  131    LanguageServerId,
  132};
  133use lsp_colors::LspColorData;
  134use markdown::Markdown;
  135use mouse_context_menu::MouseContextMenu;
  136use movement::TextLayoutDetails;
  137use multi_buffer::{
  138    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  139};
  140use parking_lot::Mutex;
  141use persistence::DB;
  142use project::{
  143    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  144    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, InlayId,
  145    InvalidationStrategy, Location, LocationLink, PrepareRenameResponse, Project, ProjectItem,
  146    ProjectPath, ProjectTransaction, TaskSourceKind,
  147    debugger::{
  148        breakpoint_store::{
  149            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  150            BreakpointStore, BreakpointStoreEvent,
  151        },
  152        session::{Session, SessionEvent},
  153    },
  154    git_store::GitStoreEvent,
  155    lsp_store::{
  156        CacheInlayHints, CompletionDocumentation, FormatTrigger, LspFormatTarget,
  157        OpenLspBufferHandle,
  158    },
  159    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  160};
  161use rand::seq::SliceRandom;
  162use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  163use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  164use selections_collection::{MutableSelectionsCollection, SelectionsCollection};
  165use serde::{Deserialize, Serialize};
  166use settings::{
  167    GitGutterSetting, RelativeLineNumbers, Settings, SettingsLocation, SettingsStore,
  168    update_settings_file,
  169};
  170use smallvec::{SmallVec, smallvec};
  171use snippet::Snippet;
  172use std::{
  173    any::{Any, TypeId},
  174    borrow::Cow,
  175    cell::{OnceCell, RefCell},
  176    cmp::{self, Ordering, Reverse},
  177    iter::{self, Peekable},
  178    mem,
  179    num::NonZeroU32,
  180    ops::{Deref, DerefMut, Not, Range, RangeInclusive},
  181    path::{Path, PathBuf},
  182    rc::Rc,
  183    sync::Arc,
  184    time::{Duration, Instant},
  185};
  186use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  187use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
  188use theme::{
  189    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  190    observe_buffer_font_size_adjustment,
  191};
  192use ui::{
  193    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  194    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  195};
  196use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  197use workspace::{
  198    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  199    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  200    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  201    item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  202    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  203    searchable::SearchEvent,
  204};
  205
  206use crate::{
  207    code_context_menus::CompletionsMenuSource,
  208    editor_settings::MultiCursorModifier,
  209    hover_links::{find_url, find_url_from_range},
  210    inlays::{
  211        InlineValueCache,
  212        inlay_hints::{LspInlayHintData, inlay_hint_settings},
  213    },
  214    scroll::{ScrollOffset, ScrollPixelOffset},
  215    selections_collection::resolve_selections_wrapping_blocks,
  216    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  217};
  218
  219pub const FILE_HEADER_HEIGHT: u32 = 2;
  220pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  221const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  222const MAX_LINE_LEN: usize = 1024;
  223const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  224const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  225pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  226#[doc(hidden)]
  227pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  228pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  229
  230pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  231pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  232pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  233pub const FETCH_COLORS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(150);
  234
  235pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  236pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  237pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  238
  239pub type RenderDiffHunkControlsFn = Arc<
  240    dyn Fn(
  241        u32,
  242        &DiffHunkStatus,
  243        Range<Anchor>,
  244        bool,
  245        Pixels,
  246        &Entity<Editor>,
  247        &mut Window,
  248        &mut App,
  249    ) -> AnyElement,
  250>;
  251
  252enum ReportEditorEvent {
  253    Saved { auto_saved: bool },
  254    EditorOpened,
  255    Closed,
  256}
  257
  258impl ReportEditorEvent {
  259    pub fn event_type(&self) -> &'static str {
  260        match self {
  261            Self::Saved { .. } => "Editor Saved",
  262            Self::EditorOpened => "Editor Opened",
  263            Self::Closed => "Editor Closed",
  264        }
  265    }
  266}
  267
  268pub enum ActiveDebugLine {}
  269pub enum DebugStackFrameLine {}
  270enum DocumentHighlightRead {}
  271enum DocumentHighlightWrite {}
  272enum InputComposition {}
  273pub enum PendingInput {}
  274enum SelectedTextHighlight {}
  275
  276pub enum ConflictsOuter {}
  277pub enum ConflictsOurs {}
  278pub enum ConflictsTheirs {}
  279pub enum ConflictsOursMarker {}
  280pub enum ConflictsTheirsMarker {}
  281
  282#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  283pub enum Navigated {
  284    Yes,
  285    No,
  286}
  287
  288impl Navigated {
  289    pub fn from_bool(yes: bool) -> Navigated {
  290        if yes { Navigated::Yes } else { Navigated::No }
  291    }
  292}
  293
  294#[derive(Debug, Clone, PartialEq, Eq)]
  295enum DisplayDiffHunk {
  296    Folded {
  297        display_row: DisplayRow,
  298    },
  299    Unfolded {
  300        is_created_file: bool,
  301        diff_base_byte_range: Range<usize>,
  302        display_row_range: Range<DisplayRow>,
  303        multi_buffer_range: Range<Anchor>,
  304        status: DiffHunkStatus,
  305    },
  306}
  307
  308pub enum HideMouseCursorOrigin {
  309    TypingAction,
  310    MovementAction,
  311}
  312
  313pub fn init_settings(cx: &mut App) {
  314    EditorSettings::register(cx);
  315}
  316
  317pub fn init(cx: &mut App) {
  318    init_settings(cx);
  319
  320    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  321
  322    workspace::register_project_item::<Editor>(cx);
  323    workspace::FollowableViewRegistry::register::<Editor>(cx);
  324    workspace::register_serializable_item::<Editor>(cx);
  325
  326    cx.observe_new(
  327        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  328            workspace.register_action(Editor::new_file);
  329            workspace.register_action(Editor::new_file_split);
  330            workspace.register_action(Editor::new_file_vertical);
  331            workspace.register_action(Editor::new_file_horizontal);
  332            workspace.register_action(Editor::cancel_language_server_work);
  333            workspace.register_action(Editor::toggle_focus);
  334        },
  335    )
  336    .detach();
  337
  338    cx.on_action(move |_: &workspace::NewFile, cx| {
  339        let app_state = workspace::AppState::global(cx);
  340        if let Some(app_state) = app_state.upgrade() {
  341            workspace::open_new(
  342                Default::default(),
  343                app_state,
  344                cx,
  345                |workspace, window, cx| {
  346                    Editor::new_file(workspace, &Default::default(), window, cx)
  347                },
  348            )
  349            .detach();
  350        }
  351    });
  352    cx.on_action(move |_: &workspace::NewWindow, cx| {
  353        let app_state = workspace::AppState::global(cx);
  354        if let Some(app_state) = app_state.upgrade() {
  355            workspace::open_new(
  356                Default::default(),
  357                app_state,
  358                cx,
  359                |workspace, window, cx| {
  360                    cx.activate(true);
  361                    Editor::new_file(workspace, &Default::default(), window, cx)
  362                },
  363            )
  364            .detach();
  365        }
  366    });
  367}
  368
  369pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  370    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  371}
  372
  373pub trait DiagnosticRenderer {
  374    fn render_group(
  375        &self,
  376        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  377        buffer_id: BufferId,
  378        snapshot: EditorSnapshot,
  379        editor: WeakEntity<Editor>,
  380        cx: &mut App,
  381    ) -> Vec<BlockProperties<Anchor>>;
  382
  383    fn render_hover(
  384        &self,
  385        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  386        range: Range<Point>,
  387        buffer_id: BufferId,
  388        cx: &mut App,
  389    ) -> Option<Entity<markdown::Markdown>>;
  390
  391    fn open_link(
  392        &self,
  393        editor: &mut Editor,
  394        link: SharedString,
  395        window: &mut Window,
  396        cx: &mut Context<Editor>,
  397    );
  398}
  399
  400pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  401
  402impl GlobalDiagnosticRenderer {
  403    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  404        cx.try_global::<Self>().map(|g| g.0.clone())
  405    }
  406}
  407
  408impl gpui::Global for GlobalDiagnosticRenderer {}
  409pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  410    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  411}
  412
  413pub struct SearchWithinRange;
  414
  415trait InvalidationRegion {
  416    fn ranges(&self) -> &[Range<Anchor>];
  417}
  418
  419#[derive(Clone, Debug, PartialEq)]
  420pub enum SelectPhase {
  421    Begin {
  422        position: DisplayPoint,
  423        add: bool,
  424        click_count: usize,
  425    },
  426    BeginColumnar {
  427        position: DisplayPoint,
  428        reset: bool,
  429        mode: ColumnarMode,
  430        goal_column: u32,
  431    },
  432    Extend {
  433        position: DisplayPoint,
  434        click_count: usize,
  435    },
  436    Update {
  437        position: DisplayPoint,
  438        goal_column: u32,
  439        scroll_delta: gpui::Point<f32>,
  440    },
  441    End,
  442}
  443
  444#[derive(Clone, Debug, PartialEq)]
  445pub enum ColumnarMode {
  446    FromMouse,
  447    FromSelection,
  448}
  449
  450#[derive(Clone, Debug)]
  451pub enum SelectMode {
  452    Character,
  453    Word(Range<Anchor>),
  454    Line(Range<Anchor>),
  455    All,
  456}
  457
  458#[derive(Copy, Clone, Default, PartialEq, Eq, Debug)]
  459pub enum SizingBehavior {
  460    /// The editor will layout itself using `size_full` and will include the vertical
  461    /// scroll margin as requested by user settings.
  462    #[default]
  463    Default,
  464    /// The editor will layout itself using `size_full`, but will not have any
  465    /// vertical overscroll.
  466    ExcludeOverscrollMargin,
  467    /// The editor will request a vertical size according to its content and will be
  468    /// layouted without a vertical scroll margin.
  469    SizeByContent,
  470}
  471
  472#[derive(Clone, PartialEq, Eq, Debug)]
  473pub enum EditorMode {
  474    SingleLine,
  475    AutoHeight {
  476        min_lines: usize,
  477        max_lines: Option<usize>,
  478    },
  479    Full {
  480        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  481        scale_ui_elements_with_buffer_font_size: bool,
  482        /// When set to `true`, the editor will render a background for the active line.
  483        show_active_line_background: bool,
  484        /// Determines the sizing behavior for this editor
  485        sizing_behavior: SizingBehavior,
  486    },
  487    Minimap {
  488        parent: WeakEntity<Editor>,
  489    },
  490}
  491
  492impl EditorMode {
  493    pub fn full() -> Self {
  494        Self::Full {
  495            scale_ui_elements_with_buffer_font_size: true,
  496            show_active_line_background: true,
  497            sizing_behavior: SizingBehavior::Default,
  498        }
  499    }
  500
  501    #[inline]
  502    pub fn is_full(&self) -> bool {
  503        matches!(self, Self::Full { .. })
  504    }
  505
  506    #[inline]
  507    pub fn is_single_line(&self) -> bool {
  508        matches!(self, Self::SingleLine { .. })
  509    }
  510
  511    #[inline]
  512    fn is_minimap(&self) -> bool {
  513        matches!(self, Self::Minimap { .. })
  514    }
  515}
  516
  517#[derive(Copy, Clone, Debug)]
  518pub enum SoftWrap {
  519    /// Prefer not to wrap at all.
  520    ///
  521    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  522    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  523    GitDiff,
  524    /// Prefer a single line generally, unless an overly long line is encountered.
  525    None,
  526    /// Soft wrap lines that exceed the editor width.
  527    EditorWidth,
  528    /// Soft wrap lines at the preferred line length.
  529    Column(u32),
  530    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  531    Bounded(u32),
  532}
  533
  534#[derive(Clone)]
  535pub struct EditorStyle {
  536    pub background: Hsla,
  537    pub border: Hsla,
  538    pub local_player: PlayerColor,
  539    pub text: TextStyle,
  540    pub scrollbar_width: Pixels,
  541    pub syntax: Arc<SyntaxTheme>,
  542    pub status: StatusColors,
  543    pub inlay_hints_style: HighlightStyle,
  544    pub edit_prediction_styles: EditPredictionStyles,
  545    pub unnecessary_code_fade: f32,
  546    pub show_underlines: bool,
  547}
  548
  549impl Default for EditorStyle {
  550    fn default() -> Self {
  551        Self {
  552            background: Hsla::default(),
  553            border: Hsla::default(),
  554            local_player: PlayerColor::default(),
  555            text: TextStyle::default(),
  556            scrollbar_width: Pixels::default(),
  557            syntax: Default::default(),
  558            // HACK: Status colors don't have a real default.
  559            // We should look into removing the status colors from the editor
  560            // style and retrieve them directly from the theme.
  561            status: StatusColors::dark(),
  562            inlay_hints_style: HighlightStyle::default(),
  563            edit_prediction_styles: EditPredictionStyles {
  564                insertion: HighlightStyle::default(),
  565                whitespace: HighlightStyle::default(),
  566            },
  567            unnecessary_code_fade: Default::default(),
  568            show_underlines: true,
  569        }
  570    }
  571}
  572
  573pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  574    let show_background = language_settings::language_settings(None, None, cx)
  575        .inlay_hints
  576        .show_background;
  577
  578    let mut style = cx.theme().syntax().get("hint");
  579
  580    if style.color.is_none() {
  581        style.color = Some(cx.theme().status().hint);
  582    }
  583
  584    if !show_background {
  585        style.background_color = None;
  586        return style;
  587    }
  588
  589    if style.background_color.is_none() {
  590        style.background_color = Some(cx.theme().status().hint_background);
  591    }
  592
  593    style
  594}
  595
  596pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  597    EditPredictionStyles {
  598        insertion: HighlightStyle {
  599            color: Some(cx.theme().status().predictive),
  600            ..HighlightStyle::default()
  601        },
  602        whitespace: HighlightStyle {
  603            background_color: Some(cx.theme().status().created_background),
  604            ..HighlightStyle::default()
  605        },
  606    }
  607}
  608
  609type CompletionId = usize;
  610
  611pub(crate) enum EditDisplayMode {
  612    TabAccept,
  613    DiffPopover,
  614    Inline,
  615}
  616
  617enum EditPrediction {
  618    Edit {
  619        edits: Vec<(Range<Anchor>, String)>,
  620        edit_preview: Option<EditPreview>,
  621        display_mode: EditDisplayMode,
  622        snapshot: BufferSnapshot,
  623    },
  624    /// Move to a specific location in the active editor
  625    MoveWithin {
  626        target: Anchor,
  627        snapshot: BufferSnapshot,
  628    },
  629    /// Move to a specific location in a different editor (not the active one)
  630    MoveOutside {
  631        target: language::Anchor,
  632        snapshot: BufferSnapshot,
  633    },
  634}
  635
  636struct EditPredictionState {
  637    inlay_ids: Vec<InlayId>,
  638    completion: EditPrediction,
  639    completion_id: Option<SharedString>,
  640    invalidation_range: Option<Range<Anchor>>,
  641}
  642
  643enum EditPredictionSettings {
  644    Disabled,
  645    Enabled {
  646        show_in_menu: bool,
  647        preview_requires_modifier: bool,
  648    },
  649}
  650
  651enum EditPredictionHighlight {}
  652
  653#[derive(Debug, Clone)]
  654struct InlineDiagnostic {
  655    message: SharedString,
  656    group_id: usize,
  657    is_primary: bool,
  658    start: Point,
  659    severity: lsp::DiagnosticSeverity,
  660}
  661
  662pub enum MenuEditPredictionsPolicy {
  663    Never,
  664    ByProvider,
  665}
  666
  667pub enum EditPredictionPreview {
  668    /// Modifier is not pressed
  669    Inactive { released_too_fast: bool },
  670    /// Modifier pressed
  671    Active {
  672        since: Instant,
  673        previous_scroll_position: Option<ScrollAnchor>,
  674    },
  675}
  676
  677impl EditPredictionPreview {
  678    pub fn released_too_fast(&self) -> bool {
  679        match self {
  680            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  681            EditPredictionPreview::Active { .. } => false,
  682        }
  683    }
  684
  685    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  686        if let EditPredictionPreview::Active {
  687            previous_scroll_position,
  688            ..
  689        } = self
  690        {
  691            *previous_scroll_position = scroll_position;
  692        }
  693    }
  694}
  695
  696pub struct ContextMenuOptions {
  697    pub min_entries_visible: usize,
  698    pub max_entries_visible: usize,
  699    pub placement: Option<ContextMenuPlacement>,
  700}
  701
  702#[derive(Debug, Clone, PartialEq, Eq)]
  703pub enum ContextMenuPlacement {
  704    Above,
  705    Below,
  706}
  707
  708#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  709struct EditorActionId(usize);
  710
  711impl EditorActionId {
  712    pub fn post_inc(&mut self) -> Self {
  713        let answer = self.0;
  714
  715        *self = Self(answer + 1);
  716
  717        Self(answer)
  718    }
  719}
  720
  721// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  722// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  723
  724type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  725type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  726
  727#[derive(Default)]
  728struct ScrollbarMarkerState {
  729    scrollbar_size: Size<Pixels>,
  730    dirty: bool,
  731    markers: Arc<[PaintQuad]>,
  732    pending_refresh: Option<Task<Result<()>>>,
  733}
  734
  735impl ScrollbarMarkerState {
  736    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  737        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  738    }
  739}
  740
  741#[derive(Clone, Copy, PartialEq, Eq)]
  742pub enum MinimapVisibility {
  743    Disabled,
  744    Enabled {
  745        /// The configuration currently present in the users settings.
  746        setting_configuration: bool,
  747        /// Whether to override the currently set visibility from the users setting.
  748        toggle_override: bool,
  749    },
  750}
  751
  752impl MinimapVisibility {
  753    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  754        if mode.is_full() {
  755            Self::Enabled {
  756                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  757                toggle_override: false,
  758            }
  759        } else {
  760            Self::Disabled
  761        }
  762    }
  763
  764    fn hidden(&self) -> Self {
  765        match *self {
  766            Self::Enabled {
  767                setting_configuration,
  768                ..
  769            } => Self::Enabled {
  770                setting_configuration,
  771                toggle_override: setting_configuration,
  772            },
  773            Self::Disabled => Self::Disabled,
  774        }
  775    }
  776
  777    fn disabled(&self) -> bool {
  778        matches!(*self, Self::Disabled)
  779    }
  780
  781    fn settings_visibility(&self) -> bool {
  782        match *self {
  783            Self::Enabled {
  784                setting_configuration,
  785                ..
  786            } => setting_configuration,
  787            _ => false,
  788        }
  789    }
  790
  791    fn visible(&self) -> bool {
  792        match *self {
  793            Self::Enabled {
  794                setting_configuration,
  795                toggle_override,
  796            } => setting_configuration ^ toggle_override,
  797            _ => false,
  798        }
  799    }
  800
  801    fn toggle_visibility(&self) -> Self {
  802        match *self {
  803            Self::Enabled {
  804                toggle_override,
  805                setting_configuration,
  806            } => Self::Enabled {
  807                setting_configuration,
  808                toggle_override: !toggle_override,
  809            },
  810            Self::Disabled => Self::Disabled,
  811        }
  812    }
  813}
  814
  815#[derive(Clone, Debug)]
  816struct RunnableTasks {
  817    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  818    offset: multi_buffer::Anchor,
  819    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  820    column: u32,
  821    // Values of all named captures, including those starting with '_'
  822    extra_variables: HashMap<String, String>,
  823    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  824    context_range: Range<BufferOffset>,
  825}
  826
  827impl RunnableTasks {
  828    fn resolve<'a>(
  829        &'a self,
  830        cx: &'a task::TaskContext,
  831    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  832        self.templates.iter().filter_map(|(kind, template)| {
  833            template
  834                .resolve_task(&kind.to_id_base(), cx)
  835                .map(|task| (kind.clone(), task))
  836        })
  837    }
  838}
  839
  840#[derive(Clone)]
  841pub struct ResolvedTasks {
  842    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  843    position: Anchor,
  844}
  845
  846#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  847struct BufferOffset(usize);
  848
  849/// Addons allow storing per-editor state in other crates (e.g. Vim)
  850pub trait Addon: 'static {
  851    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  852
  853    fn render_buffer_header_controls(
  854        &self,
  855        _: &ExcerptInfo,
  856        _: &Window,
  857        _: &App,
  858    ) -> Option<AnyElement> {
  859        None
  860    }
  861
  862    fn override_status_for_buffer_id(&self, _: BufferId, _: &App) -> Option<FileStatus> {
  863        None
  864    }
  865
  866    fn to_any(&self) -> &dyn std::any::Any;
  867
  868    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  869        None
  870    }
  871}
  872
  873struct ChangeLocation {
  874    current: Option<Vec<Anchor>>,
  875    original: Vec<Anchor>,
  876}
  877impl ChangeLocation {
  878    fn locations(&self) -> &[Anchor] {
  879        self.current.as_ref().unwrap_or(&self.original)
  880    }
  881}
  882
  883/// A set of caret positions, registered when the editor was edited.
  884pub struct ChangeList {
  885    changes: Vec<ChangeLocation>,
  886    /// Currently "selected" change.
  887    position: Option<usize>,
  888}
  889
  890impl ChangeList {
  891    pub fn new() -> Self {
  892        Self {
  893            changes: Vec::new(),
  894            position: None,
  895        }
  896    }
  897
  898    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  899    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  900    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  901        if self.changes.is_empty() {
  902            return None;
  903        }
  904
  905        let prev = self.position.unwrap_or(self.changes.len());
  906        let next = if direction == Direction::Prev {
  907            prev.saturating_sub(count)
  908        } else {
  909            (prev + count).min(self.changes.len() - 1)
  910        };
  911        self.position = Some(next);
  912        self.changes.get(next).map(|change| change.locations())
  913    }
  914
  915    /// Adds a new change to the list, resetting the change list position.
  916    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  917        self.position.take();
  918        if let Some(last) = self.changes.last_mut()
  919            && group
  920        {
  921            last.current = Some(new_positions)
  922        } else {
  923            self.changes.push(ChangeLocation {
  924                original: new_positions,
  925                current: None,
  926            });
  927        }
  928    }
  929
  930    pub fn last(&self) -> Option<&[Anchor]> {
  931        self.changes.last().map(|change| change.locations())
  932    }
  933
  934    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  935        self.changes.last().map(|change| change.original.as_slice())
  936    }
  937
  938    pub fn invert_last_group(&mut self) {
  939        if let Some(last) = self.changes.last_mut()
  940            && let Some(current) = last.current.as_mut()
  941        {
  942            mem::swap(&mut last.original, current);
  943        }
  944    }
  945}
  946
  947#[derive(Clone)]
  948struct InlineBlamePopoverState {
  949    scroll_handle: ScrollHandle,
  950    commit_message: Option<ParsedCommitMessage>,
  951    markdown: Entity<Markdown>,
  952}
  953
  954struct InlineBlamePopover {
  955    position: gpui::Point<Pixels>,
  956    hide_task: Option<Task<()>>,
  957    popover_bounds: Option<Bounds<Pixels>>,
  958    popover_state: InlineBlamePopoverState,
  959    keyboard_grace: bool,
  960}
  961
  962enum SelectionDragState {
  963    /// State when no drag related activity is detected.
  964    None,
  965    /// State when the mouse is down on a selection that is about to be dragged.
  966    ReadyToDrag {
  967        selection: Selection<Anchor>,
  968        click_position: gpui::Point<Pixels>,
  969        mouse_down_time: Instant,
  970    },
  971    /// State when the mouse is dragging the selection in the editor.
  972    Dragging {
  973        selection: Selection<Anchor>,
  974        drop_cursor: Selection<Anchor>,
  975        hide_drop_cursor: bool,
  976    },
  977}
  978
  979enum ColumnarSelectionState {
  980    FromMouse {
  981        selection_tail: Anchor,
  982        display_point: Option<DisplayPoint>,
  983    },
  984    FromSelection {
  985        selection_tail: Anchor,
  986    },
  987}
  988
  989/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  990/// a breakpoint on them.
  991#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  992struct PhantomBreakpointIndicator {
  993    display_row: DisplayRow,
  994    /// There's a small debounce between hovering over the line and showing the indicator.
  995    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  996    is_active: bool,
  997    collides_with_existing_breakpoint: bool,
  998}
  999
 1000/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1001///
 1002/// See the [module level documentation](self) for more information.
 1003pub struct Editor {
 1004    focus_handle: FocusHandle,
 1005    last_focused_descendant: Option<WeakFocusHandle>,
 1006    /// The text buffer being edited
 1007    buffer: Entity<MultiBuffer>,
 1008    /// Map of how text in the buffer should be displayed.
 1009    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1010    pub display_map: Entity<DisplayMap>,
 1011    placeholder_display_map: Option<Entity<DisplayMap>>,
 1012    pub selections: SelectionsCollection,
 1013    pub scroll_manager: ScrollManager,
 1014    /// When inline assist editors are linked, they all render cursors because
 1015    /// typing enters text into each of them, even the ones that aren't focused.
 1016    pub(crate) show_cursor_when_unfocused: bool,
 1017    columnar_selection_state: Option<ColumnarSelectionState>,
 1018    add_selections_state: Option<AddSelectionsState>,
 1019    select_next_state: Option<SelectNextState>,
 1020    select_prev_state: Option<SelectNextState>,
 1021    selection_history: SelectionHistory,
 1022    defer_selection_effects: bool,
 1023    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1024    autoclose_regions: Vec<AutocloseRegion>,
 1025    snippet_stack: InvalidationStack<SnippetState>,
 1026    select_syntax_node_history: SelectSyntaxNodeHistory,
 1027    ime_transaction: Option<TransactionId>,
 1028    pub diagnostics_max_severity: DiagnosticSeverity,
 1029    active_diagnostics: ActiveDiagnostic,
 1030    show_inline_diagnostics: bool,
 1031    inline_diagnostics_update: Task<()>,
 1032    inline_diagnostics_enabled: bool,
 1033    diagnostics_enabled: bool,
 1034    word_completions_enabled: bool,
 1035    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1036    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1037    hard_wrap: Option<usize>,
 1038    project: Option<Entity<Project>>,
 1039    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1040    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1041    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1042    blink_manager: Entity<BlinkManager>,
 1043    show_cursor_names: bool,
 1044    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1045    pub show_local_selections: bool,
 1046    mode: EditorMode,
 1047    show_breadcrumbs: bool,
 1048    show_gutter: bool,
 1049    show_scrollbars: ScrollbarAxes,
 1050    minimap_visibility: MinimapVisibility,
 1051    offset_content: bool,
 1052    disable_expand_excerpt_buttons: bool,
 1053    show_line_numbers: Option<bool>,
 1054    use_relative_line_numbers: Option<bool>,
 1055    show_git_diff_gutter: Option<bool>,
 1056    show_code_actions: Option<bool>,
 1057    show_runnables: Option<bool>,
 1058    show_breakpoints: Option<bool>,
 1059    show_wrap_guides: Option<bool>,
 1060    show_indent_guides: Option<bool>,
 1061    highlight_order: usize,
 1062    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1063    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1064    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1065    scrollbar_marker_state: ScrollbarMarkerState,
 1066    active_indent_guides_state: ActiveIndentGuidesState,
 1067    nav_history: Option<ItemNavHistory>,
 1068    context_menu: RefCell<Option<CodeContextMenu>>,
 1069    context_menu_options: Option<ContextMenuOptions>,
 1070    mouse_context_menu: Option<MouseContextMenu>,
 1071    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1072    inline_blame_popover: Option<InlineBlamePopover>,
 1073    inline_blame_popover_show_task: Option<Task<()>>,
 1074    signature_help_state: SignatureHelpState,
 1075    auto_signature_help: Option<bool>,
 1076    find_all_references_task_sources: Vec<Anchor>,
 1077    next_completion_id: CompletionId,
 1078    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1079    code_actions_task: Option<Task<Result<()>>>,
 1080    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1081    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1082    document_highlights_task: Option<Task<()>>,
 1083    linked_editing_range_task: Option<Task<Option<()>>>,
 1084    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1085    pending_rename: Option<RenameState>,
 1086    searchable: bool,
 1087    cursor_shape: CursorShape,
 1088    current_line_highlight: Option<CurrentLineHighlight>,
 1089    autoindent_mode: Option<AutoindentMode>,
 1090    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1091    input_enabled: bool,
 1092    use_modal_editing: bool,
 1093    read_only: bool,
 1094    leader_id: Option<CollaboratorId>,
 1095    remote_id: Option<ViewId>,
 1096    pub hover_state: HoverState,
 1097    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1098    gutter_hovered: bool,
 1099    hovered_link_state: Option<HoveredLinkState>,
 1100    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1101    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1102    active_edit_prediction: Option<EditPredictionState>,
 1103    /// Used to prevent flickering as the user types while the menu is open
 1104    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1105    edit_prediction_settings: EditPredictionSettings,
 1106    edit_predictions_hidden_for_vim_mode: bool,
 1107    show_edit_predictions_override: Option<bool>,
 1108    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1109    edit_prediction_preview: EditPredictionPreview,
 1110    edit_prediction_indent_conflict: bool,
 1111    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1112    next_inlay_id: usize,
 1113    next_color_inlay_id: usize,
 1114    _subscriptions: Vec<Subscription>,
 1115    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1116    gutter_dimensions: GutterDimensions,
 1117    style: Option<EditorStyle>,
 1118    text_style_refinement: Option<TextStyleRefinement>,
 1119    next_editor_action_id: EditorActionId,
 1120    editor_actions: Rc<
 1121        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1122    >,
 1123    use_autoclose: bool,
 1124    use_auto_surround: bool,
 1125    auto_replace_emoji_shortcode: bool,
 1126    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1127    show_git_blame_gutter: bool,
 1128    show_git_blame_inline: bool,
 1129    show_git_blame_inline_delay_task: Option<Task<()>>,
 1130    git_blame_inline_enabled: bool,
 1131    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1132    serialize_dirty_buffers: bool,
 1133    show_selection_menu: Option<bool>,
 1134    blame: Option<Entity<GitBlame>>,
 1135    blame_subscription: Option<Subscription>,
 1136    custom_context_menu: Option<
 1137        Box<
 1138            dyn 'static
 1139                + Fn(
 1140                    &mut Self,
 1141                    DisplayPoint,
 1142                    &mut Window,
 1143                    &mut Context<Self>,
 1144                ) -> Option<Entity<ui::ContextMenu>>,
 1145        >,
 1146    >,
 1147    last_bounds: Option<Bounds<Pixels>>,
 1148    last_position_map: Option<Rc<PositionMap>>,
 1149    expect_bounds_change: Option<Bounds<Pixels>>,
 1150    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1151    tasks_update_task: Option<Task<()>>,
 1152    breakpoint_store: Option<Entity<BreakpointStore>>,
 1153    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1154    hovered_diff_hunk_row: Option<DisplayRow>,
 1155    pull_diagnostics_task: Task<()>,
 1156    in_project_search: bool,
 1157    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1158    breadcrumb_header: Option<String>,
 1159    focused_block: Option<FocusedBlock>,
 1160    next_scroll_position: NextScrollCursorCenterTopBottom,
 1161    addons: HashMap<TypeId, Box<dyn Addon>>,
 1162    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1163    load_diff_task: Option<Shared<Task<()>>>,
 1164    /// Whether we are temporarily displaying a diff other than git's
 1165    temporary_diff_override: bool,
 1166    selection_mark_mode: bool,
 1167    toggle_fold_multiple_buffers: Task<()>,
 1168    _scroll_cursor_center_top_bottom_task: Task<()>,
 1169    serialize_selections: Task<()>,
 1170    serialize_folds: Task<()>,
 1171    mouse_cursor_hidden: bool,
 1172    minimap: Option<Entity<Self>>,
 1173    hide_mouse_mode: HideMouseMode,
 1174    pub change_list: ChangeList,
 1175    inline_value_cache: InlineValueCache,
 1176    selection_drag_state: SelectionDragState,
 1177    colors: Option<LspColorData>,
 1178    post_scroll_update: Task<()>,
 1179    refresh_colors_task: Task<()>,
 1180    inlay_hints: Option<LspInlayHintData>,
 1181    folding_newlines: Task<()>,
 1182    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1183}
 1184
 1185fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1186    if debounce_ms > 0 {
 1187        Some(Duration::from_millis(debounce_ms))
 1188    } else {
 1189        None
 1190    }
 1191}
 1192
 1193#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1194enum NextScrollCursorCenterTopBottom {
 1195    #[default]
 1196    Center,
 1197    Top,
 1198    Bottom,
 1199}
 1200
 1201impl NextScrollCursorCenterTopBottom {
 1202    fn next(&self) -> Self {
 1203        match self {
 1204            Self::Center => Self::Top,
 1205            Self::Top => Self::Bottom,
 1206            Self::Bottom => Self::Center,
 1207        }
 1208    }
 1209}
 1210
 1211#[derive(Clone)]
 1212pub struct EditorSnapshot {
 1213    pub mode: EditorMode,
 1214    show_gutter: bool,
 1215    show_line_numbers: Option<bool>,
 1216    show_git_diff_gutter: Option<bool>,
 1217    show_code_actions: Option<bool>,
 1218    show_runnables: Option<bool>,
 1219    show_breakpoints: Option<bool>,
 1220    git_blame_gutter_max_author_length: Option<usize>,
 1221    pub display_snapshot: DisplaySnapshot,
 1222    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1223    is_focused: bool,
 1224    scroll_anchor: ScrollAnchor,
 1225    ongoing_scroll: OngoingScroll,
 1226    current_line_highlight: CurrentLineHighlight,
 1227    gutter_hovered: bool,
 1228}
 1229
 1230#[derive(Default, Debug, Clone, Copy)]
 1231pub struct GutterDimensions {
 1232    pub left_padding: Pixels,
 1233    pub right_padding: Pixels,
 1234    pub width: Pixels,
 1235    pub margin: Pixels,
 1236    pub git_blame_entries_width: Option<Pixels>,
 1237}
 1238
 1239impl GutterDimensions {
 1240    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1241        Self {
 1242            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1243            ..Default::default()
 1244        }
 1245    }
 1246
 1247    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1248        -cx.text_system().descent(font_id, font_size)
 1249    }
 1250    /// The full width of the space taken up by the gutter.
 1251    pub fn full_width(&self) -> Pixels {
 1252        self.margin + self.width
 1253    }
 1254
 1255    /// The width of the space reserved for the fold indicators,
 1256    /// use alongside 'justify_end' and `gutter_width` to
 1257    /// right align content with the line numbers
 1258    pub fn fold_area_width(&self) -> Pixels {
 1259        self.margin + self.right_padding
 1260    }
 1261}
 1262
 1263struct CharacterDimensions {
 1264    em_width: Pixels,
 1265    em_advance: Pixels,
 1266    line_height: Pixels,
 1267}
 1268
 1269#[derive(Debug)]
 1270pub struct RemoteSelection {
 1271    pub replica_id: ReplicaId,
 1272    pub selection: Selection<Anchor>,
 1273    pub cursor_shape: CursorShape,
 1274    pub collaborator_id: CollaboratorId,
 1275    pub line_mode: bool,
 1276    pub user_name: Option<SharedString>,
 1277    pub color: PlayerColor,
 1278}
 1279
 1280#[derive(Clone, Debug)]
 1281struct SelectionHistoryEntry {
 1282    selections: Arc<[Selection<Anchor>]>,
 1283    select_next_state: Option<SelectNextState>,
 1284    select_prev_state: Option<SelectNextState>,
 1285    add_selections_state: Option<AddSelectionsState>,
 1286}
 1287
 1288#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1289enum SelectionHistoryMode {
 1290    Normal,
 1291    Undoing,
 1292    Redoing,
 1293    Skipping,
 1294}
 1295
 1296#[derive(Clone, PartialEq, Eq, Hash)]
 1297struct HoveredCursor {
 1298    replica_id: ReplicaId,
 1299    selection_id: usize,
 1300}
 1301
 1302impl Default for SelectionHistoryMode {
 1303    fn default() -> Self {
 1304        Self::Normal
 1305    }
 1306}
 1307
 1308#[derive(Debug)]
 1309/// SelectionEffects controls the side-effects of updating the selection.
 1310///
 1311/// The default behaviour does "what you mostly want":
 1312/// - it pushes to the nav history if the cursor moved by >10 lines
 1313/// - it re-triggers completion requests
 1314/// - it scrolls to fit
 1315///
 1316/// You might want to modify these behaviours. For example when doing a "jump"
 1317/// like go to definition, we always want to add to nav history; but when scrolling
 1318/// in vim mode we never do.
 1319///
 1320/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1321/// move.
 1322#[derive(Clone)]
 1323pub struct SelectionEffects {
 1324    nav_history: Option<bool>,
 1325    completions: bool,
 1326    scroll: Option<Autoscroll>,
 1327}
 1328
 1329impl Default for SelectionEffects {
 1330    fn default() -> Self {
 1331        Self {
 1332            nav_history: None,
 1333            completions: true,
 1334            scroll: Some(Autoscroll::fit()),
 1335        }
 1336    }
 1337}
 1338impl SelectionEffects {
 1339    pub fn scroll(scroll: Autoscroll) -> Self {
 1340        Self {
 1341            scroll: Some(scroll),
 1342            ..Default::default()
 1343        }
 1344    }
 1345
 1346    pub fn no_scroll() -> Self {
 1347        Self {
 1348            scroll: None,
 1349            ..Default::default()
 1350        }
 1351    }
 1352
 1353    pub fn completions(self, completions: bool) -> Self {
 1354        Self {
 1355            completions,
 1356            ..self
 1357        }
 1358    }
 1359
 1360    pub fn nav_history(self, nav_history: bool) -> Self {
 1361        Self {
 1362            nav_history: Some(nav_history),
 1363            ..self
 1364        }
 1365    }
 1366}
 1367
 1368struct DeferredSelectionEffectsState {
 1369    changed: bool,
 1370    effects: SelectionEffects,
 1371    old_cursor_position: Anchor,
 1372    history_entry: SelectionHistoryEntry,
 1373}
 1374
 1375#[derive(Default)]
 1376struct SelectionHistory {
 1377    #[allow(clippy::type_complexity)]
 1378    selections_by_transaction:
 1379        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1380    mode: SelectionHistoryMode,
 1381    undo_stack: VecDeque<SelectionHistoryEntry>,
 1382    redo_stack: VecDeque<SelectionHistoryEntry>,
 1383}
 1384
 1385impl SelectionHistory {
 1386    #[track_caller]
 1387    fn insert_transaction(
 1388        &mut self,
 1389        transaction_id: TransactionId,
 1390        selections: Arc<[Selection<Anchor>]>,
 1391    ) {
 1392        if selections.is_empty() {
 1393            log::error!(
 1394                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1395                std::panic::Location::caller()
 1396            );
 1397            return;
 1398        }
 1399        self.selections_by_transaction
 1400            .insert(transaction_id, (selections, None));
 1401    }
 1402
 1403    #[allow(clippy::type_complexity)]
 1404    fn transaction(
 1405        &self,
 1406        transaction_id: TransactionId,
 1407    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1408        self.selections_by_transaction.get(&transaction_id)
 1409    }
 1410
 1411    #[allow(clippy::type_complexity)]
 1412    fn transaction_mut(
 1413        &mut self,
 1414        transaction_id: TransactionId,
 1415    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1416        self.selections_by_transaction.get_mut(&transaction_id)
 1417    }
 1418
 1419    fn push(&mut self, entry: SelectionHistoryEntry) {
 1420        if !entry.selections.is_empty() {
 1421            match self.mode {
 1422                SelectionHistoryMode::Normal => {
 1423                    self.push_undo(entry);
 1424                    self.redo_stack.clear();
 1425                }
 1426                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1427                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1428                SelectionHistoryMode::Skipping => {}
 1429            }
 1430        }
 1431    }
 1432
 1433    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1434        if self
 1435            .undo_stack
 1436            .back()
 1437            .is_none_or(|e| e.selections != entry.selections)
 1438        {
 1439            self.undo_stack.push_back(entry);
 1440            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1441                self.undo_stack.pop_front();
 1442            }
 1443        }
 1444    }
 1445
 1446    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1447        if self
 1448            .redo_stack
 1449            .back()
 1450            .is_none_or(|e| e.selections != entry.selections)
 1451        {
 1452            self.redo_stack.push_back(entry);
 1453            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1454                self.redo_stack.pop_front();
 1455            }
 1456        }
 1457    }
 1458}
 1459
 1460#[derive(Clone, Copy)]
 1461pub struct RowHighlightOptions {
 1462    pub autoscroll: bool,
 1463    pub include_gutter: bool,
 1464}
 1465
 1466impl Default for RowHighlightOptions {
 1467    fn default() -> Self {
 1468        Self {
 1469            autoscroll: Default::default(),
 1470            include_gutter: true,
 1471        }
 1472    }
 1473}
 1474
 1475struct RowHighlight {
 1476    index: usize,
 1477    range: Range<Anchor>,
 1478    color: Hsla,
 1479    options: RowHighlightOptions,
 1480    type_id: TypeId,
 1481}
 1482
 1483#[derive(Clone, Debug)]
 1484struct AddSelectionsState {
 1485    groups: Vec<AddSelectionsGroup>,
 1486}
 1487
 1488#[derive(Clone, Debug)]
 1489struct AddSelectionsGroup {
 1490    above: bool,
 1491    stack: Vec<usize>,
 1492}
 1493
 1494#[derive(Clone)]
 1495struct SelectNextState {
 1496    query: AhoCorasick,
 1497    wordwise: bool,
 1498    done: bool,
 1499}
 1500
 1501impl std::fmt::Debug for SelectNextState {
 1502    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1503        f.debug_struct(std::any::type_name::<Self>())
 1504            .field("wordwise", &self.wordwise)
 1505            .field("done", &self.done)
 1506            .finish()
 1507    }
 1508}
 1509
 1510#[derive(Debug)]
 1511struct AutocloseRegion {
 1512    selection_id: usize,
 1513    range: Range<Anchor>,
 1514    pair: BracketPair,
 1515}
 1516
 1517#[derive(Debug)]
 1518struct SnippetState {
 1519    ranges: Vec<Vec<Range<Anchor>>>,
 1520    active_index: usize,
 1521    choices: Vec<Option<Vec<String>>>,
 1522}
 1523
 1524#[doc(hidden)]
 1525pub struct RenameState {
 1526    pub range: Range<Anchor>,
 1527    pub old_name: Arc<str>,
 1528    pub editor: Entity<Editor>,
 1529    block_id: CustomBlockId,
 1530}
 1531
 1532struct InvalidationStack<T>(Vec<T>);
 1533
 1534struct RegisteredEditPredictionProvider {
 1535    provider: Arc<dyn EditPredictionProviderHandle>,
 1536    _subscription: Subscription,
 1537}
 1538
 1539#[derive(Debug, PartialEq, Eq)]
 1540pub struct ActiveDiagnosticGroup {
 1541    pub active_range: Range<Anchor>,
 1542    pub active_message: String,
 1543    pub group_id: usize,
 1544    pub blocks: HashSet<CustomBlockId>,
 1545}
 1546
 1547#[derive(Debug, PartialEq, Eq)]
 1548
 1549pub(crate) enum ActiveDiagnostic {
 1550    None,
 1551    All,
 1552    Group(ActiveDiagnosticGroup),
 1553}
 1554
 1555#[derive(Serialize, Deserialize, Clone, Debug)]
 1556pub struct ClipboardSelection {
 1557    /// The number of bytes in this selection.
 1558    pub len: usize,
 1559    /// Whether this was a full-line selection.
 1560    pub is_entire_line: bool,
 1561    /// The indentation of the first line when this content was originally copied.
 1562    pub first_line_indent: u32,
 1563}
 1564
 1565// selections, scroll behavior, was newest selection reversed
 1566type SelectSyntaxNodeHistoryState = (
 1567    Box<[Selection<usize>]>,
 1568    SelectSyntaxNodeScrollBehavior,
 1569    bool,
 1570);
 1571
 1572#[derive(Default)]
 1573struct SelectSyntaxNodeHistory {
 1574    stack: Vec<SelectSyntaxNodeHistoryState>,
 1575    // disable temporarily to allow changing selections without losing the stack
 1576    pub disable_clearing: bool,
 1577}
 1578
 1579impl SelectSyntaxNodeHistory {
 1580    pub fn try_clear(&mut self) {
 1581        if !self.disable_clearing {
 1582            self.stack.clear();
 1583        }
 1584    }
 1585
 1586    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1587        self.stack.push(selection);
 1588    }
 1589
 1590    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1591        self.stack.pop()
 1592    }
 1593}
 1594
 1595enum SelectSyntaxNodeScrollBehavior {
 1596    CursorTop,
 1597    FitSelection,
 1598    CursorBottom,
 1599}
 1600
 1601#[derive(Debug)]
 1602pub(crate) struct NavigationData {
 1603    cursor_anchor: Anchor,
 1604    cursor_position: Point,
 1605    scroll_anchor: ScrollAnchor,
 1606    scroll_top_row: u32,
 1607}
 1608
 1609#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1610pub enum GotoDefinitionKind {
 1611    Symbol,
 1612    Declaration,
 1613    Type,
 1614    Implementation,
 1615}
 1616
 1617pub enum FormatTarget {
 1618    Buffers(HashSet<Entity<Buffer>>),
 1619    Ranges(Vec<Range<MultiBufferPoint>>),
 1620}
 1621
 1622pub(crate) struct FocusedBlock {
 1623    id: BlockId,
 1624    focus_handle: WeakFocusHandle,
 1625}
 1626
 1627#[derive(Clone)]
 1628enum JumpData {
 1629    MultiBufferRow {
 1630        row: MultiBufferRow,
 1631        line_offset_from_top: u32,
 1632    },
 1633    MultiBufferPoint {
 1634        excerpt_id: ExcerptId,
 1635        position: Point,
 1636        anchor: text::Anchor,
 1637        line_offset_from_top: u32,
 1638    },
 1639}
 1640
 1641pub enum MultibufferSelectionMode {
 1642    First,
 1643    All,
 1644}
 1645
 1646#[derive(Clone, Copy, Debug, Default)]
 1647pub struct RewrapOptions {
 1648    pub override_language_settings: bool,
 1649    pub preserve_existing_whitespace: bool,
 1650}
 1651
 1652impl Editor {
 1653    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1654        let buffer = cx.new(|cx| Buffer::local("", cx));
 1655        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1656        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1657    }
 1658
 1659    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1660        let buffer = cx.new(|cx| Buffer::local("", cx));
 1661        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1662        Self::new(EditorMode::full(), buffer, None, window, cx)
 1663    }
 1664
 1665    pub fn auto_height(
 1666        min_lines: usize,
 1667        max_lines: usize,
 1668        window: &mut Window,
 1669        cx: &mut Context<Self>,
 1670    ) -> Self {
 1671        let buffer = cx.new(|cx| Buffer::local("", cx));
 1672        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1673        Self::new(
 1674            EditorMode::AutoHeight {
 1675                min_lines,
 1676                max_lines: Some(max_lines),
 1677            },
 1678            buffer,
 1679            None,
 1680            window,
 1681            cx,
 1682        )
 1683    }
 1684
 1685    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1686    /// The editor grows as tall as needed to fit its content.
 1687    pub fn auto_height_unbounded(
 1688        min_lines: usize,
 1689        window: &mut Window,
 1690        cx: &mut Context<Self>,
 1691    ) -> Self {
 1692        let buffer = cx.new(|cx| Buffer::local("", cx));
 1693        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1694        Self::new(
 1695            EditorMode::AutoHeight {
 1696                min_lines,
 1697                max_lines: None,
 1698            },
 1699            buffer,
 1700            None,
 1701            window,
 1702            cx,
 1703        )
 1704    }
 1705
 1706    pub fn for_buffer(
 1707        buffer: Entity<Buffer>,
 1708        project: Option<Entity<Project>>,
 1709        window: &mut Window,
 1710        cx: &mut Context<Self>,
 1711    ) -> Self {
 1712        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1713        Self::new(EditorMode::full(), buffer, project, window, cx)
 1714    }
 1715
 1716    pub fn for_multibuffer(
 1717        buffer: Entity<MultiBuffer>,
 1718        project: Option<Entity<Project>>,
 1719        window: &mut Window,
 1720        cx: &mut Context<Self>,
 1721    ) -> Self {
 1722        Self::new(EditorMode::full(), buffer, project, window, cx)
 1723    }
 1724
 1725    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1726        let mut clone = Self::new(
 1727            self.mode.clone(),
 1728            self.buffer.clone(),
 1729            self.project.clone(),
 1730            window,
 1731            cx,
 1732        );
 1733        self.display_map.update(cx, |display_map, cx| {
 1734            let snapshot = display_map.snapshot(cx);
 1735            clone.display_map.update(cx, |display_map, cx| {
 1736                display_map.set_state(&snapshot, cx);
 1737            });
 1738        });
 1739        clone.folds_did_change(cx);
 1740        clone.selections.clone_state(&self.selections);
 1741        clone.scroll_manager.clone_state(&self.scroll_manager);
 1742        clone.searchable = self.searchable;
 1743        clone.read_only = self.read_only;
 1744        clone
 1745    }
 1746
 1747    pub fn new(
 1748        mode: EditorMode,
 1749        buffer: Entity<MultiBuffer>,
 1750        project: Option<Entity<Project>>,
 1751        window: &mut Window,
 1752        cx: &mut Context<Self>,
 1753    ) -> Self {
 1754        Editor::new_internal(mode, buffer, project, None, window, cx)
 1755    }
 1756
 1757    fn new_internal(
 1758        mode: EditorMode,
 1759        multi_buffer: Entity<MultiBuffer>,
 1760        project: Option<Entity<Project>>,
 1761        display_map: Option<Entity<DisplayMap>>,
 1762        window: &mut Window,
 1763        cx: &mut Context<Self>,
 1764    ) -> Self {
 1765        debug_assert!(
 1766            display_map.is_none() || mode.is_minimap(),
 1767            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1768        );
 1769
 1770        let full_mode = mode.is_full();
 1771        let is_minimap = mode.is_minimap();
 1772        let diagnostics_max_severity = if full_mode {
 1773            EditorSettings::get_global(cx)
 1774                .diagnostics_max_severity
 1775                .unwrap_or(DiagnosticSeverity::Hint)
 1776        } else {
 1777            DiagnosticSeverity::Off
 1778        };
 1779        let style = window.text_style();
 1780        let font_size = style.font_size.to_pixels(window.rem_size());
 1781        let editor = cx.entity().downgrade();
 1782        let fold_placeholder = FoldPlaceholder {
 1783            constrain_width: false,
 1784            render: Arc::new(move |fold_id, fold_range, cx| {
 1785                let editor = editor.clone();
 1786                div()
 1787                    .id(fold_id)
 1788                    .bg(cx.theme().colors().ghost_element_background)
 1789                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1790                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1791                    .rounded_xs()
 1792                    .size_full()
 1793                    .cursor_pointer()
 1794                    .child("")
 1795                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1796                    .on_click(move |_, _window, cx| {
 1797                        editor
 1798                            .update(cx, |editor, cx| {
 1799                                editor.unfold_ranges(
 1800                                    &[fold_range.start..fold_range.end],
 1801                                    true,
 1802                                    false,
 1803                                    cx,
 1804                                );
 1805                                cx.stop_propagation();
 1806                            })
 1807                            .ok();
 1808                    })
 1809                    .into_any()
 1810            }),
 1811            merge_adjacent: true,
 1812            ..FoldPlaceholder::default()
 1813        };
 1814        let display_map = display_map.unwrap_or_else(|| {
 1815            cx.new(|cx| {
 1816                DisplayMap::new(
 1817                    multi_buffer.clone(),
 1818                    style.font(),
 1819                    font_size,
 1820                    None,
 1821                    FILE_HEADER_HEIGHT,
 1822                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1823                    fold_placeholder,
 1824                    diagnostics_max_severity,
 1825                    cx,
 1826                )
 1827            })
 1828        });
 1829
 1830        let selections = SelectionsCollection::new(display_map.clone(), multi_buffer.clone());
 1831
 1832        let blink_manager = cx.new(|cx| {
 1833            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1834            if is_minimap {
 1835                blink_manager.disable(cx);
 1836            }
 1837            blink_manager
 1838        });
 1839
 1840        let soft_wrap_mode_override =
 1841            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1842
 1843        let mut project_subscriptions = Vec::new();
 1844        if full_mode && let Some(project) = project.as_ref() {
 1845            project_subscriptions.push(cx.subscribe_in(
 1846                project,
 1847                window,
 1848                |editor, _, event, window, cx| match event {
 1849                    project::Event::RefreshCodeLens => {
 1850                        // we always query lens with actions, without storing them, always refreshing them
 1851                    }
 1852                    project::Event::RefreshInlayHints {
 1853                        server_id,
 1854                        request_id,
 1855                    } => {
 1856                        editor.refresh_inlay_hints(
 1857                            InlayHintRefreshReason::RefreshRequested {
 1858                                server_id: *server_id,
 1859                                request_id: *request_id,
 1860                            },
 1861                            cx,
 1862                        );
 1863                    }
 1864                    project::Event::LanguageServerRemoved(..) => {
 1865                        if editor.tasks_update_task.is_none() {
 1866                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1867                        }
 1868                        editor.registered_buffers.clear();
 1869                        editor.register_visible_buffers(cx);
 1870                    }
 1871                    project::Event::LanguageServerAdded(..) => {
 1872                        if editor.tasks_update_task.is_none() {
 1873                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1874                        }
 1875                    }
 1876                    project::Event::SnippetEdit(id, snippet_edits) => {
 1877                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1878                            let focus_handle = editor.focus_handle(cx);
 1879                            if focus_handle.is_focused(window) {
 1880                                let snapshot = buffer.read(cx).snapshot();
 1881                                for (range, snippet) in snippet_edits {
 1882                                    let editor_range =
 1883                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1884                                    editor
 1885                                        .insert_snippet(
 1886                                            &[editor_range],
 1887                                            snippet.clone(),
 1888                                            window,
 1889                                            cx,
 1890                                        )
 1891                                        .ok();
 1892                                }
 1893                            }
 1894                        }
 1895                    }
 1896                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1897                        let buffer_id = *buffer_id;
 1898                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 1899                            editor.register_buffer(buffer_id, cx);
 1900                            editor.update_lsp_data(Some(buffer_id), window, cx);
 1901                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 1902                            refresh_linked_ranges(editor, window, cx);
 1903                            editor.refresh_code_actions(window, cx);
 1904                            editor.refresh_document_highlights(cx);
 1905                        }
 1906                    }
 1907
 1908                    project::Event::EntryRenamed(transaction) => {
 1909                        let Some(workspace) = editor.workspace() else {
 1910                            return;
 1911                        };
 1912                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1913                        else {
 1914                            return;
 1915                        };
 1916                        if active_editor.entity_id() == cx.entity_id() {
 1917                            let edited_buffers_already_open = {
 1918                                let other_editors: Vec<Entity<Editor>> = workspace
 1919                                    .read(cx)
 1920                                    .panes()
 1921                                    .iter()
 1922                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1923                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1924                                    .collect();
 1925
 1926                                transaction.0.keys().all(|buffer| {
 1927                                    other_editors.iter().any(|editor| {
 1928                                        let multi_buffer = editor.read(cx).buffer();
 1929                                        multi_buffer.read(cx).is_singleton()
 1930                                            && multi_buffer.read(cx).as_singleton().map_or(
 1931                                                false,
 1932                                                |singleton| {
 1933                                                    singleton.entity_id() == buffer.entity_id()
 1934                                                },
 1935                                            )
 1936                                    })
 1937                                })
 1938                            };
 1939
 1940                            if !edited_buffers_already_open {
 1941                                let workspace = workspace.downgrade();
 1942                                let transaction = transaction.clone();
 1943                                cx.defer_in(window, move |_, window, cx| {
 1944                                    cx.spawn_in(window, async move |editor, cx| {
 1945                                        Self::open_project_transaction(
 1946                                            &editor,
 1947                                            workspace,
 1948                                            transaction,
 1949                                            "Rename".to_string(),
 1950                                            cx,
 1951                                        )
 1952                                        .await
 1953                                        .ok()
 1954                                    })
 1955                                    .detach();
 1956                                });
 1957                            }
 1958                        }
 1959                    }
 1960
 1961                    _ => {}
 1962                },
 1963            ));
 1964            if let Some(task_inventory) = project
 1965                .read(cx)
 1966                .task_store()
 1967                .read(cx)
 1968                .task_inventory()
 1969                .cloned()
 1970            {
 1971                project_subscriptions.push(cx.observe_in(
 1972                    &task_inventory,
 1973                    window,
 1974                    |editor, _, window, cx| {
 1975                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1976                    },
 1977                ));
 1978            };
 1979
 1980            project_subscriptions.push(cx.subscribe_in(
 1981                &project.read(cx).breakpoint_store(),
 1982                window,
 1983                |editor, _, event, window, cx| match event {
 1984                    BreakpointStoreEvent::ClearDebugLines => {
 1985                        editor.clear_row_highlights::<ActiveDebugLine>();
 1986                        editor.refresh_inline_values(cx);
 1987                    }
 1988                    BreakpointStoreEvent::SetDebugLine => {
 1989                        if editor.go_to_active_debug_line(window, cx) {
 1990                            cx.stop_propagation();
 1991                        }
 1992
 1993                        editor.refresh_inline_values(cx);
 1994                    }
 1995                    _ => {}
 1996                },
 1997            ));
 1998            let git_store = project.read(cx).git_store().clone();
 1999            let project = project.clone();
 2000            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2001                if let GitStoreEvent::RepositoryAdded = event {
 2002                    this.load_diff_task = Some(
 2003                        update_uncommitted_diff_for_buffer(
 2004                            cx.entity(),
 2005                            &project,
 2006                            this.buffer.read(cx).all_buffers(),
 2007                            this.buffer.clone(),
 2008                            cx,
 2009                        )
 2010                        .shared(),
 2011                    );
 2012                }
 2013            }));
 2014        }
 2015
 2016        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2017
 2018        let inlay_hint_settings =
 2019            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2020        let focus_handle = cx.focus_handle();
 2021        if !is_minimap {
 2022            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2023                .detach();
 2024            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2025                .detach();
 2026            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2027                .detach();
 2028            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2029                .detach();
 2030            cx.observe_pending_input(window, Self::observe_pending_input)
 2031                .detach();
 2032        }
 2033
 2034        let show_indent_guides =
 2035            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2036                Some(false)
 2037            } else {
 2038                None
 2039            };
 2040
 2041        let breakpoint_store = match (&mode, project.as_ref()) {
 2042            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2043            _ => None,
 2044        };
 2045
 2046        let mut code_action_providers = Vec::new();
 2047        let mut load_uncommitted_diff = None;
 2048        if let Some(project) = project.clone() {
 2049            load_uncommitted_diff = Some(
 2050                update_uncommitted_diff_for_buffer(
 2051                    cx.entity(),
 2052                    &project,
 2053                    multi_buffer.read(cx).all_buffers(),
 2054                    multi_buffer.clone(),
 2055                    cx,
 2056                )
 2057                .shared(),
 2058            );
 2059            code_action_providers.push(Rc::new(project) as Rc<_>);
 2060        }
 2061
 2062        let mut editor = Self {
 2063            focus_handle,
 2064            show_cursor_when_unfocused: false,
 2065            last_focused_descendant: None,
 2066            buffer: multi_buffer.clone(),
 2067            display_map: display_map.clone(),
 2068            placeholder_display_map: None,
 2069            selections,
 2070            scroll_manager: ScrollManager::new(cx),
 2071            columnar_selection_state: None,
 2072            add_selections_state: None,
 2073            select_next_state: None,
 2074            select_prev_state: None,
 2075            selection_history: SelectionHistory::default(),
 2076            defer_selection_effects: false,
 2077            deferred_selection_effects_state: None,
 2078            autoclose_regions: Vec::new(),
 2079            snippet_stack: InvalidationStack::default(),
 2080            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2081            ime_transaction: None,
 2082            active_diagnostics: ActiveDiagnostic::None,
 2083            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2084            inline_diagnostics_update: Task::ready(()),
 2085            inline_diagnostics: Vec::new(),
 2086            soft_wrap_mode_override,
 2087            diagnostics_max_severity,
 2088            hard_wrap: None,
 2089            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2090            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2091            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2092            project,
 2093            blink_manager: blink_manager.clone(),
 2094            show_local_selections: true,
 2095            show_scrollbars: ScrollbarAxes {
 2096                horizontal: full_mode,
 2097                vertical: full_mode,
 2098            },
 2099            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2100            offset_content: !matches!(mode, EditorMode::SingleLine),
 2101            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2102            show_gutter: full_mode,
 2103            show_line_numbers: (!full_mode).then_some(false),
 2104            use_relative_line_numbers: None,
 2105            disable_expand_excerpt_buttons: !full_mode,
 2106            show_git_diff_gutter: None,
 2107            show_code_actions: None,
 2108            show_runnables: None,
 2109            show_breakpoints: None,
 2110            show_wrap_guides: None,
 2111            show_indent_guides,
 2112            highlight_order: 0,
 2113            highlighted_rows: HashMap::default(),
 2114            background_highlights: HashMap::default(),
 2115            gutter_highlights: HashMap::default(),
 2116            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2117            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2118            nav_history: None,
 2119            context_menu: RefCell::new(None),
 2120            context_menu_options: None,
 2121            mouse_context_menu: None,
 2122            completion_tasks: Vec::new(),
 2123            inline_blame_popover: None,
 2124            inline_blame_popover_show_task: None,
 2125            signature_help_state: SignatureHelpState::default(),
 2126            auto_signature_help: None,
 2127            find_all_references_task_sources: Vec::new(),
 2128            next_completion_id: 0,
 2129            next_inlay_id: 0,
 2130            code_action_providers,
 2131            available_code_actions: None,
 2132            code_actions_task: None,
 2133            quick_selection_highlight_task: None,
 2134            debounced_selection_highlight_task: None,
 2135            document_highlights_task: None,
 2136            linked_editing_range_task: None,
 2137            pending_rename: None,
 2138            searchable: !is_minimap,
 2139            cursor_shape: EditorSettings::get_global(cx)
 2140                .cursor_shape
 2141                .unwrap_or_default(),
 2142            current_line_highlight: None,
 2143            autoindent_mode: Some(AutoindentMode::EachLine),
 2144
 2145            workspace: None,
 2146            input_enabled: !is_minimap,
 2147            use_modal_editing: full_mode,
 2148            read_only: is_minimap,
 2149            use_autoclose: true,
 2150            use_auto_surround: true,
 2151            auto_replace_emoji_shortcode: false,
 2152            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2153            leader_id: None,
 2154            remote_id: None,
 2155            hover_state: HoverState::default(),
 2156            pending_mouse_down: None,
 2157            hovered_link_state: None,
 2158            edit_prediction_provider: None,
 2159            active_edit_prediction: None,
 2160            stale_edit_prediction_in_menu: None,
 2161            edit_prediction_preview: EditPredictionPreview::Inactive {
 2162                released_too_fast: false,
 2163            },
 2164            inline_diagnostics_enabled: full_mode,
 2165            diagnostics_enabled: full_mode,
 2166            word_completions_enabled: full_mode,
 2167            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2168            gutter_hovered: false,
 2169            pixel_position_of_newest_cursor: None,
 2170            last_bounds: None,
 2171            last_position_map: None,
 2172            expect_bounds_change: None,
 2173            gutter_dimensions: GutterDimensions::default(),
 2174            style: None,
 2175            show_cursor_names: false,
 2176            hovered_cursors: HashMap::default(),
 2177            next_editor_action_id: EditorActionId::default(),
 2178            editor_actions: Rc::default(),
 2179            edit_predictions_hidden_for_vim_mode: false,
 2180            show_edit_predictions_override: None,
 2181            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2182            edit_prediction_settings: EditPredictionSettings::Disabled,
 2183            edit_prediction_indent_conflict: false,
 2184            edit_prediction_requires_modifier_in_indent_conflict: true,
 2185            custom_context_menu: None,
 2186            show_git_blame_gutter: false,
 2187            show_git_blame_inline: false,
 2188            show_selection_menu: None,
 2189            show_git_blame_inline_delay_task: None,
 2190            git_blame_inline_enabled: full_mode
 2191                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2192            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2193            serialize_dirty_buffers: !is_minimap
 2194                && ProjectSettings::get_global(cx)
 2195                    .session
 2196                    .restore_unsaved_buffers,
 2197            blame: None,
 2198            blame_subscription: None,
 2199            tasks: BTreeMap::default(),
 2200
 2201            breakpoint_store,
 2202            gutter_breakpoint_indicator: (None, None),
 2203            hovered_diff_hunk_row: None,
 2204            _subscriptions: (!is_minimap)
 2205                .then(|| {
 2206                    vec![
 2207                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2208                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2209                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2210                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2211                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2212                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2213                        cx.observe_window_activation(window, |editor, window, cx| {
 2214                            let active = window.is_window_active();
 2215                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2216                                if active {
 2217                                    blink_manager.enable(cx);
 2218                                } else {
 2219                                    blink_manager.disable(cx);
 2220                                }
 2221                            });
 2222                            if active {
 2223                                editor.show_mouse_cursor(cx);
 2224                            }
 2225                        }),
 2226                    ]
 2227                })
 2228                .unwrap_or_default(),
 2229            tasks_update_task: None,
 2230            pull_diagnostics_task: Task::ready(()),
 2231            colors: None,
 2232            refresh_colors_task: Task::ready(()),
 2233            inlay_hints: None,
 2234            next_color_inlay_id: 0,
 2235            post_scroll_update: Task::ready(()),
 2236            linked_edit_ranges: Default::default(),
 2237            in_project_search: false,
 2238            previous_search_ranges: None,
 2239            breadcrumb_header: None,
 2240            focused_block: None,
 2241            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2242            addons: HashMap::default(),
 2243            registered_buffers: HashMap::default(),
 2244            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2245            selection_mark_mode: false,
 2246            toggle_fold_multiple_buffers: Task::ready(()),
 2247            serialize_selections: Task::ready(()),
 2248            serialize_folds: Task::ready(()),
 2249            text_style_refinement: None,
 2250            load_diff_task: load_uncommitted_diff,
 2251            temporary_diff_override: false,
 2252            mouse_cursor_hidden: false,
 2253            minimap: None,
 2254            hide_mouse_mode: EditorSettings::get_global(cx)
 2255                .hide_mouse
 2256                .unwrap_or_default(),
 2257            change_list: ChangeList::new(),
 2258            mode,
 2259            selection_drag_state: SelectionDragState::None,
 2260            folding_newlines: Task::ready(()),
 2261            lookup_key: None,
 2262        };
 2263
 2264        if is_minimap {
 2265            return editor;
 2266        }
 2267
 2268        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2269            editor
 2270                ._subscriptions
 2271                .push(cx.observe(breakpoints, |_, _, cx| {
 2272                    cx.notify();
 2273                }));
 2274        }
 2275        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2276        editor._subscriptions.extend(project_subscriptions);
 2277
 2278        editor._subscriptions.push(cx.subscribe_in(
 2279            &cx.entity(),
 2280            window,
 2281            |editor, _, e: &EditorEvent, window, cx| match e {
 2282                EditorEvent::ScrollPositionChanged { local, .. } => {
 2283                    if *local {
 2284                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2285                        editor.inline_blame_popover.take();
 2286                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2287                            cx.background_executor()
 2288                                .timer(Duration::from_millis(50))
 2289                                .await;
 2290                            editor
 2291                                .update_in(cx, |editor, window, cx| {
 2292                                    editor.register_visible_buffers(cx);
 2293                                    editor.refresh_colors_for_visible_range(None, window, cx);
 2294                                    editor.refresh_inlay_hints(
 2295                                        InlayHintRefreshReason::NewLinesShown,
 2296                                        cx,
 2297                                    );
 2298
 2299                                    let new_anchor = editor.scroll_manager.anchor();
 2300                                    let snapshot = editor.snapshot(window, cx);
 2301                                    editor.update_restoration_data(cx, move |data| {
 2302                                        data.scroll_position = (
 2303                                            new_anchor.top_row(snapshot.buffer_snapshot()),
 2304                                            new_anchor.offset,
 2305                                        );
 2306                                    });
 2307                                })
 2308                                .ok();
 2309                        });
 2310                    }
 2311                }
 2312                EditorEvent::Edited { .. } => {
 2313                    if vim_flavor(cx).is_none() {
 2314                        let display_map = editor.display_snapshot(cx);
 2315                        let selections = editor.selections.all_adjusted_display(&display_map);
 2316                        let pop_state = editor
 2317                            .change_list
 2318                            .last()
 2319                            .map(|previous| {
 2320                                previous.len() == selections.len()
 2321                                    && previous.iter().enumerate().all(|(ix, p)| {
 2322                                        p.to_display_point(&display_map).row()
 2323                                            == selections[ix].head().row()
 2324                                    })
 2325                            })
 2326                            .unwrap_or(false);
 2327                        let new_positions = selections
 2328                            .into_iter()
 2329                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2330                            .collect();
 2331                        editor
 2332                            .change_list
 2333                            .push_to_change_list(pop_state, new_positions);
 2334                    }
 2335                }
 2336                _ => (),
 2337            },
 2338        ));
 2339
 2340        if let Some(dap_store) = editor
 2341            .project
 2342            .as_ref()
 2343            .map(|project| project.read(cx).dap_store())
 2344        {
 2345            let weak_editor = cx.weak_entity();
 2346
 2347            editor
 2348                ._subscriptions
 2349                .push(
 2350                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2351                        let session_entity = cx.entity();
 2352                        weak_editor
 2353                            .update(cx, |editor, cx| {
 2354                                editor._subscriptions.push(
 2355                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2356                                );
 2357                            })
 2358                            .ok();
 2359                    }),
 2360                );
 2361
 2362            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2363                editor
 2364                    ._subscriptions
 2365                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2366            }
 2367        }
 2368
 2369        // skip adding the initial selection to selection history
 2370        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2371        editor.end_selection(window, cx);
 2372        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2373
 2374        editor.scroll_manager.show_scrollbars(window, cx);
 2375        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2376
 2377        if full_mode {
 2378            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2379            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2380
 2381            if editor.git_blame_inline_enabled {
 2382                editor.start_git_blame_inline(false, window, cx);
 2383            }
 2384
 2385            editor.go_to_active_debug_line(window, cx);
 2386
 2387            editor.minimap =
 2388                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2389            editor.colors = Some(LspColorData::new(cx));
 2390            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2391
 2392            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2393                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2394            }
 2395            editor.update_lsp_data(None, window, cx);
 2396            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2397        }
 2398
 2399        editor
 2400    }
 2401
 2402    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2403        self.selections.display_map(cx)
 2404    }
 2405
 2406    pub fn deploy_mouse_context_menu(
 2407        &mut self,
 2408        position: gpui::Point<Pixels>,
 2409        context_menu: Entity<ContextMenu>,
 2410        window: &mut Window,
 2411        cx: &mut Context<Self>,
 2412    ) {
 2413        self.mouse_context_menu = Some(MouseContextMenu::new(
 2414            self,
 2415            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2416            context_menu,
 2417            window,
 2418            cx,
 2419        ));
 2420    }
 2421
 2422    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2423        self.mouse_context_menu
 2424            .as_ref()
 2425            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2426    }
 2427
 2428    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2429        if self
 2430            .selections
 2431            .pending_anchor()
 2432            .is_some_and(|pending_selection| {
 2433                let snapshot = self.buffer().read(cx).snapshot(cx);
 2434                pending_selection.range().includes(range, &snapshot)
 2435            })
 2436        {
 2437            return true;
 2438        }
 2439
 2440        self.selections
 2441            .disjoint_in_range::<usize>(range.clone(), &self.display_snapshot(cx))
 2442            .into_iter()
 2443            .any(|selection| {
 2444                // This is needed to cover a corner case, if we just check for an existing
 2445                // selection in the fold range, having a cursor at the start of the fold
 2446                // marks it as selected. Non-empty selections don't cause this.
 2447                let length = selection.end - selection.start;
 2448                length > 0
 2449            })
 2450    }
 2451
 2452    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2453        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2454    }
 2455
 2456    fn key_context_internal(
 2457        &self,
 2458        has_active_edit_prediction: bool,
 2459        window: &mut Window,
 2460        cx: &mut App,
 2461    ) -> KeyContext {
 2462        let mut key_context = KeyContext::new_with_defaults();
 2463        key_context.add("Editor");
 2464        let mode = match self.mode {
 2465            EditorMode::SingleLine => "single_line",
 2466            EditorMode::AutoHeight { .. } => "auto_height",
 2467            EditorMode::Minimap { .. } => "minimap",
 2468            EditorMode::Full { .. } => "full",
 2469        };
 2470
 2471        if EditorSettings::jupyter_enabled(cx) {
 2472            key_context.add("jupyter");
 2473        }
 2474
 2475        key_context.set("mode", mode);
 2476        if self.pending_rename.is_some() {
 2477            key_context.add("renaming");
 2478        }
 2479
 2480        match self.context_menu.borrow().as_ref() {
 2481            Some(CodeContextMenu::Completions(menu)) => {
 2482                if menu.visible() {
 2483                    key_context.add("menu");
 2484                    key_context.add("showing_completions");
 2485                }
 2486            }
 2487            Some(CodeContextMenu::CodeActions(menu)) => {
 2488                if menu.visible() {
 2489                    key_context.add("menu");
 2490                    key_context.add("showing_code_actions")
 2491                }
 2492            }
 2493            None => {}
 2494        }
 2495
 2496        if self.signature_help_state.has_multiple_signatures() {
 2497            key_context.add("showing_signature_help");
 2498        }
 2499
 2500        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2501        if !self.focus_handle(cx).contains_focused(window, cx)
 2502            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2503        {
 2504            for addon in self.addons.values() {
 2505                addon.extend_key_context(&mut key_context, cx)
 2506            }
 2507        }
 2508
 2509        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2510            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2511                Some(
 2512                    file.full_path(cx)
 2513                        .extension()?
 2514                        .to_string_lossy()
 2515                        .into_owned(),
 2516                )
 2517            }) {
 2518                key_context.set("extension", extension);
 2519            }
 2520        } else {
 2521            key_context.add("multibuffer");
 2522        }
 2523
 2524        if has_active_edit_prediction {
 2525            if self.edit_prediction_in_conflict() {
 2526                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2527            } else {
 2528                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2529                key_context.add("copilot_suggestion");
 2530            }
 2531        }
 2532
 2533        if self.selection_mark_mode {
 2534            key_context.add("selection_mode");
 2535        }
 2536
 2537        let disjoint = self.selections.disjoint_anchors();
 2538        let snapshot = self.snapshot(window, cx);
 2539        let snapshot = snapshot.buffer_snapshot();
 2540        if self.mode == EditorMode::SingleLine
 2541            && let [selection] = disjoint
 2542            && selection.start == selection.end
 2543            && selection.end.to_offset(snapshot) == snapshot.len()
 2544        {
 2545            key_context.add("end_of_input");
 2546        }
 2547
 2548        key_context
 2549    }
 2550
 2551    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2552        self.last_bounds.as_ref()
 2553    }
 2554
 2555    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2556        if self.mouse_cursor_hidden {
 2557            self.mouse_cursor_hidden = false;
 2558            cx.notify();
 2559        }
 2560    }
 2561
 2562    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2563        let hide_mouse_cursor = match origin {
 2564            HideMouseCursorOrigin::TypingAction => {
 2565                matches!(
 2566                    self.hide_mouse_mode,
 2567                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2568                )
 2569            }
 2570            HideMouseCursorOrigin::MovementAction => {
 2571                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2572            }
 2573        };
 2574        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2575            self.mouse_cursor_hidden = hide_mouse_cursor;
 2576            cx.notify();
 2577        }
 2578    }
 2579
 2580    pub fn edit_prediction_in_conflict(&self) -> bool {
 2581        if !self.show_edit_predictions_in_menu() {
 2582            return false;
 2583        }
 2584
 2585        let showing_completions = self
 2586            .context_menu
 2587            .borrow()
 2588            .as_ref()
 2589            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2590
 2591        showing_completions
 2592            || self.edit_prediction_requires_modifier()
 2593            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2594            // bindings to insert tab characters.
 2595            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2596    }
 2597
 2598    pub fn accept_edit_prediction_keybind(
 2599        &self,
 2600        accept_partial: bool,
 2601        window: &mut Window,
 2602        cx: &mut App,
 2603    ) -> AcceptEditPredictionBinding {
 2604        let key_context = self.key_context_internal(true, window, cx);
 2605        let in_conflict = self.edit_prediction_in_conflict();
 2606
 2607        let bindings = if accept_partial {
 2608            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2609        } else {
 2610            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2611        };
 2612
 2613        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2614        // just the first one.
 2615        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2616            !in_conflict
 2617                || binding
 2618                    .keystrokes()
 2619                    .first()
 2620                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2621        }))
 2622    }
 2623
 2624    pub fn new_file(
 2625        workspace: &mut Workspace,
 2626        _: &workspace::NewFile,
 2627        window: &mut Window,
 2628        cx: &mut Context<Workspace>,
 2629    ) {
 2630        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2631            "Failed to create buffer",
 2632            window,
 2633            cx,
 2634            |e, _, _| match e.error_code() {
 2635                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2636                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2637                e.error_tag("required").unwrap_or("the latest version")
 2638            )),
 2639                _ => None,
 2640            },
 2641        );
 2642    }
 2643
 2644    pub fn new_in_workspace(
 2645        workspace: &mut Workspace,
 2646        window: &mut Window,
 2647        cx: &mut Context<Workspace>,
 2648    ) -> Task<Result<Entity<Editor>>> {
 2649        let project = workspace.project().clone();
 2650        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2651
 2652        cx.spawn_in(window, async move |workspace, cx| {
 2653            let buffer = create.await?;
 2654            workspace.update_in(cx, |workspace, window, cx| {
 2655                let editor =
 2656                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2657                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2658                editor
 2659            })
 2660        })
 2661    }
 2662
 2663    fn new_file_vertical(
 2664        workspace: &mut Workspace,
 2665        _: &workspace::NewFileSplitVertical,
 2666        window: &mut Window,
 2667        cx: &mut Context<Workspace>,
 2668    ) {
 2669        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2670    }
 2671
 2672    fn new_file_horizontal(
 2673        workspace: &mut Workspace,
 2674        _: &workspace::NewFileSplitHorizontal,
 2675        window: &mut Window,
 2676        cx: &mut Context<Workspace>,
 2677    ) {
 2678        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2679    }
 2680
 2681    fn new_file_split(
 2682        workspace: &mut Workspace,
 2683        action: &workspace::NewFileSplit,
 2684        window: &mut Window,
 2685        cx: &mut Context<Workspace>,
 2686    ) {
 2687        Self::new_file_in_direction(workspace, action.0, window, cx)
 2688    }
 2689
 2690    fn new_file_in_direction(
 2691        workspace: &mut Workspace,
 2692        direction: SplitDirection,
 2693        window: &mut Window,
 2694        cx: &mut Context<Workspace>,
 2695    ) {
 2696        let project = workspace.project().clone();
 2697        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2698
 2699        cx.spawn_in(window, async move |workspace, cx| {
 2700            let buffer = create.await?;
 2701            workspace.update_in(cx, move |workspace, window, cx| {
 2702                workspace.split_item(
 2703                    direction,
 2704                    Box::new(
 2705                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2706                    ),
 2707                    window,
 2708                    cx,
 2709                )
 2710            })?;
 2711            anyhow::Ok(())
 2712        })
 2713        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2714            match e.error_code() {
 2715                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2716                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2717                e.error_tag("required").unwrap_or("the latest version")
 2718            )),
 2719                _ => None,
 2720            }
 2721        });
 2722    }
 2723
 2724    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2725        self.leader_id
 2726    }
 2727
 2728    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2729        &self.buffer
 2730    }
 2731
 2732    pub fn project(&self) -> Option<&Entity<Project>> {
 2733        self.project.as_ref()
 2734    }
 2735
 2736    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2737        self.workspace.as_ref()?.0.upgrade()
 2738    }
 2739
 2740    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2741        self.buffer().read(cx).title(cx)
 2742    }
 2743
 2744    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2745        let git_blame_gutter_max_author_length = self
 2746            .render_git_blame_gutter(cx)
 2747            .then(|| {
 2748                if let Some(blame) = self.blame.as_ref() {
 2749                    let max_author_length =
 2750                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2751                    Some(max_author_length)
 2752                } else {
 2753                    None
 2754                }
 2755            })
 2756            .flatten();
 2757
 2758        EditorSnapshot {
 2759            mode: self.mode.clone(),
 2760            show_gutter: self.show_gutter,
 2761            show_line_numbers: self.show_line_numbers,
 2762            show_git_diff_gutter: self.show_git_diff_gutter,
 2763            show_code_actions: self.show_code_actions,
 2764            show_runnables: self.show_runnables,
 2765            show_breakpoints: self.show_breakpoints,
 2766            git_blame_gutter_max_author_length,
 2767            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2768            placeholder_display_snapshot: self
 2769                .placeholder_display_map
 2770                .as_ref()
 2771                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2772            scroll_anchor: self.scroll_manager.anchor(),
 2773            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2774            is_focused: self.focus_handle.is_focused(window),
 2775            current_line_highlight: self
 2776                .current_line_highlight
 2777                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2778            gutter_hovered: self.gutter_hovered,
 2779        }
 2780    }
 2781
 2782    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2783        self.buffer.read(cx).language_at(point, cx)
 2784    }
 2785
 2786    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2787        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2788    }
 2789
 2790    pub fn active_excerpt(
 2791        &self,
 2792        cx: &App,
 2793    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2794        self.buffer
 2795            .read(cx)
 2796            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2797    }
 2798
 2799    pub fn mode(&self) -> &EditorMode {
 2800        &self.mode
 2801    }
 2802
 2803    pub fn set_mode(&mut self, mode: EditorMode) {
 2804        self.mode = mode;
 2805    }
 2806
 2807    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2808        self.collaboration_hub.as_deref()
 2809    }
 2810
 2811    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2812        self.collaboration_hub = Some(hub);
 2813    }
 2814
 2815    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2816        self.in_project_search = in_project_search;
 2817    }
 2818
 2819    pub fn set_custom_context_menu(
 2820        &mut self,
 2821        f: impl 'static
 2822        + Fn(
 2823            &mut Self,
 2824            DisplayPoint,
 2825            &mut Window,
 2826            &mut Context<Self>,
 2827        ) -> Option<Entity<ui::ContextMenu>>,
 2828    ) {
 2829        self.custom_context_menu = Some(Box::new(f))
 2830    }
 2831
 2832    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2833        self.completion_provider = provider;
 2834    }
 2835
 2836    #[cfg(any(test, feature = "test-support"))]
 2837    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2838        self.completion_provider.clone()
 2839    }
 2840
 2841    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2842        self.semantics_provider.clone()
 2843    }
 2844
 2845    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2846        self.semantics_provider = provider;
 2847    }
 2848
 2849    pub fn set_edit_prediction_provider<T>(
 2850        &mut self,
 2851        provider: Option<Entity<T>>,
 2852        window: &mut Window,
 2853        cx: &mut Context<Self>,
 2854    ) where
 2855        T: EditPredictionProvider,
 2856    {
 2857        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2858            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2859                if this.focus_handle.is_focused(window) {
 2860                    this.update_visible_edit_prediction(window, cx);
 2861                }
 2862            }),
 2863            provider: Arc::new(provider),
 2864        });
 2865        self.update_edit_prediction_settings(cx);
 2866        self.refresh_edit_prediction(false, false, window, cx);
 2867    }
 2868
 2869    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2870        self.placeholder_display_map
 2871            .as_ref()
 2872            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2873    }
 2874
 2875    pub fn set_placeholder_text(
 2876        &mut self,
 2877        placeholder_text: &str,
 2878        window: &mut Window,
 2879        cx: &mut Context<Self>,
 2880    ) {
 2881        let multibuffer = cx
 2882            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2883
 2884        let style = window.text_style();
 2885
 2886        self.placeholder_display_map = Some(cx.new(|cx| {
 2887            DisplayMap::new(
 2888                multibuffer,
 2889                style.font(),
 2890                style.font_size.to_pixels(window.rem_size()),
 2891                None,
 2892                FILE_HEADER_HEIGHT,
 2893                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2894                Default::default(),
 2895                DiagnosticSeverity::Off,
 2896                cx,
 2897            )
 2898        }));
 2899        cx.notify();
 2900    }
 2901
 2902    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2903        self.cursor_shape = cursor_shape;
 2904
 2905        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2906        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2907
 2908        cx.notify();
 2909    }
 2910
 2911    pub fn set_current_line_highlight(
 2912        &mut self,
 2913        current_line_highlight: Option<CurrentLineHighlight>,
 2914    ) {
 2915        self.current_line_highlight = current_line_highlight;
 2916    }
 2917
 2918    pub fn range_for_match<T: std::marker::Copy>(
 2919        &self,
 2920        range: &Range<T>,
 2921        collapse: bool,
 2922    ) -> Range<T> {
 2923        if collapse {
 2924            return range.start..range.start;
 2925        }
 2926        range.clone()
 2927    }
 2928
 2929    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2930        if self.display_map.read(cx).clip_at_line_ends != clip {
 2931            self.display_map
 2932                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2933        }
 2934    }
 2935
 2936    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2937        self.input_enabled = input_enabled;
 2938    }
 2939
 2940    pub fn set_edit_predictions_hidden_for_vim_mode(
 2941        &mut self,
 2942        hidden: bool,
 2943        window: &mut Window,
 2944        cx: &mut Context<Self>,
 2945    ) {
 2946        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2947            self.edit_predictions_hidden_for_vim_mode = hidden;
 2948            if hidden {
 2949                self.update_visible_edit_prediction(window, cx);
 2950            } else {
 2951                self.refresh_edit_prediction(true, false, window, cx);
 2952            }
 2953        }
 2954    }
 2955
 2956    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2957        self.menu_edit_predictions_policy = value;
 2958    }
 2959
 2960    pub fn set_autoindent(&mut self, autoindent: bool) {
 2961        if autoindent {
 2962            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2963        } else {
 2964            self.autoindent_mode = None;
 2965        }
 2966    }
 2967
 2968    pub fn read_only(&self, cx: &App) -> bool {
 2969        self.read_only || self.buffer.read(cx).read_only()
 2970    }
 2971
 2972    pub fn set_read_only(&mut self, read_only: bool) {
 2973        self.read_only = read_only;
 2974    }
 2975
 2976    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2977        self.use_autoclose = autoclose;
 2978    }
 2979
 2980    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2981        self.use_auto_surround = auto_surround;
 2982    }
 2983
 2984    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2985        self.auto_replace_emoji_shortcode = auto_replace;
 2986    }
 2987
 2988    pub fn toggle_edit_predictions(
 2989        &mut self,
 2990        _: &ToggleEditPrediction,
 2991        window: &mut Window,
 2992        cx: &mut Context<Self>,
 2993    ) {
 2994        if self.show_edit_predictions_override.is_some() {
 2995            self.set_show_edit_predictions(None, window, cx);
 2996        } else {
 2997            let show_edit_predictions = !self.edit_predictions_enabled();
 2998            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2999        }
 3000    }
 3001
 3002    pub fn set_show_edit_predictions(
 3003        &mut self,
 3004        show_edit_predictions: Option<bool>,
 3005        window: &mut Window,
 3006        cx: &mut Context<Self>,
 3007    ) {
 3008        self.show_edit_predictions_override = show_edit_predictions;
 3009        self.update_edit_prediction_settings(cx);
 3010
 3011        if let Some(false) = show_edit_predictions {
 3012            self.discard_edit_prediction(false, cx);
 3013        } else {
 3014            self.refresh_edit_prediction(false, true, window, cx);
 3015        }
 3016    }
 3017
 3018    fn edit_predictions_disabled_in_scope(
 3019        &self,
 3020        buffer: &Entity<Buffer>,
 3021        buffer_position: language::Anchor,
 3022        cx: &App,
 3023    ) -> bool {
 3024        let snapshot = buffer.read(cx).snapshot();
 3025        let settings = snapshot.settings_at(buffer_position, cx);
 3026
 3027        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3028            return false;
 3029        };
 3030
 3031        scope.override_name().is_some_and(|scope_name| {
 3032            settings
 3033                .edit_predictions_disabled_in
 3034                .iter()
 3035                .any(|s| s == scope_name)
 3036        })
 3037    }
 3038
 3039    pub fn set_use_modal_editing(&mut self, to: bool) {
 3040        self.use_modal_editing = to;
 3041    }
 3042
 3043    pub fn use_modal_editing(&self) -> bool {
 3044        self.use_modal_editing
 3045    }
 3046
 3047    fn selections_did_change(
 3048        &mut self,
 3049        local: bool,
 3050        old_cursor_position: &Anchor,
 3051        effects: SelectionEffects,
 3052        window: &mut Window,
 3053        cx: &mut Context<Self>,
 3054    ) {
 3055        window.invalidate_character_coordinates();
 3056
 3057        // Copy selections to primary selection buffer
 3058        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3059        if local {
 3060            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3061            let buffer_handle = self.buffer.read(cx).read(cx);
 3062
 3063            let mut text = String::new();
 3064            for (index, selection) in selections.iter().enumerate() {
 3065                let text_for_selection = buffer_handle
 3066                    .text_for_range(selection.start..selection.end)
 3067                    .collect::<String>();
 3068
 3069                text.push_str(&text_for_selection);
 3070                if index != selections.len() - 1 {
 3071                    text.push('\n');
 3072                }
 3073            }
 3074
 3075            if !text.is_empty() {
 3076                cx.write_to_primary(ClipboardItem::new_string(text));
 3077            }
 3078        }
 3079
 3080        let selection_anchors = self.selections.disjoint_anchors_arc();
 3081
 3082        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3083            self.buffer.update(cx, |buffer, cx| {
 3084                buffer.set_active_selections(
 3085                    &selection_anchors,
 3086                    self.selections.line_mode(),
 3087                    self.cursor_shape,
 3088                    cx,
 3089                )
 3090            });
 3091        }
 3092        let display_map = self
 3093            .display_map
 3094            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3095        let buffer = display_map.buffer_snapshot();
 3096        if self.selections.count() == 1 {
 3097            self.add_selections_state = None;
 3098        }
 3099        self.select_next_state = None;
 3100        self.select_prev_state = None;
 3101        self.select_syntax_node_history.try_clear();
 3102        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3103        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3104        self.take_rename(false, window, cx);
 3105
 3106        let newest_selection = self.selections.newest_anchor();
 3107        let new_cursor_position = newest_selection.head();
 3108        let selection_start = newest_selection.start;
 3109
 3110        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3111            self.push_to_nav_history(
 3112                *old_cursor_position,
 3113                Some(new_cursor_position.to_point(buffer)),
 3114                false,
 3115                effects.nav_history == Some(true),
 3116                cx,
 3117            );
 3118        }
 3119
 3120        if local {
 3121            if let Some(buffer_id) = new_cursor_position.buffer_id {
 3122                self.register_buffer(buffer_id, cx);
 3123            }
 3124
 3125            let mut context_menu = self.context_menu.borrow_mut();
 3126            let completion_menu = match context_menu.as_ref() {
 3127                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3128                Some(CodeContextMenu::CodeActions(_)) => {
 3129                    *context_menu = None;
 3130                    None
 3131                }
 3132                None => None,
 3133            };
 3134            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3135            drop(context_menu);
 3136
 3137            if effects.completions
 3138                && let Some(completion_position) = completion_position
 3139            {
 3140                let start_offset = selection_start.to_offset(buffer);
 3141                let position_matches = start_offset == completion_position.to_offset(buffer);
 3142                let continue_showing = if position_matches {
 3143                    if self.snippet_stack.is_empty() {
 3144                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3145                            == Some(CharKind::Word)
 3146                    } else {
 3147                        // Snippet choices can be shown even when the cursor is in whitespace.
 3148                        // Dismissing the menu with actions like backspace is handled by
 3149                        // invalidation regions.
 3150                        true
 3151                    }
 3152                } else {
 3153                    false
 3154                };
 3155
 3156                if continue_showing {
 3157                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3158                } else {
 3159                    self.hide_context_menu(window, cx);
 3160                }
 3161            }
 3162
 3163            hide_hover(self, cx);
 3164
 3165            if old_cursor_position.to_display_point(&display_map).row()
 3166                != new_cursor_position.to_display_point(&display_map).row()
 3167            {
 3168                self.available_code_actions.take();
 3169            }
 3170            self.refresh_code_actions(window, cx);
 3171            self.refresh_document_highlights(cx);
 3172            refresh_linked_ranges(self, window, cx);
 3173
 3174            self.refresh_selected_text_highlights(false, window, cx);
 3175            self.refresh_matching_bracket_highlights(window, cx);
 3176            self.update_visible_edit_prediction(window, cx);
 3177            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3178            self.inline_blame_popover.take();
 3179            if self.git_blame_inline_enabled {
 3180                self.start_inline_blame_timer(window, cx);
 3181            }
 3182        }
 3183
 3184        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3185        cx.emit(EditorEvent::SelectionsChanged { local });
 3186
 3187        let selections = &self.selections.disjoint_anchors_arc();
 3188        if selections.len() == 1 {
 3189            cx.emit(SearchEvent::ActiveMatchChanged)
 3190        }
 3191        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3192            let inmemory_selections = selections
 3193                .iter()
 3194                .map(|s| {
 3195                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3196                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3197                })
 3198                .collect();
 3199            self.update_restoration_data(cx, |data| {
 3200                data.selections = inmemory_selections;
 3201            });
 3202
 3203            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3204                && let Some(workspace_id) =
 3205                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3206            {
 3207                let snapshot = self.buffer().read(cx).snapshot(cx);
 3208                let selections = selections.clone();
 3209                let background_executor = cx.background_executor().clone();
 3210                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3211                self.serialize_selections = cx.background_spawn(async move {
 3212                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3213                    let db_selections = selections
 3214                        .iter()
 3215                        .map(|selection| {
 3216                            (
 3217                                selection.start.to_offset(&snapshot),
 3218                                selection.end.to_offset(&snapshot),
 3219                            )
 3220                        })
 3221                        .collect();
 3222
 3223                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3224                        .await
 3225                        .with_context(|| {
 3226                            format!(
 3227                                "persisting editor selections for editor {editor_id}, \
 3228                                workspace {workspace_id:?}"
 3229                            )
 3230                        })
 3231                        .log_err();
 3232                });
 3233            }
 3234        }
 3235
 3236        cx.notify();
 3237    }
 3238
 3239    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3240        use text::ToOffset as _;
 3241        use text::ToPoint as _;
 3242
 3243        if self.mode.is_minimap()
 3244            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3245        {
 3246            return;
 3247        }
 3248
 3249        if !self.buffer().read(cx).is_singleton() {
 3250            return;
 3251        }
 3252
 3253        let display_snapshot = self
 3254            .display_map
 3255            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3256        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3257            return;
 3258        };
 3259        let inmemory_folds = display_snapshot
 3260            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3261            .map(|fold| {
 3262                fold.range.start.text_anchor.to_point(&snapshot)
 3263                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3264            })
 3265            .collect();
 3266        self.update_restoration_data(cx, |data| {
 3267            data.folds = inmemory_folds;
 3268        });
 3269
 3270        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3271            return;
 3272        };
 3273        let background_executor = cx.background_executor().clone();
 3274        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3275        let db_folds = display_snapshot
 3276            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3277            .map(|fold| {
 3278                (
 3279                    fold.range.start.text_anchor.to_offset(&snapshot),
 3280                    fold.range.end.text_anchor.to_offset(&snapshot),
 3281                )
 3282            })
 3283            .collect();
 3284        self.serialize_folds = cx.background_spawn(async move {
 3285            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3286            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3287                .await
 3288                .with_context(|| {
 3289                    format!(
 3290                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3291                    )
 3292                })
 3293                .log_err();
 3294        });
 3295    }
 3296
 3297    pub fn sync_selections(
 3298        &mut self,
 3299        other: Entity<Editor>,
 3300        cx: &mut Context<Self>,
 3301    ) -> gpui::Subscription {
 3302        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3303        if !other_selections.is_empty() {
 3304            self.selections.change_with(cx, |selections| {
 3305                selections.select_anchors(other_selections);
 3306            });
 3307        }
 3308
 3309        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3310            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3311                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3312                if other_selections.is_empty() {
 3313                    return;
 3314                }
 3315                this.selections.change_with(cx, |selections| {
 3316                    selections.select_anchors(other_selections);
 3317                });
 3318            }
 3319        });
 3320
 3321        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3322            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3323                let these_selections = this.selections.disjoint_anchors().to_vec();
 3324                if these_selections.is_empty() {
 3325                    return;
 3326                }
 3327                other.update(cx, |other_editor, cx| {
 3328                    other_editor.selections.change_with(cx, |selections| {
 3329                        selections.select_anchors(these_selections);
 3330                    })
 3331                });
 3332            }
 3333        });
 3334
 3335        Subscription::join(other_subscription, this_subscription)
 3336    }
 3337
 3338    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3339    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3340    /// effects of selection change occur at the end of the transaction.
 3341    pub fn change_selections<R>(
 3342        &mut self,
 3343        effects: SelectionEffects,
 3344        window: &mut Window,
 3345        cx: &mut Context<Self>,
 3346        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3347    ) -> R {
 3348        if let Some(state) = &mut self.deferred_selection_effects_state {
 3349            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3350            state.effects.completions = effects.completions;
 3351            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3352            let (changed, result) = self.selections.change_with(cx, change);
 3353            state.changed |= changed;
 3354            return result;
 3355        }
 3356        let mut state = DeferredSelectionEffectsState {
 3357            changed: false,
 3358            effects,
 3359            old_cursor_position: self.selections.newest_anchor().head(),
 3360            history_entry: SelectionHistoryEntry {
 3361                selections: self.selections.disjoint_anchors_arc(),
 3362                select_next_state: self.select_next_state.clone(),
 3363                select_prev_state: self.select_prev_state.clone(),
 3364                add_selections_state: self.add_selections_state.clone(),
 3365            },
 3366        };
 3367        let (changed, result) = self.selections.change_with(cx, change);
 3368        state.changed = state.changed || changed;
 3369        if self.defer_selection_effects {
 3370            self.deferred_selection_effects_state = Some(state);
 3371        } else {
 3372            self.apply_selection_effects(state, window, cx);
 3373        }
 3374        result
 3375    }
 3376
 3377    /// Defers the effects of selection change, so that the effects of multiple calls to
 3378    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3379    /// to selection history and the state of popovers based on selection position aren't
 3380    /// erroneously updated.
 3381    pub fn with_selection_effects_deferred<R>(
 3382        &mut self,
 3383        window: &mut Window,
 3384        cx: &mut Context<Self>,
 3385        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3386    ) -> R {
 3387        let already_deferred = self.defer_selection_effects;
 3388        self.defer_selection_effects = true;
 3389        let result = update(self, window, cx);
 3390        if !already_deferred {
 3391            self.defer_selection_effects = false;
 3392            if let Some(state) = self.deferred_selection_effects_state.take() {
 3393                self.apply_selection_effects(state, window, cx);
 3394            }
 3395        }
 3396        result
 3397    }
 3398
 3399    fn apply_selection_effects(
 3400        &mut self,
 3401        state: DeferredSelectionEffectsState,
 3402        window: &mut Window,
 3403        cx: &mut Context<Self>,
 3404    ) {
 3405        if state.changed {
 3406            self.selection_history.push(state.history_entry);
 3407
 3408            if let Some(autoscroll) = state.effects.scroll {
 3409                self.request_autoscroll(autoscroll, cx);
 3410            }
 3411
 3412            let old_cursor_position = &state.old_cursor_position;
 3413
 3414            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3415
 3416            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3417                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3418            }
 3419        }
 3420    }
 3421
 3422    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3423    where
 3424        I: IntoIterator<Item = (Range<S>, T)>,
 3425        S: ToOffset,
 3426        T: Into<Arc<str>>,
 3427    {
 3428        if self.read_only(cx) {
 3429            return;
 3430        }
 3431
 3432        self.buffer
 3433            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3434    }
 3435
 3436    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3437    where
 3438        I: IntoIterator<Item = (Range<S>, T)>,
 3439        S: ToOffset,
 3440        T: Into<Arc<str>>,
 3441    {
 3442        if self.read_only(cx) {
 3443            return;
 3444        }
 3445
 3446        self.buffer.update(cx, |buffer, cx| {
 3447            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3448        });
 3449    }
 3450
 3451    pub fn edit_with_block_indent<I, S, T>(
 3452        &mut self,
 3453        edits: I,
 3454        original_indent_columns: Vec<Option<u32>>,
 3455        cx: &mut Context<Self>,
 3456    ) where
 3457        I: IntoIterator<Item = (Range<S>, T)>,
 3458        S: ToOffset,
 3459        T: Into<Arc<str>>,
 3460    {
 3461        if self.read_only(cx) {
 3462            return;
 3463        }
 3464
 3465        self.buffer.update(cx, |buffer, cx| {
 3466            buffer.edit(
 3467                edits,
 3468                Some(AutoindentMode::Block {
 3469                    original_indent_columns,
 3470                }),
 3471                cx,
 3472            )
 3473        });
 3474    }
 3475
 3476    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3477        self.hide_context_menu(window, cx);
 3478
 3479        match phase {
 3480            SelectPhase::Begin {
 3481                position,
 3482                add,
 3483                click_count,
 3484            } => self.begin_selection(position, add, click_count, window, cx),
 3485            SelectPhase::BeginColumnar {
 3486                position,
 3487                goal_column,
 3488                reset,
 3489                mode,
 3490            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3491            SelectPhase::Extend {
 3492                position,
 3493                click_count,
 3494            } => self.extend_selection(position, click_count, window, cx),
 3495            SelectPhase::Update {
 3496                position,
 3497                goal_column,
 3498                scroll_delta,
 3499            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3500            SelectPhase::End => self.end_selection(window, cx),
 3501        }
 3502    }
 3503
 3504    fn extend_selection(
 3505        &mut self,
 3506        position: DisplayPoint,
 3507        click_count: usize,
 3508        window: &mut Window,
 3509        cx: &mut Context<Self>,
 3510    ) {
 3511        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3512        let tail = self.selections.newest::<usize>(&display_map).tail();
 3513        let click_count = click_count.max(match self.selections.select_mode() {
 3514            SelectMode::Character => 1,
 3515            SelectMode::Word(_) => 2,
 3516            SelectMode::Line(_) => 3,
 3517            SelectMode::All => 4,
 3518        });
 3519        self.begin_selection(position, false, click_count, window, cx);
 3520
 3521        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3522
 3523        let current_selection = match self.selections.select_mode() {
 3524            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3525            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3526        };
 3527
 3528        let mut pending_selection = self
 3529            .selections
 3530            .pending_anchor()
 3531            .cloned()
 3532            .expect("extend_selection not called with pending selection");
 3533
 3534        if pending_selection
 3535            .start
 3536            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3537            == Ordering::Greater
 3538        {
 3539            pending_selection.start = current_selection.start;
 3540        }
 3541        if pending_selection
 3542            .end
 3543            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3544            == Ordering::Less
 3545        {
 3546            pending_selection.end = current_selection.end;
 3547            pending_selection.reversed = true;
 3548        }
 3549
 3550        let mut pending_mode = self.selections.pending_mode().unwrap();
 3551        match &mut pending_mode {
 3552            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3553            _ => {}
 3554        }
 3555
 3556        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3557            SelectionEffects::scroll(Autoscroll::fit())
 3558        } else {
 3559            SelectionEffects::no_scroll()
 3560        };
 3561
 3562        self.change_selections(effects, window, cx, |s| {
 3563            s.set_pending(pending_selection.clone(), pending_mode);
 3564            s.set_is_extending(true);
 3565        });
 3566    }
 3567
 3568    fn begin_selection(
 3569        &mut self,
 3570        position: DisplayPoint,
 3571        add: bool,
 3572        click_count: usize,
 3573        window: &mut Window,
 3574        cx: &mut Context<Self>,
 3575    ) {
 3576        if !self.focus_handle.is_focused(window) {
 3577            self.last_focused_descendant = None;
 3578            window.focus(&self.focus_handle);
 3579        }
 3580
 3581        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3582        let buffer = display_map.buffer_snapshot();
 3583        let position = display_map.clip_point(position, Bias::Left);
 3584
 3585        let start;
 3586        let end;
 3587        let mode;
 3588        let mut auto_scroll;
 3589        match click_count {
 3590            1 => {
 3591                start = buffer.anchor_before(position.to_point(&display_map));
 3592                end = start;
 3593                mode = SelectMode::Character;
 3594                auto_scroll = true;
 3595            }
 3596            2 => {
 3597                let position = display_map
 3598                    .clip_point(position, Bias::Left)
 3599                    .to_offset(&display_map, Bias::Left);
 3600                let (range, _) = buffer.surrounding_word(position, None);
 3601                start = buffer.anchor_before(range.start);
 3602                end = buffer.anchor_before(range.end);
 3603                mode = SelectMode::Word(start..end);
 3604                auto_scroll = true;
 3605            }
 3606            3 => {
 3607                let position = display_map
 3608                    .clip_point(position, Bias::Left)
 3609                    .to_point(&display_map);
 3610                let line_start = display_map.prev_line_boundary(position).0;
 3611                let next_line_start = buffer.clip_point(
 3612                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3613                    Bias::Left,
 3614                );
 3615                start = buffer.anchor_before(line_start);
 3616                end = buffer.anchor_before(next_line_start);
 3617                mode = SelectMode::Line(start..end);
 3618                auto_scroll = true;
 3619            }
 3620            _ => {
 3621                start = buffer.anchor_before(0);
 3622                end = buffer.anchor_before(buffer.len());
 3623                mode = SelectMode::All;
 3624                auto_scroll = false;
 3625            }
 3626        }
 3627        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3628
 3629        let point_to_delete: Option<usize> = {
 3630            let selected_points: Vec<Selection<Point>> =
 3631                self.selections.disjoint_in_range(start..end, &display_map);
 3632
 3633            if !add || click_count > 1 {
 3634                None
 3635            } else if !selected_points.is_empty() {
 3636                Some(selected_points[0].id)
 3637            } else {
 3638                let clicked_point_already_selected =
 3639                    self.selections.disjoint_anchors().iter().find(|selection| {
 3640                        selection.start.to_point(buffer) == start.to_point(buffer)
 3641                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3642                    });
 3643
 3644                clicked_point_already_selected.map(|selection| selection.id)
 3645            }
 3646        };
 3647
 3648        let selections_count = self.selections.count();
 3649        let effects = if auto_scroll {
 3650            SelectionEffects::default()
 3651        } else {
 3652            SelectionEffects::no_scroll()
 3653        };
 3654
 3655        self.change_selections(effects, window, cx, |s| {
 3656            if let Some(point_to_delete) = point_to_delete {
 3657                s.delete(point_to_delete);
 3658
 3659                if selections_count == 1 {
 3660                    s.set_pending_anchor_range(start..end, mode);
 3661                }
 3662            } else {
 3663                if !add {
 3664                    s.clear_disjoint();
 3665                }
 3666
 3667                s.set_pending_anchor_range(start..end, mode);
 3668            }
 3669        });
 3670    }
 3671
 3672    fn begin_columnar_selection(
 3673        &mut self,
 3674        position: DisplayPoint,
 3675        goal_column: u32,
 3676        reset: bool,
 3677        mode: ColumnarMode,
 3678        window: &mut Window,
 3679        cx: &mut Context<Self>,
 3680    ) {
 3681        if !self.focus_handle.is_focused(window) {
 3682            self.last_focused_descendant = None;
 3683            window.focus(&self.focus_handle);
 3684        }
 3685
 3686        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3687
 3688        if reset {
 3689            let pointer_position = display_map
 3690                .buffer_snapshot()
 3691                .anchor_before(position.to_point(&display_map));
 3692
 3693            self.change_selections(
 3694                SelectionEffects::scroll(Autoscroll::newest()),
 3695                window,
 3696                cx,
 3697                |s| {
 3698                    s.clear_disjoint();
 3699                    s.set_pending_anchor_range(
 3700                        pointer_position..pointer_position,
 3701                        SelectMode::Character,
 3702                    );
 3703                },
 3704            );
 3705        };
 3706
 3707        let tail = self.selections.newest::<Point>(&display_map).tail();
 3708        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3709        self.columnar_selection_state = match mode {
 3710            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3711                selection_tail: selection_anchor,
 3712                display_point: if reset {
 3713                    if position.column() != goal_column {
 3714                        Some(DisplayPoint::new(position.row(), goal_column))
 3715                    } else {
 3716                        None
 3717                    }
 3718                } else {
 3719                    None
 3720                },
 3721            }),
 3722            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3723                selection_tail: selection_anchor,
 3724            }),
 3725        };
 3726
 3727        if !reset {
 3728            self.select_columns(position, goal_column, &display_map, window, cx);
 3729        }
 3730    }
 3731
 3732    fn update_selection(
 3733        &mut self,
 3734        position: DisplayPoint,
 3735        goal_column: u32,
 3736        scroll_delta: gpui::Point<f32>,
 3737        window: &mut Window,
 3738        cx: &mut Context<Self>,
 3739    ) {
 3740        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3741
 3742        if self.columnar_selection_state.is_some() {
 3743            self.select_columns(position, goal_column, &display_map, window, cx);
 3744        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3745            let buffer = display_map.buffer_snapshot();
 3746            let head;
 3747            let tail;
 3748            let mode = self.selections.pending_mode().unwrap();
 3749            match &mode {
 3750                SelectMode::Character => {
 3751                    head = position.to_point(&display_map);
 3752                    tail = pending.tail().to_point(buffer);
 3753                }
 3754                SelectMode::Word(original_range) => {
 3755                    let offset = display_map
 3756                        .clip_point(position, Bias::Left)
 3757                        .to_offset(&display_map, Bias::Left);
 3758                    let original_range = original_range.to_offset(buffer);
 3759
 3760                    let head_offset = if buffer.is_inside_word(offset, None)
 3761                        || original_range.contains(&offset)
 3762                    {
 3763                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3764                        if word_range.start < original_range.start {
 3765                            word_range.start
 3766                        } else {
 3767                            word_range.end
 3768                        }
 3769                    } else {
 3770                        offset
 3771                    };
 3772
 3773                    head = head_offset.to_point(buffer);
 3774                    if head_offset <= original_range.start {
 3775                        tail = original_range.end.to_point(buffer);
 3776                    } else {
 3777                        tail = original_range.start.to_point(buffer);
 3778                    }
 3779                }
 3780                SelectMode::Line(original_range) => {
 3781                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3782
 3783                    let position = display_map
 3784                        .clip_point(position, Bias::Left)
 3785                        .to_point(&display_map);
 3786                    let line_start = display_map.prev_line_boundary(position).0;
 3787                    let next_line_start = buffer.clip_point(
 3788                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3789                        Bias::Left,
 3790                    );
 3791
 3792                    if line_start < original_range.start {
 3793                        head = line_start
 3794                    } else {
 3795                        head = next_line_start
 3796                    }
 3797
 3798                    if head <= original_range.start {
 3799                        tail = original_range.end;
 3800                    } else {
 3801                        tail = original_range.start;
 3802                    }
 3803                }
 3804                SelectMode::All => {
 3805                    return;
 3806                }
 3807            };
 3808
 3809            if head < tail {
 3810                pending.start = buffer.anchor_before(head);
 3811                pending.end = buffer.anchor_before(tail);
 3812                pending.reversed = true;
 3813            } else {
 3814                pending.start = buffer.anchor_before(tail);
 3815                pending.end = buffer.anchor_before(head);
 3816                pending.reversed = false;
 3817            }
 3818
 3819            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3820                s.set_pending(pending.clone(), mode);
 3821            });
 3822        } else {
 3823            log::error!("update_selection dispatched with no pending selection");
 3824            return;
 3825        }
 3826
 3827        self.apply_scroll_delta(scroll_delta, window, cx);
 3828        cx.notify();
 3829    }
 3830
 3831    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3832        self.columnar_selection_state.take();
 3833        if let Some(pending_mode) = self.selections.pending_mode() {
 3834            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3835            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3836                s.select(selections);
 3837                s.clear_pending();
 3838                if s.is_extending() {
 3839                    s.set_is_extending(false);
 3840                } else {
 3841                    s.set_select_mode(pending_mode);
 3842                }
 3843            });
 3844        }
 3845    }
 3846
 3847    fn select_columns(
 3848        &mut self,
 3849        head: DisplayPoint,
 3850        goal_column: u32,
 3851        display_map: &DisplaySnapshot,
 3852        window: &mut Window,
 3853        cx: &mut Context<Self>,
 3854    ) {
 3855        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3856            return;
 3857        };
 3858
 3859        let tail = match columnar_state {
 3860            ColumnarSelectionState::FromMouse {
 3861                selection_tail,
 3862                display_point,
 3863            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3864            ColumnarSelectionState::FromSelection { selection_tail } => {
 3865                selection_tail.to_display_point(display_map)
 3866            }
 3867        };
 3868
 3869        let start_row = cmp::min(tail.row(), head.row());
 3870        let end_row = cmp::max(tail.row(), head.row());
 3871        let start_column = cmp::min(tail.column(), goal_column);
 3872        let end_column = cmp::max(tail.column(), goal_column);
 3873        let reversed = start_column < tail.column();
 3874
 3875        let selection_ranges = (start_row.0..=end_row.0)
 3876            .map(DisplayRow)
 3877            .filter_map(|row| {
 3878                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3879                    || start_column <= display_map.line_len(row))
 3880                    && !display_map.is_block_line(row)
 3881                {
 3882                    let start = display_map
 3883                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3884                        .to_point(display_map);
 3885                    let end = display_map
 3886                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3887                        .to_point(display_map);
 3888                    if reversed {
 3889                        Some(end..start)
 3890                    } else {
 3891                        Some(start..end)
 3892                    }
 3893                } else {
 3894                    None
 3895                }
 3896            })
 3897            .collect::<Vec<_>>();
 3898        if selection_ranges.is_empty() {
 3899            return;
 3900        }
 3901
 3902        let ranges = match columnar_state {
 3903            ColumnarSelectionState::FromMouse { .. } => {
 3904                let mut non_empty_ranges = selection_ranges
 3905                    .iter()
 3906                    .filter(|selection_range| selection_range.start != selection_range.end)
 3907                    .peekable();
 3908                if non_empty_ranges.peek().is_some() {
 3909                    non_empty_ranges.cloned().collect()
 3910                } else {
 3911                    selection_ranges
 3912                }
 3913            }
 3914            _ => selection_ranges,
 3915        };
 3916
 3917        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3918            s.select_ranges(ranges);
 3919        });
 3920        cx.notify();
 3921    }
 3922
 3923    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 3924        self.selections
 3925            .all_adjusted(snapshot)
 3926            .iter()
 3927            .any(|selection| !selection.is_empty())
 3928    }
 3929
 3930    pub fn has_pending_nonempty_selection(&self) -> bool {
 3931        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3932            Some(Selection { start, end, .. }) => start != end,
 3933            None => false,
 3934        };
 3935
 3936        pending_nonempty_selection
 3937            || (self.columnar_selection_state.is_some()
 3938                && self.selections.disjoint_anchors().len() > 1)
 3939    }
 3940
 3941    pub fn has_pending_selection(&self) -> bool {
 3942        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3943    }
 3944
 3945    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3946        self.selection_mark_mode = false;
 3947        self.selection_drag_state = SelectionDragState::None;
 3948
 3949        if self.clear_expanded_diff_hunks(cx) {
 3950            cx.notify();
 3951            return;
 3952        }
 3953        if self.dismiss_menus_and_popups(true, window, cx) {
 3954            return;
 3955        }
 3956
 3957        if self.mode.is_full()
 3958            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3959        {
 3960            return;
 3961        }
 3962
 3963        cx.propagate();
 3964    }
 3965
 3966    pub fn dismiss_menus_and_popups(
 3967        &mut self,
 3968        is_user_requested: bool,
 3969        window: &mut Window,
 3970        cx: &mut Context<Self>,
 3971    ) -> bool {
 3972        if self.take_rename(false, window, cx).is_some() {
 3973            return true;
 3974        }
 3975
 3976        if self.hide_blame_popover(true, cx) {
 3977            return true;
 3978        }
 3979
 3980        if hide_hover(self, cx) {
 3981            return true;
 3982        }
 3983
 3984        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3985            return true;
 3986        }
 3987
 3988        if self.hide_context_menu(window, cx).is_some() {
 3989            return true;
 3990        }
 3991
 3992        if self.mouse_context_menu.take().is_some() {
 3993            return true;
 3994        }
 3995
 3996        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3997            return true;
 3998        }
 3999
 4000        if self.snippet_stack.pop().is_some() {
 4001            return true;
 4002        }
 4003
 4004        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4005            self.dismiss_diagnostics(cx);
 4006            return true;
 4007        }
 4008
 4009        false
 4010    }
 4011
 4012    fn linked_editing_ranges_for(
 4013        &self,
 4014        selection: Range<text::Anchor>,
 4015        cx: &App,
 4016    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4017        if self.linked_edit_ranges.is_empty() {
 4018            return None;
 4019        }
 4020        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4021            selection.end.buffer_id.and_then(|end_buffer_id| {
 4022                if selection.start.buffer_id != Some(end_buffer_id) {
 4023                    return None;
 4024                }
 4025                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4026                let snapshot = buffer.read(cx).snapshot();
 4027                self.linked_edit_ranges
 4028                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4029                    .map(|ranges| (ranges, snapshot, buffer))
 4030            })?;
 4031        use text::ToOffset as TO;
 4032        // find offset from the start of current range to current cursor position
 4033        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4034
 4035        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4036        let start_difference = start_offset - start_byte_offset;
 4037        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4038        let end_difference = end_offset - start_byte_offset;
 4039        // Current range has associated linked ranges.
 4040        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4041        for range in linked_ranges.iter() {
 4042            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4043            let end_offset = start_offset + end_difference;
 4044            let start_offset = start_offset + start_difference;
 4045            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4046                continue;
 4047            }
 4048            if self.selections.disjoint_anchor_ranges().any(|s| {
 4049                if s.start.buffer_id != selection.start.buffer_id
 4050                    || s.end.buffer_id != selection.end.buffer_id
 4051                {
 4052                    return false;
 4053                }
 4054                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4055                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4056            }) {
 4057                continue;
 4058            }
 4059            let start = buffer_snapshot.anchor_after(start_offset);
 4060            let end = buffer_snapshot.anchor_after(end_offset);
 4061            linked_edits
 4062                .entry(buffer.clone())
 4063                .or_default()
 4064                .push(start..end);
 4065        }
 4066        Some(linked_edits)
 4067    }
 4068
 4069    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4070        let text: Arc<str> = text.into();
 4071
 4072        if self.read_only(cx) {
 4073            return;
 4074        }
 4075
 4076        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4077
 4078        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4079        let mut bracket_inserted = false;
 4080        let mut edits = Vec::new();
 4081        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4082        let mut new_selections = Vec::with_capacity(selections.len());
 4083        let mut new_autoclose_regions = Vec::new();
 4084        let snapshot = self.buffer.read(cx).read(cx);
 4085        let mut clear_linked_edit_ranges = false;
 4086
 4087        for (selection, autoclose_region) in
 4088            self.selections_with_autoclose_regions(selections, &snapshot)
 4089        {
 4090            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4091                // Determine if the inserted text matches the opening or closing
 4092                // bracket of any of this language's bracket pairs.
 4093                let mut bracket_pair = None;
 4094                let mut is_bracket_pair_start = false;
 4095                let mut is_bracket_pair_end = false;
 4096                if !text.is_empty() {
 4097                    let mut bracket_pair_matching_end = None;
 4098                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4099                    //  and they are removing the character that triggered IME popup.
 4100                    for (pair, enabled) in scope.brackets() {
 4101                        if !pair.close && !pair.surround {
 4102                            continue;
 4103                        }
 4104
 4105                        if enabled && pair.start.ends_with(text.as_ref()) {
 4106                            let prefix_len = pair.start.len() - text.len();
 4107                            let preceding_text_matches_prefix = prefix_len == 0
 4108                                || (selection.start.column >= (prefix_len as u32)
 4109                                    && snapshot.contains_str_at(
 4110                                        Point::new(
 4111                                            selection.start.row,
 4112                                            selection.start.column - (prefix_len as u32),
 4113                                        ),
 4114                                        &pair.start[..prefix_len],
 4115                                    ));
 4116                            if preceding_text_matches_prefix {
 4117                                bracket_pair = Some(pair.clone());
 4118                                is_bracket_pair_start = true;
 4119                                break;
 4120                            }
 4121                        }
 4122                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4123                        {
 4124                            // take first bracket pair matching end, but don't break in case a later bracket
 4125                            // pair matches start
 4126                            bracket_pair_matching_end = Some(pair.clone());
 4127                        }
 4128                    }
 4129                    if let Some(end) = bracket_pair_matching_end
 4130                        && bracket_pair.is_none()
 4131                    {
 4132                        bracket_pair = Some(end);
 4133                        is_bracket_pair_end = true;
 4134                    }
 4135                }
 4136
 4137                if let Some(bracket_pair) = bracket_pair {
 4138                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4139                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4140                    let auto_surround =
 4141                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4142                    if selection.is_empty() {
 4143                        if is_bracket_pair_start {
 4144                            // If the inserted text is a suffix of an opening bracket and the
 4145                            // selection is preceded by the rest of the opening bracket, then
 4146                            // insert the closing bracket.
 4147                            let following_text_allows_autoclose = snapshot
 4148                                .chars_at(selection.start)
 4149                                .next()
 4150                                .is_none_or(|c| scope.should_autoclose_before(c));
 4151
 4152                            let preceding_text_allows_autoclose = selection.start.column == 0
 4153                                || snapshot
 4154                                    .reversed_chars_at(selection.start)
 4155                                    .next()
 4156                                    .is_none_or(|c| {
 4157                                        bracket_pair.start != bracket_pair.end
 4158                                            || !snapshot
 4159                                                .char_classifier_at(selection.start)
 4160                                                .is_word(c)
 4161                                    });
 4162
 4163                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4164                                && bracket_pair.start.len() == 1
 4165                            {
 4166                                let target = bracket_pair.start.chars().next().unwrap();
 4167                                let current_line_count = snapshot
 4168                                    .reversed_chars_at(selection.start)
 4169                                    .take_while(|&c| c != '\n')
 4170                                    .filter(|&c| c == target)
 4171                                    .count();
 4172                                current_line_count % 2 == 1
 4173                            } else {
 4174                                false
 4175                            };
 4176
 4177                            if autoclose
 4178                                && bracket_pair.close
 4179                                && following_text_allows_autoclose
 4180                                && preceding_text_allows_autoclose
 4181                                && !is_closing_quote
 4182                            {
 4183                                let anchor = snapshot.anchor_before(selection.end);
 4184                                new_selections.push((selection.map(|_| anchor), text.len()));
 4185                                new_autoclose_regions.push((
 4186                                    anchor,
 4187                                    text.len(),
 4188                                    selection.id,
 4189                                    bracket_pair.clone(),
 4190                                ));
 4191                                edits.push((
 4192                                    selection.range(),
 4193                                    format!("{}{}", text, bracket_pair.end).into(),
 4194                                ));
 4195                                bracket_inserted = true;
 4196                                continue;
 4197                            }
 4198                        }
 4199
 4200                        if let Some(region) = autoclose_region {
 4201                            // If the selection is followed by an auto-inserted closing bracket,
 4202                            // then don't insert that closing bracket again; just move the selection
 4203                            // past the closing bracket.
 4204                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4205                                && text.as_ref() == region.pair.end.as_str()
 4206                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4207                            if should_skip {
 4208                                let anchor = snapshot.anchor_after(selection.end);
 4209                                new_selections
 4210                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4211                                continue;
 4212                            }
 4213                        }
 4214
 4215                        let always_treat_brackets_as_autoclosed = snapshot
 4216                            .language_settings_at(selection.start, cx)
 4217                            .always_treat_brackets_as_autoclosed;
 4218                        if always_treat_brackets_as_autoclosed
 4219                            && is_bracket_pair_end
 4220                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4221                        {
 4222                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4223                            // and the inserted text is a closing bracket and the selection is followed
 4224                            // by the closing bracket then move the selection past the closing bracket.
 4225                            let anchor = snapshot.anchor_after(selection.end);
 4226                            new_selections.push((selection.map(|_| anchor), text.len()));
 4227                            continue;
 4228                        }
 4229                    }
 4230                    // If an opening bracket is 1 character long and is typed while
 4231                    // text is selected, then surround that text with the bracket pair.
 4232                    else if auto_surround
 4233                        && bracket_pair.surround
 4234                        && is_bracket_pair_start
 4235                        && bracket_pair.start.chars().count() == 1
 4236                    {
 4237                        edits.push((selection.start..selection.start, text.clone()));
 4238                        edits.push((
 4239                            selection.end..selection.end,
 4240                            bracket_pair.end.as_str().into(),
 4241                        ));
 4242                        bracket_inserted = true;
 4243                        new_selections.push((
 4244                            Selection {
 4245                                id: selection.id,
 4246                                start: snapshot.anchor_after(selection.start),
 4247                                end: snapshot.anchor_before(selection.end),
 4248                                reversed: selection.reversed,
 4249                                goal: selection.goal,
 4250                            },
 4251                            0,
 4252                        ));
 4253                        continue;
 4254                    }
 4255                }
 4256            }
 4257
 4258            if self.auto_replace_emoji_shortcode
 4259                && selection.is_empty()
 4260                && text.as_ref().ends_with(':')
 4261                && let Some(possible_emoji_short_code) =
 4262                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4263                && !possible_emoji_short_code.is_empty()
 4264                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4265            {
 4266                let emoji_shortcode_start = Point::new(
 4267                    selection.start.row,
 4268                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4269                );
 4270
 4271                // Remove shortcode from buffer
 4272                edits.push((
 4273                    emoji_shortcode_start..selection.start,
 4274                    "".to_string().into(),
 4275                ));
 4276                new_selections.push((
 4277                    Selection {
 4278                        id: selection.id,
 4279                        start: snapshot.anchor_after(emoji_shortcode_start),
 4280                        end: snapshot.anchor_before(selection.start),
 4281                        reversed: selection.reversed,
 4282                        goal: selection.goal,
 4283                    },
 4284                    0,
 4285                ));
 4286
 4287                // Insert emoji
 4288                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4289                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4290                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4291
 4292                continue;
 4293            }
 4294
 4295            // If not handling any auto-close operation, then just replace the selected
 4296            // text with the given input and move the selection to the end of the
 4297            // newly inserted text.
 4298            let anchor = snapshot.anchor_after(selection.end);
 4299            if !self.linked_edit_ranges.is_empty() {
 4300                let start_anchor = snapshot.anchor_before(selection.start);
 4301
 4302                let is_word_char = text.chars().next().is_none_or(|char| {
 4303                    let classifier = snapshot
 4304                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4305                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4306                    classifier.is_word(char)
 4307                });
 4308
 4309                if is_word_char {
 4310                    if let Some(ranges) = self
 4311                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4312                    {
 4313                        for (buffer, edits) in ranges {
 4314                            linked_edits
 4315                                .entry(buffer.clone())
 4316                                .or_default()
 4317                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4318                        }
 4319                    }
 4320                } else {
 4321                    clear_linked_edit_ranges = true;
 4322                }
 4323            }
 4324
 4325            new_selections.push((selection.map(|_| anchor), 0));
 4326            edits.push((selection.start..selection.end, text.clone()));
 4327        }
 4328
 4329        drop(snapshot);
 4330
 4331        self.transact(window, cx, |this, window, cx| {
 4332            if clear_linked_edit_ranges {
 4333                this.linked_edit_ranges.clear();
 4334            }
 4335            let initial_buffer_versions =
 4336                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4337
 4338            this.buffer.update(cx, |buffer, cx| {
 4339                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4340            });
 4341            for (buffer, edits) in linked_edits {
 4342                buffer.update(cx, |buffer, cx| {
 4343                    let snapshot = buffer.snapshot();
 4344                    let edits = edits
 4345                        .into_iter()
 4346                        .map(|(range, text)| {
 4347                            use text::ToPoint as TP;
 4348                            let end_point = TP::to_point(&range.end, &snapshot);
 4349                            let start_point = TP::to_point(&range.start, &snapshot);
 4350                            (start_point..end_point, text)
 4351                        })
 4352                        .sorted_by_key(|(range, _)| range.start);
 4353                    buffer.edit(edits, None, cx);
 4354                })
 4355            }
 4356            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4357            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4358            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4359            let new_selections =
 4360                resolve_selections_wrapping_blocks::<usize, _>(new_anchor_selections, &map)
 4361                    .zip(new_selection_deltas)
 4362                    .map(|(selection, delta)| Selection {
 4363                        id: selection.id,
 4364                        start: selection.start + delta,
 4365                        end: selection.end + delta,
 4366                        reversed: selection.reversed,
 4367                        goal: SelectionGoal::None,
 4368                    })
 4369                    .collect::<Vec<_>>();
 4370
 4371            let mut i = 0;
 4372            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4373                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4374                let start = map.buffer_snapshot().anchor_before(position);
 4375                let end = map.buffer_snapshot().anchor_after(position);
 4376                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4377                    match existing_state
 4378                        .range
 4379                        .start
 4380                        .cmp(&start, map.buffer_snapshot())
 4381                    {
 4382                        Ordering::Less => i += 1,
 4383                        Ordering::Greater => break,
 4384                        Ordering::Equal => {
 4385                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4386                                Ordering::Less => i += 1,
 4387                                Ordering::Equal => break,
 4388                                Ordering::Greater => break,
 4389                            }
 4390                        }
 4391                    }
 4392                }
 4393                this.autoclose_regions.insert(
 4394                    i,
 4395                    AutocloseRegion {
 4396                        selection_id,
 4397                        range: start..end,
 4398                        pair,
 4399                    },
 4400                );
 4401            }
 4402
 4403            let had_active_edit_prediction = this.has_active_edit_prediction();
 4404            this.change_selections(
 4405                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4406                window,
 4407                cx,
 4408                |s| s.select(new_selections),
 4409            );
 4410
 4411            if !bracket_inserted
 4412                && let Some(on_type_format_task) =
 4413                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4414            {
 4415                on_type_format_task.detach_and_log_err(cx);
 4416            }
 4417
 4418            let editor_settings = EditorSettings::get_global(cx);
 4419            if bracket_inserted
 4420                && (editor_settings.auto_signature_help
 4421                    || editor_settings.show_signature_help_after_edits)
 4422            {
 4423                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4424            }
 4425
 4426            let trigger_in_words =
 4427                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4428            if this.hard_wrap.is_some() {
 4429                let latest: Range<Point> = this.selections.newest(&map).range();
 4430                if latest.is_empty()
 4431                    && this
 4432                        .buffer()
 4433                        .read(cx)
 4434                        .snapshot(cx)
 4435                        .line_len(MultiBufferRow(latest.start.row))
 4436                        == latest.start.column
 4437                {
 4438                    this.rewrap_impl(
 4439                        RewrapOptions {
 4440                            override_language_settings: true,
 4441                            preserve_existing_whitespace: true,
 4442                        },
 4443                        cx,
 4444                    )
 4445                }
 4446            }
 4447            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4448            refresh_linked_ranges(this, window, cx);
 4449            this.refresh_edit_prediction(true, false, window, cx);
 4450            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4451        });
 4452    }
 4453
 4454    fn find_possible_emoji_shortcode_at_position(
 4455        snapshot: &MultiBufferSnapshot,
 4456        position: Point,
 4457    ) -> Option<String> {
 4458        let mut chars = Vec::new();
 4459        let mut found_colon = false;
 4460        for char in snapshot.reversed_chars_at(position).take(100) {
 4461            // Found a possible emoji shortcode in the middle of the buffer
 4462            if found_colon {
 4463                if char.is_whitespace() {
 4464                    chars.reverse();
 4465                    return Some(chars.iter().collect());
 4466                }
 4467                // If the previous character is not a whitespace, we are in the middle of a word
 4468                // and we only want to complete the shortcode if the word is made up of other emojis
 4469                let mut containing_word = String::new();
 4470                for ch in snapshot
 4471                    .reversed_chars_at(position)
 4472                    .skip(chars.len() + 1)
 4473                    .take(100)
 4474                {
 4475                    if ch.is_whitespace() {
 4476                        break;
 4477                    }
 4478                    containing_word.push(ch);
 4479                }
 4480                let containing_word = containing_word.chars().rev().collect::<String>();
 4481                if util::word_consists_of_emojis(containing_word.as_str()) {
 4482                    chars.reverse();
 4483                    return Some(chars.iter().collect());
 4484                }
 4485            }
 4486
 4487            if char.is_whitespace() || !char.is_ascii() {
 4488                return None;
 4489            }
 4490            if char == ':' {
 4491                found_colon = true;
 4492            } else {
 4493                chars.push(char);
 4494            }
 4495        }
 4496        // Found a possible emoji shortcode at the beginning of the buffer
 4497        chars.reverse();
 4498        Some(chars.iter().collect())
 4499    }
 4500
 4501    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4502        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4503        self.transact(window, cx, |this, window, cx| {
 4504            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4505                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
 4506                let multi_buffer = this.buffer.read(cx);
 4507                let buffer = multi_buffer.snapshot(cx);
 4508                selections
 4509                    .iter()
 4510                    .map(|selection| {
 4511                        let start_point = selection.start.to_point(&buffer);
 4512                        let mut existing_indent =
 4513                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4514                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4515                        let start = selection.start;
 4516                        let end = selection.end;
 4517                        let selection_is_empty = start == end;
 4518                        let language_scope = buffer.language_scope_at(start);
 4519                        let (
 4520                            comment_delimiter,
 4521                            doc_delimiter,
 4522                            insert_extra_newline,
 4523                            indent_on_newline,
 4524                            indent_on_extra_newline,
 4525                        ) = if let Some(language) = &language_scope {
 4526                            let mut insert_extra_newline =
 4527                                insert_extra_newline_brackets(&buffer, start..end, language)
 4528                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4529
 4530                            // Comment extension on newline is allowed only for cursor selections
 4531                            let comment_delimiter = maybe!({
 4532                                if !selection_is_empty {
 4533                                    return None;
 4534                                }
 4535
 4536                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4537                                    return None;
 4538                                }
 4539
 4540                                let delimiters = language.line_comment_prefixes();
 4541                                let max_len_of_delimiter =
 4542                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4543                                let (snapshot, range) =
 4544                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4545
 4546                                let num_of_whitespaces = snapshot
 4547                                    .chars_for_range(range.clone())
 4548                                    .take_while(|c| c.is_whitespace())
 4549                                    .count();
 4550                                let comment_candidate = snapshot
 4551                                    .chars_for_range(range.clone())
 4552                                    .skip(num_of_whitespaces)
 4553                                    .take(max_len_of_delimiter)
 4554                                    .collect::<String>();
 4555                                let (delimiter, trimmed_len) = delimiters
 4556                                    .iter()
 4557                                    .filter_map(|delimiter| {
 4558                                        let prefix = delimiter.trim_end();
 4559                                        if comment_candidate.starts_with(prefix) {
 4560                                            Some((delimiter, prefix.len()))
 4561                                        } else {
 4562                                            None
 4563                                        }
 4564                                    })
 4565                                    .max_by_key(|(_, len)| *len)?;
 4566
 4567                                if let Some(BlockCommentConfig {
 4568                                    start: block_start, ..
 4569                                }) = language.block_comment()
 4570                                {
 4571                                    let block_start_trimmed = block_start.trim_end();
 4572                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4573                                        let line_content = snapshot
 4574                                            .chars_for_range(range)
 4575                                            .skip(num_of_whitespaces)
 4576                                            .take(block_start_trimmed.len())
 4577                                            .collect::<String>();
 4578
 4579                                        if line_content.starts_with(block_start_trimmed) {
 4580                                            return None;
 4581                                        }
 4582                                    }
 4583                                }
 4584
 4585                                let cursor_is_placed_after_comment_marker =
 4586                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4587                                if cursor_is_placed_after_comment_marker {
 4588                                    Some(delimiter.clone())
 4589                                } else {
 4590                                    None
 4591                                }
 4592                            });
 4593
 4594                            let mut indent_on_newline = IndentSize::spaces(0);
 4595                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4596
 4597                            let doc_delimiter = maybe!({
 4598                                if !selection_is_empty {
 4599                                    return None;
 4600                                }
 4601
 4602                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4603                                    return None;
 4604                                }
 4605
 4606                                let BlockCommentConfig {
 4607                                    start: start_tag,
 4608                                    end: end_tag,
 4609                                    prefix: delimiter,
 4610                                    tab_size: len,
 4611                                } = language.documentation_comment()?;
 4612                                let is_within_block_comment = buffer
 4613                                    .language_scope_at(start_point)
 4614                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4615                                if !is_within_block_comment {
 4616                                    return None;
 4617                                }
 4618
 4619                                let (snapshot, range) =
 4620                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4621
 4622                                let num_of_whitespaces = snapshot
 4623                                    .chars_for_range(range.clone())
 4624                                    .take_while(|c| c.is_whitespace())
 4625                                    .count();
 4626
 4627                                // 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.
 4628                                let column = start_point.column;
 4629                                let cursor_is_after_start_tag = {
 4630                                    let start_tag_len = start_tag.len();
 4631                                    let start_tag_line = snapshot
 4632                                        .chars_for_range(range.clone())
 4633                                        .skip(num_of_whitespaces)
 4634                                        .take(start_tag_len)
 4635                                        .collect::<String>();
 4636                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4637                                        num_of_whitespaces + start_tag_len <= column as usize
 4638                                    } else {
 4639                                        false
 4640                                    }
 4641                                };
 4642
 4643                                let cursor_is_after_delimiter = {
 4644                                    let delimiter_trim = delimiter.trim_end();
 4645                                    let delimiter_line = snapshot
 4646                                        .chars_for_range(range.clone())
 4647                                        .skip(num_of_whitespaces)
 4648                                        .take(delimiter_trim.len())
 4649                                        .collect::<String>();
 4650                                    if delimiter_line.starts_with(delimiter_trim) {
 4651                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4652                                    } else {
 4653                                        false
 4654                                    }
 4655                                };
 4656
 4657                                let cursor_is_before_end_tag_if_exists = {
 4658                                    let mut char_position = 0u32;
 4659                                    let mut end_tag_offset = None;
 4660
 4661                                    'outer: for chunk in snapshot.text_for_range(range) {
 4662                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4663                                            let chars_before_match =
 4664                                                chunk[..byte_pos].chars().count() as u32;
 4665                                            end_tag_offset =
 4666                                                Some(char_position + chars_before_match);
 4667                                            break 'outer;
 4668                                        }
 4669                                        char_position += chunk.chars().count() as u32;
 4670                                    }
 4671
 4672                                    if let Some(end_tag_offset) = end_tag_offset {
 4673                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4674                                        if cursor_is_after_start_tag {
 4675                                            if cursor_is_before_end_tag {
 4676                                                insert_extra_newline = true;
 4677                                            }
 4678                                            let cursor_is_at_start_of_end_tag =
 4679                                                column == end_tag_offset;
 4680                                            if cursor_is_at_start_of_end_tag {
 4681                                                indent_on_extra_newline.len = *len;
 4682                                            }
 4683                                        }
 4684                                        cursor_is_before_end_tag
 4685                                    } else {
 4686                                        true
 4687                                    }
 4688                                };
 4689
 4690                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4691                                    && cursor_is_before_end_tag_if_exists
 4692                                {
 4693                                    if cursor_is_after_start_tag {
 4694                                        indent_on_newline.len = *len;
 4695                                    }
 4696                                    Some(delimiter.clone())
 4697                                } else {
 4698                                    None
 4699                                }
 4700                            });
 4701
 4702                            (
 4703                                comment_delimiter,
 4704                                doc_delimiter,
 4705                                insert_extra_newline,
 4706                                indent_on_newline,
 4707                                indent_on_extra_newline,
 4708                            )
 4709                        } else {
 4710                            (
 4711                                None,
 4712                                None,
 4713                                false,
 4714                                IndentSize::default(),
 4715                                IndentSize::default(),
 4716                            )
 4717                        };
 4718
 4719                        let prevent_auto_indent = doc_delimiter.is_some();
 4720                        let delimiter = comment_delimiter.or(doc_delimiter);
 4721
 4722                        let capacity_for_delimiter =
 4723                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4724                        let mut new_text = String::with_capacity(
 4725                            1 + capacity_for_delimiter
 4726                                + existing_indent.len as usize
 4727                                + indent_on_newline.len as usize
 4728                                + indent_on_extra_newline.len as usize,
 4729                        );
 4730                        new_text.push('\n');
 4731                        new_text.extend(existing_indent.chars());
 4732                        new_text.extend(indent_on_newline.chars());
 4733
 4734                        if let Some(delimiter) = &delimiter {
 4735                            new_text.push_str(delimiter);
 4736                        }
 4737
 4738                        if insert_extra_newline {
 4739                            new_text.push('\n');
 4740                            new_text.extend(existing_indent.chars());
 4741                            new_text.extend(indent_on_extra_newline.chars());
 4742                        }
 4743
 4744                        let anchor = buffer.anchor_after(end);
 4745                        let new_selection = selection.map(|_| anchor);
 4746                        (
 4747                            ((start..end, new_text), prevent_auto_indent),
 4748                            (insert_extra_newline, new_selection),
 4749                        )
 4750                    })
 4751                    .unzip()
 4752            };
 4753
 4754            let mut auto_indent_edits = Vec::new();
 4755            let mut edits = Vec::new();
 4756            for (edit, prevent_auto_indent) in edits_with_flags {
 4757                if prevent_auto_indent {
 4758                    edits.push(edit);
 4759                } else {
 4760                    auto_indent_edits.push(edit);
 4761                }
 4762            }
 4763            if !edits.is_empty() {
 4764                this.edit(edits, cx);
 4765            }
 4766            if !auto_indent_edits.is_empty() {
 4767                this.edit_with_autoindent(auto_indent_edits, cx);
 4768            }
 4769
 4770            let buffer = this.buffer.read(cx).snapshot(cx);
 4771            let new_selections = selection_info
 4772                .into_iter()
 4773                .map(|(extra_newline_inserted, new_selection)| {
 4774                    let mut cursor = new_selection.end.to_point(&buffer);
 4775                    if extra_newline_inserted {
 4776                        cursor.row -= 1;
 4777                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4778                    }
 4779                    new_selection.map(|_| cursor)
 4780                })
 4781                .collect();
 4782
 4783            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4784            this.refresh_edit_prediction(true, false, window, cx);
 4785        });
 4786    }
 4787
 4788    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4789        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4790
 4791        let buffer = self.buffer.read(cx);
 4792        let snapshot = buffer.snapshot(cx);
 4793
 4794        let mut edits = Vec::new();
 4795        let mut rows = Vec::new();
 4796
 4797        for (rows_inserted, selection) in self
 4798            .selections
 4799            .all_adjusted(&self.display_snapshot(cx))
 4800            .into_iter()
 4801            .enumerate()
 4802        {
 4803            let cursor = selection.head();
 4804            let row = cursor.row;
 4805
 4806            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4807
 4808            let newline = "\n".to_string();
 4809            edits.push((start_of_line..start_of_line, newline));
 4810
 4811            rows.push(row + rows_inserted as u32);
 4812        }
 4813
 4814        self.transact(window, cx, |editor, window, cx| {
 4815            editor.edit(edits, cx);
 4816
 4817            editor.change_selections(Default::default(), window, cx, |s| {
 4818                let mut index = 0;
 4819                s.move_cursors_with(|map, _, _| {
 4820                    let row = rows[index];
 4821                    index += 1;
 4822
 4823                    let point = Point::new(row, 0);
 4824                    let boundary = map.next_line_boundary(point).1;
 4825                    let clipped = map.clip_point(boundary, Bias::Left);
 4826
 4827                    (clipped, SelectionGoal::None)
 4828                });
 4829            });
 4830
 4831            let mut indent_edits = Vec::new();
 4832            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4833            for row in rows {
 4834                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4835                for (row, indent) in indents {
 4836                    if indent.len == 0 {
 4837                        continue;
 4838                    }
 4839
 4840                    let text = match indent.kind {
 4841                        IndentKind::Space => " ".repeat(indent.len as usize),
 4842                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4843                    };
 4844                    let point = Point::new(row.0, 0);
 4845                    indent_edits.push((point..point, text));
 4846                }
 4847            }
 4848            editor.edit(indent_edits, cx);
 4849        });
 4850    }
 4851
 4852    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4853        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4854
 4855        let buffer = self.buffer.read(cx);
 4856        let snapshot = buffer.snapshot(cx);
 4857
 4858        let mut edits = Vec::new();
 4859        let mut rows = Vec::new();
 4860        let mut rows_inserted = 0;
 4861
 4862        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 4863            let cursor = selection.head();
 4864            let row = cursor.row;
 4865
 4866            let point = Point::new(row + 1, 0);
 4867            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4868
 4869            let newline = "\n".to_string();
 4870            edits.push((start_of_line..start_of_line, newline));
 4871
 4872            rows_inserted += 1;
 4873            rows.push(row + rows_inserted);
 4874        }
 4875
 4876        self.transact(window, cx, |editor, window, cx| {
 4877            editor.edit(edits, cx);
 4878
 4879            editor.change_selections(Default::default(), window, cx, |s| {
 4880                let mut index = 0;
 4881                s.move_cursors_with(|map, _, _| {
 4882                    let row = rows[index];
 4883                    index += 1;
 4884
 4885                    let point = Point::new(row, 0);
 4886                    let boundary = map.next_line_boundary(point).1;
 4887                    let clipped = map.clip_point(boundary, Bias::Left);
 4888
 4889                    (clipped, SelectionGoal::None)
 4890                });
 4891            });
 4892
 4893            let mut indent_edits = Vec::new();
 4894            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4895            for row in rows {
 4896                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4897                for (row, indent) in indents {
 4898                    if indent.len == 0 {
 4899                        continue;
 4900                    }
 4901
 4902                    let text = match indent.kind {
 4903                        IndentKind::Space => " ".repeat(indent.len as usize),
 4904                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4905                    };
 4906                    let point = Point::new(row.0, 0);
 4907                    indent_edits.push((point..point, text));
 4908                }
 4909            }
 4910            editor.edit(indent_edits, cx);
 4911        });
 4912    }
 4913
 4914    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4915        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4916            original_indent_columns: Vec::new(),
 4917        });
 4918        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4919    }
 4920
 4921    fn insert_with_autoindent_mode(
 4922        &mut self,
 4923        text: &str,
 4924        autoindent_mode: Option<AutoindentMode>,
 4925        window: &mut Window,
 4926        cx: &mut Context<Self>,
 4927    ) {
 4928        if self.read_only(cx) {
 4929            return;
 4930        }
 4931
 4932        let text: Arc<str> = text.into();
 4933        self.transact(window, cx, |this, window, cx| {
 4934            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 4935            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4936                let anchors = {
 4937                    let snapshot = buffer.read(cx);
 4938                    old_selections
 4939                        .iter()
 4940                        .map(|s| {
 4941                            let anchor = snapshot.anchor_after(s.head());
 4942                            s.map(|_| anchor)
 4943                        })
 4944                        .collect::<Vec<_>>()
 4945                };
 4946                buffer.edit(
 4947                    old_selections
 4948                        .iter()
 4949                        .map(|s| (s.start..s.end, text.clone())),
 4950                    autoindent_mode,
 4951                    cx,
 4952                );
 4953                anchors
 4954            });
 4955
 4956            this.change_selections(Default::default(), window, cx, |s| {
 4957                s.select_anchors(selection_anchors);
 4958            });
 4959
 4960            cx.notify();
 4961        });
 4962    }
 4963
 4964    fn trigger_completion_on_input(
 4965        &mut self,
 4966        text: &str,
 4967        trigger_in_words: bool,
 4968        window: &mut Window,
 4969        cx: &mut Context<Self>,
 4970    ) {
 4971        let completions_source = self
 4972            .context_menu
 4973            .borrow()
 4974            .as_ref()
 4975            .and_then(|menu| match menu {
 4976                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4977                CodeContextMenu::CodeActions(_) => None,
 4978            });
 4979
 4980        match completions_source {
 4981            Some(CompletionsMenuSource::Words { .. }) => {
 4982                self.open_or_update_completions_menu(
 4983                    Some(CompletionsMenuSource::Words {
 4984                        ignore_threshold: false,
 4985                    }),
 4986                    None,
 4987                    window,
 4988                    cx,
 4989                );
 4990            }
 4991            Some(CompletionsMenuSource::Normal)
 4992            | Some(CompletionsMenuSource::SnippetChoices)
 4993            | None
 4994                if self.is_completion_trigger(
 4995                    text,
 4996                    trigger_in_words,
 4997                    completions_source.is_some(),
 4998                    cx,
 4999                ) =>
 5000            {
 5001                self.show_completions(
 5002                    &ShowCompletions {
 5003                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 5004                    },
 5005                    window,
 5006                    cx,
 5007                )
 5008            }
 5009            _ => {
 5010                self.hide_context_menu(window, cx);
 5011            }
 5012        }
 5013    }
 5014
 5015    fn is_completion_trigger(
 5016        &self,
 5017        text: &str,
 5018        trigger_in_words: bool,
 5019        menu_is_open: bool,
 5020        cx: &mut Context<Self>,
 5021    ) -> bool {
 5022        let position = self.selections.newest_anchor().head();
 5023        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 5024            return false;
 5025        };
 5026
 5027        if let Some(completion_provider) = &self.completion_provider {
 5028            completion_provider.is_completion_trigger(
 5029                &buffer,
 5030                position.text_anchor,
 5031                text,
 5032                trigger_in_words,
 5033                menu_is_open,
 5034                cx,
 5035            )
 5036        } else {
 5037            false
 5038        }
 5039    }
 5040
 5041    /// If any empty selections is touching the start of its innermost containing autoclose
 5042    /// region, expand it to select the brackets.
 5043    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5044        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5045        let buffer = self.buffer.read(cx).read(cx);
 5046        let new_selections = self
 5047            .selections_with_autoclose_regions(selections, &buffer)
 5048            .map(|(mut selection, region)| {
 5049                if !selection.is_empty() {
 5050                    return selection;
 5051                }
 5052
 5053                if let Some(region) = region {
 5054                    let mut range = region.range.to_offset(&buffer);
 5055                    if selection.start == range.start && range.start >= region.pair.start.len() {
 5056                        range.start -= region.pair.start.len();
 5057                        if buffer.contains_str_at(range.start, &region.pair.start)
 5058                            && buffer.contains_str_at(range.end, &region.pair.end)
 5059                        {
 5060                            range.end += region.pair.end.len();
 5061                            selection.start = range.start;
 5062                            selection.end = range.end;
 5063
 5064                            return selection;
 5065                        }
 5066                    }
 5067                }
 5068
 5069                let always_treat_brackets_as_autoclosed = buffer
 5070                    .language_settings_at(selection.start, cx)
 5071                    .always_treat_brackets_as_autoclosed;
 5072
 5073                if !always_treat_brackets_as_autoclosed {
 5074                    return selection;
 5075                }
 5076
 5077                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5078                    for (pair, enabled) in scope.brackets() {
 5079                        if !enabled || !pair.close {
 5080                            continue;
 5081                        }
 5082
 5083                        if buffer.contains_str_at(selection.start, &pair.end) {
 5084                            let pair_start_len = pair.start.len();
 5085                            if buffer.contains_str_at(
 5086                                selection.start.saturating_sub(pair_start_len),
 5087                                &pair.start,
 5088                            ) {
 5089                                selection.start -= pair_start_len;
 5090                                selection.end += pair.end.len();
 5091
 5092                                return selection;
 5093                            }
 5094                        }
 5095                    }
 5096                }
 5097
 5098                selection
 5099            })
 5100            .collect();
 5101
 5102        drop(buffer);
 5103        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5104            selections.select(new_selections)
 5105        });
 5106    }
 5107
 5108    /// Iterate the given selections, and for each one, find the smallest surrounding
 5109    /// autoclose region. This uses the ordering of the selections and the autoclose
 5110    /// regions to avoid repeated comparisons.
 5111    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5112        &'a self,
 5113        selections: impl IntoIterator<Item = Selection<D>>,
 5114        buffer: &'a MultiBufferSnapshot,
 5115    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5116        let mut i = 0;
 5117        let mut regions = self.autoclose_regions.as_slice();
 5118        selections.into_iter().map(move |selection| {
 5119            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5120
 5121            let mut enclosing = None;
 5122            while let Some(pair_state) = regions.get(i) {
 5123                if pair_state.range.end.to_offset(buffer) < range.start {
 5124                    regions = &regions[i + 1..];
 5125                    i = 0;
 5126                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5127                    break;
 5128                } else {
 5129                    if pair_state.selection_id == selection.id {
 5130                        enclosing = Some(pair_state);
 5131                    }
 5132                    i += 1;
 5133                }
 5134            }
 5135
 5136            (selection, enclosing)
 5137        })
 5138    }
 5139
 5140    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5141    fn invalidate_autoclose_regions(
 5142        &mut self,
 5143        mut selections: &[Selection<Anchor>],
 5144        buffer: &MultiBufferSnapshot,
 5145    ) {
 5146        self.autoclose_regions.retain(|state| {
 5147            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5148                return false;
 5149            }
 5150
 5151            let mut i = 0;
 5152            while let Some(selection) = selections.get(i) {
 5153                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5154                    selections = &selections[1..];
 5155                    continue;
 5156                }
 5157                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5158                    break;
 5159                }
 5160                if selection.id == state.selection_id {
 5161                    return true;
 5162                } else {
 5163                    i += 1;
 5164                }
 5165            }
 5166            false
 5167        });
 5168    }
 5169
 5170    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5171        let offset = position.to_offset(buffer);
 5172        let (word_range, kind) =
 5173            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5174        if offset > word_range.start && kind == Some(CharKind::Word) {
 5175            Some(
 5176                buffer
 5177                    .text_for_range(word_range.start..offset)
 5178                    .collect::<String>(),
 5179            )
 5180        } else {
 5181            None
 5182        }
 5183    }
 5184
 5185    pub fn visible_excerpts(
 5186        &self,
 5187        cx: &mut Context<Editor>,
 5188    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5189        let Some(project) = self.project() else {
 5190            return HashMap::default();
 5191        };
 5192        let project = project.read(cx);
 5193        let multi_buffer = self.buffer().read(cx);
 5194        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5195        let multi_buffer_visible_start = self
 5196            .scroll_manager
 5197            .anchor()
 5198            .anchor
 5199            .to_point(&multi_buffer_snapshot);
 5200        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5201            multi_buffer_visible_start
 5202                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5203            Bias::Left,
 5204        );
 5205        multi_buffer_snapshot
 5206            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5207            .into_iter()
 5208            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5209            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5210                let buffer_file = project::File::from_dyn(buffer.file())?;
 5211                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5212                let worktree_entry = buffer_worktree
 5213                    .read(cx)
 5214                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5215                if worktree_entry.is_ignored {
 5216                    None
 5217                } else {
 5218                    Some((
 5219                        excerpt_id,
 5220                        (
 5221                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5222                            buffer.version().clone(),
 5223                            excerpt_visible_range,
 5224                        ),
 5225                    ))
 5226                }
 5227            })
 5228            .collect()
 5229    }
 5230
 5231    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5232        TextLayoutDetails {
 5233            text_system: window.text_system().clone(),
 5234            editor_style: self.style.clone().unwrap(),
 5235            rem_size: window.rem_size(),
 5236            scroll_anchor: self.scroll_manager.anchor(),
 5237            visible_rows: self.visible_line_count(),
 5238            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5239        }
 5240    }
 5241
 5242    fn trigger_on_type_formatting(
 5243        &self,
 5244        input: String,
 5245        window: &mut Window,
 5246        cx: &mut Context<Self>,
 5247    ) -> Option<Task<Result<()>>> {
 5248        if input.len() != 1 {
 5249            return None;
 5250        }
 5251
 5252        let project = self.project()?;
 5253        let position = self.selections.newest_anchor().head();
 5254        let (buffer, buffer_position) = self
 5255            .buffer
 5256            .read(cx)
 5257            .text_anchor_for_position(position, cx)?;
 5258
 5259        let settings = language_settings::language_settings(
 5260            buffer
 5261                .read(cx)
 5262                .language_at(buffer_position)
 5263                .map(|l| l.name()),
 5264            buffer.read(cx).file(),
 5265            cx,
 5266        );
 5267        if !settings.use_on_type_format {
 5268            return None;
 5269        }
 5270
 5271        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5272        // hence we do LSP request & edit on host side only — add formats to host's history.
 5273        let push_to_lsp_host_history = true;
 5274        // If this is not the host, append its history with new edits.
 5275        let push_to_client_history = project.read(cx).is_via_collab();
 5276
 5277        let on_type_formatting = project.update(cx, |project, cx| {
 5278            project.on_type_format(
 5279                buffer.clone(),
 5280                buffer_position,
 5281                input,
 5282                push_to_lsp_host_history,
 5283                cx,
 5284            )
 5285        });
 5286        Some(cx.spawn_in(window, async move |editor, cx| {
 5287            if let Some(transaction) = on_type_formatting.await? {
 5288                if push_to_client_history {
 5289                    buffer
 5290                        .update(cx, |buffer, _| {
 5291                            buffer.push_transaction(transaction, Instant::now());
 5292                            buffer.finalize_last_transaction();
 5293                        })
 5294                        .ok();
 5295                }
 5296                editor.update(cx, |editor, cx| {
 5297                    editor.refresh_document_highlights(cx);
 5298                })?;
 5299            }
 5300            Ok(())
 5301        }))
 5302    }
 5303
 5304    pub fn show_word_completions(
 5305        &mut self,
 5306        _: &ShowWordCompletions,
 5307        window: &mut Window,
 5308        cx: &mut Context<Self>,
 5309    ) {
 5310        self.open_or_update_completions_menu(
 5311            Some(CompletionsMenuSource::Words {
 5312                ignore_threshold: true,
 5313            }),
 5314            None,
 5315            window,
 5316            cx,
 5317        );
 5318    }
 5319
 5320    pub fn show_completions(
 5321        &mut self,
 5322        options: &ShowCompletions,
 5323        window: &mut Window,
 5324        cx: &mut Context<Self>,
 5325    ) {
 5326        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5327    }
 5328
 5329    fn open_or_update_completions_menu(
 5330        &mut self,
 5331        requested_source: Option<CompletionsMenuSource>,
 5332        trigger: Option<&str>,
 5333        window: &mut Window,
 5334        cx: &mut Context<Self>,
 5335    ) {
 5336        if self.pending_rename.is_some() {
 5337            return;
 5338        }
 5339
 5340        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5341
 5342        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5343        // inserted and selected. To handle that case, the start of the selection is used so that
 5344        // the menu starts with all choices.
 5345        let position = self
 5346            .selections
 5347            .newest_anchor()
 5348            .start
 5349            .bias_right(&multibuffer_snapshot);
 5350        if position.diff_base_anchor.is_some() {
 5351            return;
 5352        }
 5353        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5354        let Some(buffer) = buffer_position
 5355            .buffer_id
 5356            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5357        else {
 5358            return;
 5359        };
 5360        let buffer_snapshot = buffer.read(cx).snapshot();
 5361
 5362        let query: Option<Arc<String>> =
 5363            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5364                .map(|query| query.into());
 5365
 5366        drop(multibuffer_snapshot);
 5367
 5368        // Hide the current completions menu when query is empty. Without this, cached
 5369        // completions from before the trigger char may be reused (#32774).
 5370        if query.is_none() {
 5371            let menu_is_open = matches!(
 5372                self.context_menu.borrow().as_ref(),
 5373                Some(CodeContextMenu::Completions(_))
 5374            );
 5375            if menu_is_open {
 5376                self.hide_context_menu(window, cx);
 5377            }
 5378        }
 5379
 5380        let mut ignore_word_threshold = false;
 5381        let provider = match requested_source {
 5382            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5383            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5384                ignore_word_threshold = ignore_threshold;
 5385                None
 5386            }
 5387            Some(CompletionsMenuSource::SnippetChoices) => {
 5388                log::error!("bug: SnippetChoices requested_source is not handled");
 5389                None
 5390            }
 5391        };
 5392
 5393        let sort_completions = provider
 5394            .as_ref()
 5395            .is_some_and(|provider| provider.sort_completions());
 5396
 5397        let filter_completions = provider
 5398            .as_ref()
 5399            .is_none_or(|provider| provider.filter_completions());
 5400
 5401        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5402            if filter_completions {
 5403                menu.filter(query.clone(), provider.clone(), window, cx);
 5404            }
 5405            // When `is_incomplete` is false, no need to re-query completions when the current query
 5406            // is a suffix of the initial query.
 5407            if !menu.is_incomplete {
 5408                // If the new query is a suffix of the old query (typing more characters) and
 5409                // the previous result was complete, the existing completions can be filtered.
 5410                //
 5411                // Note that this is always true for snippet completions.
 5412                let query_matches = match (&menu.initial_query, &query) {
 5413                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5414                    (None, _) => true,
 5415                    _ => false,
 5416                };
 5417                if query_matches {
 5418                    let position_matches = if menu.initial_position == position {
 5419                        true
 5420                    } else {
 5421                        let snapshot = self.buffer.read(cx).read(cx);
 5422                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5423                    };
 5424                    if position_matches {
 5425                        return;
 5426                    }
 5427                }
 5428            }
 5429        };
 5430
 5431        let trigger_kind = match trigger {
 5432            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5433                CompletionTriggerKind::TRIGGER_CHARACTER
 5434            }
 5435            _ => CompletionTriggerKind::INVOKED,
 5436        };
 5437        let completion_context = CompletionContext {
 5438            trigger_character: trigger.and_then(|trigger| {
 5439                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5440                    Some(String::from(trigger))
 5441                } else {
 5442                    None
 5443                }
 5444            }),
 5445            trigger_kind,
 5446        };
 5447
 5448        let Anchor {
 5449            excerpt_id: buffer_excerpt_id,
 5450            text_anchor: buffer_position,
 5451            ..
 5452        } = buffer_position;
 5453
 5454        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5455            buffer_snapshot.surrounding_word(buffer_position, None)
 5456        {
 5457            let word_to_exclude = buffer_snapshot
 5458                .text_for_range(word_range.clone())
 5459                .collect::<String>();
 5460            (
 5461                buffer_snapshot.anchor_before(word_range.start)
 5462                    ..buffer_snapshot.anchor_after(buffer_position),
 5463                Some(word_to_exclude),
 5464            )
 5465        } else {
 5466            (buffer_position..buffer_position, None)
 5467        };
 5468
 5469        let language = buffer_snapshot
 5470            .language_at(buffer_position)
 5471            .map(|language| language.name());
 5472
 5473        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5474            .completions
 5475            .clone();
 5476
 5477        let show_completion_documentation = buffer_snapshot
 5478            .settings_at(buffer_position, cx)
 5479            .show_completion_documentation;
 5480
 5481        // The document can be large, so stay in reasonable bounds when searching for words,
 5482        // otherwise completion pop-up might be slow to appear.
 5483        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5484        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5485        let min_word_search = buffer_snapshot.clip_point(
 5486            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5487            Bias::Left,
 5488        );
 5489        let max_word_search = buffer_snapshot.clip_point(
 5490            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5491            Bias::Right,
 5492        );
 5493        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5494            ..buffer_snapshot.point_to_offset(max_word_search);
 5495
 5496        let skip_digits = query
 5497            .as_ref()
 5498            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5499
 5500        let omit_word_completions = !self.word_completions_enabled
 5501            || (!ignore_word_threshold
 5502                && match &query {
 5503                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5504                    None => completion_settings.words_min_length != 0,
 5505                });
 5506
 5507        let (mut words, provider_responses) = match &provider {
 5508            Some(provider) => {
 5509                let provider_responses = provider.completions(
 5510                    buffer_excerpt_id,
 5511                    &buffer,
 5512                    buffer_position,
 5513                    completion_context,
 5514                    window,
 5515                    cx,
 5516                );
 5517
 5518                let words = match (omit_word_completions, completion_settings.words) {
 5519                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5520                        Task::ready(BTreeMap::default())
 5521                    }
 5522                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5523                        .background_spawn(async move {
 5524                            buffer_snapshot.words_in_range(WordsQuery {
 5525                                fuzzy_contents: None,
 5526                                range: word_search_range,
 5527                                skip_digits,
 5528                            })
 5529                        }),
 5530                };
 5531
 5532                (words, provider_responses)
 5533            }
 5534            None => {
 5535                let words = if omit_word_completions {
 5536                    Task::ready(BTreeMap::default())
 5537                } else {
 5538                    cx.background_spawn(async move {
 5539                        buffer_snapshot.words_in_range(WordsQuery {
 5540                            fuzzy_contents: None,
 5541                            range: word_search_range,
 5542                            skip_digits,
 5543                        })
 5544                    })
 5545                };
 5546                (words, Task::ready(Ok(Vec::new())))
 5547            }
 5548        };
 5549
 5550        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5551
 5552        let id = post_inc(&mut self.next_completion_id);
 5553        let task = cx.spawn_in(window, async move |editor, cx| {
 5554            let Ok(()) = editor.update(cx, |this, _| {
 5555                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5556            }) else {
 5557                return;
 5558            };
 5559
 5560            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5561            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5562            let mut completions = Vec::new();
 5563            let mut is_incomplete = false;
 5564            let mut display_options: Option<CompletionDisplayOptions> = None;
 5565            if let Some(provider_responses) = provider_responses.await.log_err()
 5566                && !provider_responses.is_empty()
 5567            {
 5568                for response in provider_responses {
 5569                    completions.extend(response.completions);
 5570                    is_incomplete = is_incomplete || response.is_incomplete;
 5571                    match display_options.as_mut() {
 5572                        None => {
 5573                            display_options = Some(response.display_options);
 5574                        }
 5575                        Some(options) => options.merge(&response.display_options),
 5576                    }
 5577                }
 5578                if completion_settings.words == WordsCompletionMode::Fallback {
 5579                    words = Task::ready(BTreeMap::default());
 5580                }
 5581            }
 5582            let display_options = display_options.unwrap_or_default();
 5583
 5584            let mut words = words.await;
 5585            if let Some(word_to_exclude) = &word_to_exclude {
 5586                words.remove(word_to_exclude);
 5587            }
 5588            for lsp_completion in &completions {
 5589                words.remove(&lsp_completion.new_text);
 5590            }
 5591            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5592                replace_range: word_replace_range.clone(),
 5593                new_text: word.clone(),
 5594                label: CodeLabel::plain(word, None),
 5595                icon_path: None,
 5596                documentation: None,
 5597                source: CompletionSource::BufferWord {
 5598                    word_range,
 5599                    resolved: false,
 5600                },
 5601                insert_text_mode: Some(InsertTextMode::AS_IS),
 5602                confirm: None,
 5603            }));
 5604
 5605            let menu = if completions.is_empty() {
 5606                None
 5607            } else {
 5608                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5609                    let languages = editor
 5610                        .workspace
 5611                        .as_ref()
 5612                        .and_then(|(workspace, _)| workspace.upgrade())
 5613                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5614                    let menu = CompletionsMenu::new(
 5615                        id,
 5616                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5617                        sort_completions,
 5618                        show_completion_documentation,
 5619                        position,
 5620                        query.clone(),
 5621                        is_incomplete,
 5622                        buffer.clone(),
 5623                        completions.into(),
 5624                        display_options,
 5625                        snippet_sort_order,
 5626                        languages,
 5627                        language,
 5628                        cx,
 5629                    );
 5630
 5631                    let query = if filter_completions { query } else { None };
 5632                    let matches_task = if let Some(query) = query {
 5633                        menu.do_async_filtering(query, cx)
 5634                    } else {
 5635                        Task::ready(menu.unfiltered_matches())
 5636                    };
 5637                    (menu, matches_task)
 5638                }) else {
 5639                    return;
 5640                };
 5641
 5642                let matches = matches_task.await;
 5643
 5644                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5645                    // Newer menu already set, so exit.
 5646                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5647                        editor.context_menu.borrow().as_ref()
 5648                        && prev_menu.id > id
 5649                    {
 5650                        return;
 5651                    };
 5652
 5653                    // Only valid to take prev_menu because it the new menu is immediately set
 5654                    // below, or the menu is hidden.
 5655                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5656                        editor.context_menu.borrow_mut().take()
 5657                    {
 5658                        let position_matches =
 5659                            if prev_menu.initial_position == menu.initial_position {
 5660                                true
 5661                            } else {
 5662                                let snapshot = editor.buffer.read(cx).read(cx);
 5663                                prev_menu.initial_position.to_offset(&snapshot)
 5664                                    == menu.initial_position.to_offset(&snapshot)
 5665                            };
 5666                        if position_matches {
 5667                            // Preserve markdown cache before `set_filter_results` because it will
 5668                            // try to populate the documentation cache.
 5669                            menu.preserve_markdown_cache(prev_menu);
 5670                        }
 5671                    };
 5672
 5673                    menu.set_filter_results(matches, provider, window, cx);
 5674                }) else {
 5675                    return;
 5676                };
 5677
 5678                menu.visible().then_some(menu)
 5679            };
 5680
 5681            editor
 5682                .update_in(cx, |editor, window, cx| {
 5683                    if editor.focus_handle.is_focused(window)
 5684                        && let Some(menu) = menu
 5685                    {
 5686                        *editor.context_menu.borrow_mut() =
 5687                            Some(CodeContextMenu::Completions(menu));
 5688
 5689                        crate::hover_popover::hide_hover(editor, cx);
 5690                        if editor.show_edit_predictions_in_menu() {
 5691                            editor.update_visible_edit_prediction(window, cx);
 5692                        } else {
 5693                            editor.discard_edit_prediction(false, cx);
 5694                        }
 5695
 5696                        cx.notify();
 5697                        return;
 5698                    }
 5699
 5700                    if editor.completion_tasks.len() <= 1 {
 5701                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5702                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5703                        // If it was already hidden and we don't show edit predictions in the menu,
 5704                        // we should also show the edit prediction when available.
 5705                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5706                            editor.update_visible_edit_prediction(window, cx);
 5707                        }
 5708                    }
 5709                })
 5710                .ok();
 5711        });
 5712
 5713        self.completion_tasks.push((id, task));
 5714    }
 5715
 5716    #[cfg(feature = "test-support")]
 5717    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5718        let menu = self.context_menu.borrow();
 5719        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5720            let completions = menu.completions.borrow();
 5721            Some(completions.to_vec())
 5722        } else {
 5723            None
 5724        }
 5725    }
 5726
 5727    pub fn with_completions_menu_matching_id<R>(
 5728        &self,
 5729        id: CompletionId,
 5730        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5731    ) -> R {
 5732        let mut context_menu = self.context_menu.borrow_mut();
 5733        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5734            return f(None);
 5735        };
 5736        if completions_menu.id != id {
 5737            return f(None);
 5738        }
 5739        f(Some(completions_menu))
 5740    }
 5741
 5742    pub fn confirm_completion(
 5743        &mut self,
 5744        action: &ConfirmCompletion,
 5745        window: &mut Window,
 5746        cx: &mut Context<Self>,
 5747    ) -> Option<Task<Result<()>>> {
 5748        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5749        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5750    }
 5751
 5752    pub fn confirm_completion_insert(
 5753        &mut self,
 5754        _: &ConfirmCompletionInsert,
 5755        window: &mut Window,
 5756        cx: &mut Context<Self>,
 5757    ) -> Option<Task<Result<()>>> {
 5758        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5759        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5760    }
 5761
 5762    pub fn confirm_completion_replace(
 5763        &mut self,
 5764        _: &ConfirmCompletionReplace,
 5765        window: &mut Window,
 5766        cx: &mut Context<Self>,
 5767    ) -> Option<Task<Result<()>>> {
 5768        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5769        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5770    }
 5771
 5772    pub fn compose_completion(
 5773        &mut self,
 5774        action: &ComposeCompletion,
 5775        window: &mut Window,
 5776        cx: &mut Context<Self>,
 5777    ) -> Option<Task<Result<()>>> {
 5778        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5779        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5780    }
 5781
 5782    fn do_completion(
 5783        &mut self,
 5784        item_ix: Option<usize>,
 5785        intent: CompletionIntent,
 5786        window: &mut Window,
 5787        cx: &mut Context<Editor>,
 5788    ) -> Option<Task<Result<()>>> {
 5789        use language::ToOffset as _;
 5790
 5791        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5792        else {
 5793            return None;
 5794        };
 5795
 5796        let candidate_id = {
 5797            let entries = completions_menu.entries.borrow();
 5798            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5799            if self.show_edit_predictions_in_menu() {
 5800                self.discard_edit_prediction(true, cx);
 5801            }
 5802            mat.candidate_id
 5803        };
 5804
 5805        let completion = completions_menu
 5806            .completions
 5807            .borrow()
 5808            .get(candidate_id)?
 5809            .clone();
 5810        cx.stop_propagation();
 5811
 5812        let buffer_handle = completions_menu.buffer.clone();
 5813
 5814        let CompletionEdit {
 5815            new_text,
 5816            snippet,
 5817            replace_range,
 5818        } = process_completion_for_edit(
 5819            &completion,
 5820            intent,
 5821            &buffer_handle,
 5822            &completions_menu.initial_position.text_anchor,
 5823            cx,
 5824        );
 5825
 5826        let buffer = buffer_handle.read(cx);
 5827        let snapshot = self.buffer.read(cx).snapshot(cx);
 5828        let newest_anchor = self.selections.newest_anchor();
 5829        let replace_range_multibuffer = {
 5830            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5831            excerpt.map_range_from_buffer(replace_range.clone())
 5832        };
 5833        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5834            return None;
 5835        }
 5836
 5837        let old_text = buffer
 5838            .text_for_range(replace_range.clone())
 5839            .collect::<String>();
 5840        let lookbehind = newest_anchor
 5841            .start
 5842            .text_anchor
 5843            .to_offset(buffer)
 5844            .saturating_sub(replace_range.start);
 5845        let lookahead = replace_range
 5846            .end
 5847            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5848        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5849        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5850
 5851        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5852        let mut ranges = Vec::new();
 5853        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5854
 5855        for selection in &selections {
 5856            let range = if selection.id == newest_anchor.id {
 5857                replace_range_multibuffer.clone()
 5858            } else {
 5859                let mut range = selection.range();
 5860
 5861                // if prefix is present, don't duplicate it
 5862                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5863                    range.start = range.start.saturating_sub(lookbehind);
 5864
 5865                    // if suffix is also present, mimic the newest cursor and replace it
 5866                    if selection.id != newest_anchor.id
 5867                        && snapshot.contains_str_at(range.end, suffix)
 5868                    {
 5869                        range.end += lookahead;
 5870                    }
 5871                }
 5872                range
 5873            };
 5874
 5875            ranges.push(range.clone());
 5876
 5877            if !self.linked_edit_ranges.is_empty() {
 5878                let start_anchor = snapshot.anchor_before(range.start);
 5879                let end_anchor = snapshot.anchor_after(range.end);
 5880                if let Some(ranges) = self
 5881                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5882                {
 5883                    for (buffer, edits) in ranges {
 5884                        linked_edits
 5885                            .entry(buffer.clone())
 5886                            .or_default()
 5887                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5888                    }
 5889                }
 5890            }
 5891        }
 5892
 5893        let common_prefix_len = old_text
 5894            .chars()
 5895            .zip(new_text.chars())
 5896            .take_while(|(a, b)| a == b)
 5897            .map(|(a, _)| a.len_utf8())
 5898            .sum::<usize>();
 5899
 5900        cx.emit(EditorEvent::InputHandled {
 5901            utf16_range_to_replace: None,
 5902            text: new_text[common_prefix_len..].into(),
 5903        });
 5904
 5905        self.transact(window, cx, |editor, window, cx| {
 5906            if let Some(mut snippet) = snippet {
 5907                snippet.text = new_text.to_string();
 5908                editor
 5909                    .insert_snippet(&ranges, snippet, window, cx)
 5910                    .log_err();
 5911            } else {
 5912                editor.buffer.update(cx, |multi_buffer, cx| {
 5913                    let auto_indent = match completion.insert_text_mode {
 5914                        Some(InsertTextMode::AS_IS) => None,
 5915                        _ => editor.autoindent_mode.clone(),
 5916                    };
 5917                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5918                    multi_buffer.edit(edits, auto_indent, cx);
 5919                });
 5920            }
 5921            for (buffer, edits) in linked_edits {
 5922                buffer.update(cx, |buffer, cx| {
 5923                    let snapshot = buffer.snapshot();
 5924                    let edits = edits
 5925                        .into_iter()
 5926                        .map(|(range, text)| {
 5927                            use text::ToPoint as TP;
 5928                            let end_point = TP::to_point(&range.end, &snapshot);
 5929                            let start_point = TP::to_point(&range.start, &snapshot);
 5930                            (start_point..end_point, text)
 5931                        })
 5932                        .sorted_by_key(|(range, _)| range.start);
 5933                    buffer.edit(edits, None, cx);
 5934                })
 5935            }
 5936
 5937            editor.refresh_edit_prediction(true, false, window, cx);
 5938        });
 5939        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 5940
 5941        let show_new_completions_on_confirm = completion
 5942            .confirm
 5943            .as_ref()
 5944            .is_some_and(|confirm| confirm(intent, window, cx));
 5945        if show_new_completions_on_confirm {
 5946            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5947        }
 5948
 5949        let provider = self.completion_provider.as_ref()?;
 5950        drop(completion);
 5951        let apply_edits = provider.apply_additional_edits_for_completion(
 5952            buffer_handle,
 5953            completions_menu.completions.clone(),
 5954            candidate_id,
 5955            true,
 5956            cx,
 5957        );
 5958
 5959        let editor_settings = EditorSettings::get_global(cx);
 5960        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5961            // After the code completion is finished, users often want to know what signatures are needed.
 5962            // so we should automatically call signature_help
 5963            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5964        }
 5965
 5966        Some(cx.foreground_executor().spawn(async move {
 5967            apply_edits.await?;
 5968            Ok(())
 5969        }))
 5970    }
 5971
 5972    pub fn toggle_code_actions(
 5973        &mut self,
 5974        action: &ToggleCodeActions,
 5975        window: &mut Window,
 5976        cx: &mut Context<Self>,
 5977    ) {
 5978        let quick_launch = action.quick_launch;
 5979        let mut context_menu = self.context_menu.borrow_mut();
 5980        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5981            if code_actions.deployed_from == action.deployed_from {
 5982                // Toggle if we're selecting the same one
 5983                *context_menu = None;
 5984                cx.notify();
 5985                return;
 5986            } else {
 5987                // Otherwise, clear it and start a new one
 5988                *context_menu = None;
 5989                cx.notify();
 5990            }
 5991        }
 5992        drop(context_menu);
 5993        let snapshot = self.snapshot(window, cx);
 5994        let deployed_from = action.deployed_from.clone();
 5995        let action = action.clone();
 5996        self.completion_tasks.clear();
 5997        self.discard_edit_prediction(false, cx);
 5998
 5999        let multibuffer_point = match &action.deployed_from {
 6000            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6001                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6002            }
 6003            _ => self
 6004                .selections
 6005                .newest::<Point>(&snapshot.display_snapshot)
 6006                .head(),
 6007        };
 6008        let Some((buffer, buffer_row)) = snapshot
 6009            .buffer_snapshot()
 6010            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6011            .and_then(|(buffer_snapshot, range)| {
 6012                self.buffer()
 6013                    .read(cx)
 6014                    .buffer(buffer_snapshot.remote_id())
 6015                    .map(|buffer| (buffer, range.start.row))
 6016            })
 6017        else {
 6018            return;
 6019        };
 6020        let buffer_id = buffer.read(cx).remote_id();
 6021        let tasks = self
 6022            .tasks
 6023            .get(&(buffer_id, buffer_row))
 6024            .map(|t| Arc::new(t.to_owned()));
 6025
 6026        if !self.focus_handle.is_focused(window) {
 6027            return;
 6028        }
 6029        let project = self.project.clone();
 6030
 6031        let code_actions_task = match deployed_from {
 6032            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6033            _ => self.code_actions(buffer_row, window, cx),
 6034        };
 6035
 6036        let runnable_task = match deployed_from {
 6037            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6038            _ => {
 6039                let mut task_context_task = Task::ready(None);
 6040                if let Some(tasks) = &tasks
 6041                    && let Some(project) = project
 6042                {
 6043                    task_context_task =
 6044                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6045                }
 6046
 6047                cx.spawn_in(window, {
 6048                    let buffer = buffer.clone();
 6049                    async move |editor, cx| {
 6050                        let task_context = task_context_task.await;
 6051
 6052                        let resolved_tasks =
 6053                            tasks
 6054                                .zip(task_context.clone())
 6055                                .map(|(tasks, task_context)| ResolvedTasks {
 6056                                    templates: tasks.resolve(&task_context).collect(),
 6057                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6058                                        multibuffer_point.row,
 6059                                        tasks.column,
 6060                                    )),
 6061                                });
 6062                        let debug_scenarios = editor
 6063                            .update(cx, |editor, cx| {
 6064                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6065                            })?
 6066                            .await;
 6067                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6068                    }
 6069                })
 6070            }
 6071        };
 6072
 6073        cx.spawn_in(window, async move |editor, cx| {
 6074            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6075            let code_actions = code_actions_task.await;
 6076            let spawn_straight_away = quick_launch
 6077                && resolved_tasks
 6078                    .as_ref()
 6079                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6080                && code_actions
 6081                    .as_ref()
 6082                    .is_none_or(|actions| actions.is_empty())
 6083                && debug_scenarios.is_empty();
 6084
 6085            editor.update_in(cx, |editor, window, cx| {
 6086                crate::hover_popover::hide_hover(editor, cx);
 6087                let actions = CodeActionContents::new(
 6088                    resolved_tasks,
 6089                    code_actions,
 6090                    debug_scenarios,
 6091                    task_context.unwrap_or_default(),
 6092                );
 6093
 6094                // Don't show the menu if there are no actions available
 6095                if actions.is_empty() {
 6096                    cx.notify();
 6097                    return Task::ready(Ok(()));
 6098                }
 6099
 6100                *editor.context_menu.borrow_mut() =
 6101                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6102                        buffer,
 6103                        actions,
 6104                        selected_item: Default::default(),
 6105                        scroll_handle: UniformListScrollHandle::default(),
 6106                        deployed_from,
 6107                    }));
 6108                cx.notify();
 6109                if spawn_straight_away
 6110                    && let Some(task) = editor.confirm_code_action(
 6111                        &ConfirmCodeAction { item_ix: Some(0) },
 6112                        window,
 6113                        cx,
 6114                    )
 6115                {
 6116                    return task;
 6117                }
 6118
 6119                Task::ready(Ok(()))
 6120            })
 6121        })
 6122        .detach_and_log_err(cx);
 6123    }
 6124
 6125    fn debug_scenarios(
 6126        &mut self,
 6127        resolved_tasks: &Option<ResolvedTasks>,
 6128        buffer: &Entity<Buffer>,
 6129        cx: &mut App,
 6130    ) -> Task<Vec<task::DebugScenario>> {
 6131        maybe!({
 6132            let project = self.project()?;
 6133            let dap_store = project.read(cx).dap_store();
 6134            let mut scenarios = vec![];
 6135            let resolved_tasks = resolved_tasks.as_ref()?;
 6136            let buffer = buffer.read(cx);
 6137            let language = buffer.language()?;
 6138            let file = buffer.file();
 6139            let debug_adapter = language_settings(language.name().into(), file, cx)
 6140                .debuggers
 6141                .first()
 6142                .map(SharedString::from)
 6143                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6144
 6145            dap_store.update(cx, |dap_store, cx| {
 6146                for (_, task) in &resolved_tasks.templates {
 6147                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6148                        task.original_task().clone(),
 6149                        debug_adapter.clone().into(),
 6150                        task.display_label().to_owned().into(),
 6151                        cx,
 6152                    );
 6153                    scenarios.push(maybe_scenario);
 6154                }
 6155            });
 6156            Some(cx.background_spawn(async move {
 6157                futures::future::join_all(scenarios)
 6158                    .await
 6159                    .into_iter()
 6160                    .flatten()
 6161                    .collect::<Vec<_>>()
 6162            }))
 6163        })
 6164        .unwrap_or_else(|| Task::ready(vec![]))
 6165    }
 6166
 6167    fn code_actions(
 6168        &mut self,
 6169        buffer_row: u32,
 6170        window: &mut Window,
 6171        cx: &mut Context<Self>,
 6172    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6173        let mut task = self.code_actions_task.take();
 6174        cx.spawn_in(window, async move |editor, cx| {
 6175            while let Some(prev_task) = task {
 6176                prev_task.await.log_err();
 6177                task = editor
 6178                    .update(cx, |this, _| this.code_actions_task.take())
 6179                    .ok()?;
 6180            }
 6181
 6182            editor
 6183                .update(cx, |editor, cx| {
 6184                    editor
 6185                        .available_code_actions
 6186                        .clone()
 6187                        .and_then(|(location, code_actions)| {
 6188                            let snapshot = location.buffer.read(cx).snapshot();
 6189                            let point_range = location.range.to_point(&snapshot);
 6190                            let point_range = point_range.start.row..=point_range.end.row;
 6191                            if point_range.contains(&buffer_row) {
 6192                                Some(code_actions)
 6193                            } else {
 6194                                None
 6195                            }
 6196                        })
 6197                })
 6198                .ok()
 6199                .flatten()
 6200        })
 6201    }
 6202
 6203    pub fn confirm_code_action(
 6204        &mut self,
 6205        action: &ConfirmCodeAction,
 6206        window: &mut Window,
 6207        cx: &mut Context<Self>,
 6208    ) -> Option<Task<Result<()>>> {
 6209        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6210
 6211        let actions_menu =
 6212            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6213                menu
 6214            } else {
 6215                return None;
 6216            };
 6217
 6218        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6219        let action = actions_menu.actions.get(action_ix)?;
 6220        let title = action.label();
 6221        let buffer = actions_menu.buffer;
 6222        let workspace = self.workspace()?;
 6223
 6224        match action {
 6225            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6226                workspace.update(cx, |workspace, cx| {
 6227                    workspace.schedule_resolved_task(
 6228                        task_source_kind,
 6229                        resolved_task,
 6230                        false,
 6231                        window,
 6232                        cx,
 6233                    );
 6234
 6235                    Some(Task::ready(Ok(())))
 6236                })
 6237            }
 6238            CodeActionsItem::CodeAction {
 6239                excerpt_id,
 6240                action,
 6241                provider,
 6242            } => {
 6243                let apply_code_action =
 6244                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6245                let workspace = workspace.downgrade();
 6246                Some(cx.spawn_in(window, async move |editor, cx| {
 6247                    let project_transaction = apply_code_action.await?;
 6248                    Self::open_project_transaction(
 6249                        &editor,
 6250                        workspace,
 6251                        project_transaction,
 6252                        title,
 6253                        cx,
 6254                    )
 6255                    .await
 6256                }))
 6257            }
 6258            CodeActionsItem::DebugScenario(scenario) => {
 6259                let context = actions_menu.actions.context;
 6260
 6261                workspace.update(cx, |workspace, cx| {
 6262                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6263                    workspace.start_debug_session(
 6264                        scenario,
 6265                        context,
 6266                        Some(buffer),
 6267                        None,
 6268                        window,
 6269                        cx,
 6270                    );
 6271                });
 6272                Some(Task::ready(Ok(())))
 6273            }
 6274        }
 6275    }
 6276
 6277    pub async fn open_project_transaction(
 6278        editor: &WeakEntity<Editor>,
 6279        workspace: WeakEntity<Workspace>,
 6280        transaction: ProjectTransaction,
 6281        title: String,
 6282        cx: &mut AsyncWindowContext,
 6283    ) -> Result<()> {
 6284        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6285        cx.update(|_, cx| {
 6286            entries.sort_unstable_by_key(|(buffer, _)| {
 6287                buffer.read(cx).file().map(|f| f.path().clone())
 6288            });
 6289        })?;
 6290        if entries.is_empty() {
 6291            return Ok(());
 6292        }
 6293
 6294        // If the project transaction's edits are all contained within this editor, then
 6295        // avoid opening a new editor to display them.
 6296
 6297        if let [(buffer, transaction)] = &*entries {
 6298            let excerpt = editor.update(cx, |editor, cx| {
 6299                editor
 6300                    .buffer()
 6301                    .read(cx)
 6302                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6303            })?;
 6304            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6305                && excerpted_buffer == *buffer
 6306            {
 6307                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6308                    let excerpt_range = excerpt_range.to_offset(buffer);
 6309                    buffer
 6310                        .edited_ranges_for_transaction::<usize>(transaction)
 6311                        .all(|range| {
 6312                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6313                        })
 6314                })?;
 6315
 6316                if all_edits_within_excerpt {
 6317                    return Ok(());
 6318                }
 6319            }
 6320        }
 6321
 6322        let mut ranges_to_highlight = Vec::new();
 6323        let excerpt_buffer = cx.new(|cx| {
 6324            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6325            for (buffer_handle, transaction) in &entries {
 6326                let edited_ranges = buffer_handle
 6327                    .read(cx)
 6328                    .edited_ranges_for_transaction::<Point>(transaction)
 6329                    .collect::<Vec<_>>();
 6330                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6331                    PathKey::for_buffer(buffer_handle, cx),
 6332                    buffer_handle.clone(),
 6333                    edited_ranges,
 6334                    multibuffer_context_lines(cx),
 6335                    cx,
 6336                );
 6337
 6338                ranges_to_highlight.extend(ranges);
 6339            }
 6340            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6341            multibuffer
 6342        })?;
 6343
 6344        workspace.update_in(cx, |workspace, window, cx| {
 6345            let project = workspace.project().clone();
 6346            let editor =
 6347                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6348            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6349            editor.update(cx, |editor, cx| {
 6350                editor.highlight_background::<Self>(
 6351                    &ranges_to_highlight,
 6352                    |theme| theme.colors().editor_highlighted_line_background,
 6353                    cx,
 6354                );
 6355            });
 6356        })?;
 6357
 6358        Ok(())
 6359    }
 6360
 6361    pub fn clear_code_action_providers(&mut self) {
 6362        self.code_action_providers.clear();
 6363        self.available_code_actions.take();
 6364    }
 6365
 6366    pub fn add_code_action_provider(
 6367        &mut self,
 6368        provider: Rc<dyn CodeActionProvider>,
 6369        window: &mut Window,
 6370        cx: &mut Context<Self>,
 6371    ) {
 6372        if self
 6373            .code_action_providers
 6374            .iter()
 6375            .any(|existing_provider| existing_provider.id() == provider.id())
 6376        {
 6377            return;
 6378        }
 6379
 6380        self.code_action_providers.push(provider);
 6381        self.refresh_code_actions(window, cx);
 6382    }
 6383
 6384    pub fn remove_code_action_provider(
 6385        &mut self,
 6386        id: Arc<str>,
 6387        window: &mut Window,
 6388        cx: &mut Context<Self>,
 6389    ) {
 6390        self.code_action_providers
 6391            .retain(|provider| provider.id() != id);
 6392        self.refresh_code_actions(window, cx);
 6393    }
 6394
 6395    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6396        !self.code_action_providers.is_empty()
 6397            && EditorSettings::get_global(cx).toolbar.code_actions
 6398    }
 6399
 6400    pub fn has_available_code_actions(&self) -> bool {
 6401        self.available_code_actions
 6402            .as_ref()
 6403            .is_some_and(|(_, actions)| !actions.is_empty())
 6404    }
 6405
 6406    fn render_inline_code_actions(
 6407        &self,
 6408        icon_size: ui::IconSize,
 6409        display_row: DisplayRow,
 6410        is_active: bool,
 6411        cx: &mut Context<Self>,
 6412    ) -> AnyElement {
 6413        let show_tooltip = !self.context_menu_visible();
 6414        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6415            .icon_size(icon_size)
 6416            .shape(ui::IconButtonShape::Square)
 6417            .icon_color(ui::Color::Hidden)
 6418            .toggle_state(is_active)
 6419            .when(show_tooltip, |this| {
 6420                this.tooltip({
 6421                    let focus_handle = self.focus_handle.clone();
 6422                    move |_window, cx| {
 6423                        Tooltip::for_action_in(
 6424                            "Toggle Code Actions",
 6425                            &ToggleCodeActions {
 6426                                deployed_from: None,
 6427                                quick_launch: false,
 6428                            },
 6429                            &focus_handle,
 6430                            cx,
 6431                        )
 6432                    }
 6433                })
 6434            })
 6435            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6436                window.focus(&editor.focus_handle(cx));
 6437                editor.toggle_code_actions(
 6438                    &crate::actions::ToggleCodeActions {
 6439                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6440                            display_row,
 6441                        )),
 6442                        quick_launch: false,
 6443                    },
 6444                    window,
 6445                    cx,
 6446                );
 6447            }))
 6448            .into_any_element()
 6449    }
 6450
 6451    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6452        &self.context_menu
 6453    }
 6454
 6455    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6456        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6457            cx.background_executor()
 6458                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6459                .await;
 6460
 6461            let (start_buffer, start, _, end, newest_selection) = this
 6462                .update(cx, |this, cx| {
 6463                    let newest_selection = this.selections.newest_anchor().clone();
 6464                    if newest_selection.head().diff_base_anchor.is_some() {
 6465                        return None;
 6466                    }
 6467                    let display_snapshot = this.display_snapshot(cx);
 6468                    let newest_selection_adjusted =
 6469                        this.selections.newest_adjusted(&display_snapshot);
 6470                    let buffer = this.buffer.read(cx);
 6471
 6472                    let (start_buffer, start) =
 6473                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6474                    let (end_buffer, end) =
 6475                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6476
 6477                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6478                })?
 6479                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6480                .context(
 6481                    "Expected selection to lie in a single buffer when refreshing code actions",
 6482                )?;
 6483            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6484                let providers = this.code_action_providers.clone();
 6485                let tasks = this
 6486                    .code_action_providers
 6487                    .iter()
 6488                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6489                    .collect::<Vec<_>>();
 6490                (providers, tasks)
 6491            })?;
 6492
 6493            let mut actions = Vec::new();
 6494            for (provider, provider_actions) in
 6495                providers.into_iter().zip(future::join_all(tasks).await)
 6496            {
 6497                if let Some(provider_actions) = provider_actions.log_err() {
 6498                    actions.extend(provider_actions.into_iter().map(|action| {
 6499                        AvailableCodeAction {
 6500                            excerpt_id: newest_selection.start.excerpt_id,
 6501                            action,
 6502                            provider: provider.clone(),
 6503                        }
 6504                    }));
 6505                }
 6506            }
 6507
 6508            this.update(cx, |this, cx| {
 6509                this.available_code_actions = if actions.is_empty() {
 6510                    None
 6511                } else {
 6512                    Some((
 6513                        Location {
 6514                            buffer: start_buffer,
 6515                            range: start..end,
 6516                        },
 6517                        actions.into(),
 6518                    ))
 6519                };
 6520                cx.notify();
 6521            })
 6522        }));
 6523    }
 6524
 6525    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6526        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6527            self.show_git_blame_inline = false;
 6528
 6529            self.show_git_blame_inline_delay_task =
 6530                Some(cx.spawn_in(window, async move |this, cx| {
 6531                    cx.background_executor().timer(delay).await;
 6532
 6533                    this.update(cx, |this, cx| {
 6534                        this.show_git_blame_inline = true;
 6535                        cx.notify();
 6536                    })
 6537                    .log_err();
 6538                }));
 6539        }
 6540    }
 6541
 6542    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6543        let snapshot = self.snapshot(window, cx);
 6544        let cursor = self
 6545            .selections
 6546            .newest::<Point>(&snapshot.display_snapshot)
 6547            .head();
 6548        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6549        else {
 6550            return;
 6551        };
 6552
 6553        let Some(blame) = self.blame.as_ref() else {
 6554            return;
 6555        };
 6556
 6557        let row_info = RowInfo {
 6558            buffer_id: Some(buffer.remote_id()),
 6559            buffer_row: Some(point.row),
 6560            ..Default::default()
 6561        };
 6562        let Some((buffer, blame_entry)) = blame
 6563            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6564            .flatten()
 6565        else {
 6566            return;
 6567        };
 6568
 6569        let anchor = self.selections.newest_anchor().head();
 6570        let position = self.to_pixel_point(anchor, &snapshot, window);
 6571        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6572            self.show_blame_popover(
 6573                buffer,
 6574                &blame_entry,
 6575                position + last_bounds.origin,
 6576                true,
 6577                cx,
 6578            );
 6579        };
 6580    }
 6581
 6582    fn show_blame_popover(
 6583        &mut self,
 6584        buffer: BufferId,
 6585        blame_entry: &BlameEntry,
 6586        position: gpui::Point<Pixels>,
 6587        ignore_timeout: bool,
 6588        cx: &mut Context<Self>,
 6589    ) {
 6590        if let Some(state) = &mut self.inline_blame_popover {
 6591            state.hide_task.take();
 6592        } else {
 6593            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6594            let blame_entry = blame_entry.clone();
 6595            let show_task = cx.spawn(async move |editor, cx| {
 6596                if !ignore_timeout {
 6597                    cx.background_executor()
 6598                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6599                        .await;
 6600                }
 6601                editor
 6602                    .update(cx, |editor, cx| {
 6603                        editor.inline_blame_popover_show_task.take();
 6604                        let Some(blame) = editor.blame.as_ref() else {
 6605                            return;
 6606                        };
 6607                        let blame = blame.read(cx);
 6608                        let details = blame.details_for_entry(buffer, &blame_entry);
 6609                        let markdown = cx.new(|cx| {
 6610                            Markdown::new(
 6611                                details
 6612                                    .as_ref()
 6613                                    .map(|message| message.message.clone())
 6614                                    .unwrap_or_default(),
 6615                                None,
 6616                                None,
 6617                                cx,
 6618                            )
 6619                        });
 6620                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6621                            position,
 6622                            hide_task: None,
 6623                            popover_bounds: None,
 6624                            popover_state: InlineBlamePopoverState {
 6625                                scroll_handle: ScrollHandle::new(),
 6626                                commit_message: details,
 6627                                markdown,
 6628                            },
 6629                            keyboard_grace: ignore_timeout,
 6630                        });
 6631                        cx.notify();
 6632                    })
 6633                    .ok();
 6634            });
 6635            self.inline_blame_popover_show_task = Some(show_task);
 6636        }
 6637    }
 6638
 6639    fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6640        self.inline_blame_popover_show_task.take();
 6641        if let Some(state) = &mut self.inline_blame_popover {
 6642            let hide_task = cx.spawn(async move |editor, cx| {
 6643                if !ignore_timeout {
 6644                    cx.background_executor()
 6645                        .timer(std::time::Duration::from_millis(100))
 6646                        .await;
 6647                }
 6648                editor
 6649                    .update(cx, |editor, cx| {
 6650                        editor.inline_blame_popover.take();
 6651                        cx.notify();
 6652                    })
 6653                    .ok();
 6654            });
 6655            state.hide_task = Some(hide_task);
 6656            true
 6657        } else {
 6658            false
 6659        }
 6660    }
 6661
 6662    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6663        if self.pending_rename.is_some() {
 6664            return None;
 6665        }
 6666
 6667        let provider = self.semantics_provider.clone()?;
 6668        let buffer = self.buffer.read(cx);
 6669        let newest_selection = self.selections.newest_anchor().clone();
 6670        let cursor_position = newest_selection.head();
 6671        let (cursor_buffer, cursor_buffer_position) =
 6672            buffer.text_anchor_for_position(cursor_position, cx)?;
 6673        let (tail_buffer, tail_buffer_position) =
 6674            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6675        if cursor_buffer != tail_buffer {
 6676            return None;
 6677        }
 6678
 6679        let snapshot = cursor_buffer.read(cx).snapshot();
 6680        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6681        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6682        if start_word_range != end_word_range {
 6683            self.document_highlights_task.take();
 6684            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6685            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6686            return None;
 6687        }
 6688
 6689        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 6690        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6691            cx.background_executor()
 6692                .timer(Duration::from_millis(debounce))
 6693                .await;
 6694
 6695            let highlights = if let Some(highlights) = cx
 6696                .update(|cx| {
 6697                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6698                })
 6699                .ok()
 6700                .flatten()
 6701            {
 6702                highlights.await.log_err()
 6703            } else {
 6704                None
 6705            };
 6706
 6707            if let Some(highlights) = highlights {
 6708                this.update(cx, |this, cx| {
 6709                    if this.pending_rename.is_some() {
 6710                        return;
 6711                    }
 6712
 6713                    let buffer = this.buffer.read(cx);
 6714                    if buffer
 6715                        .text_anchor_for_position(cursor_position, cx)
 6716                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6717                    {
 6718                        return;
 6719                    }
 6720
 6721                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6722                    let mut write_ranges = Vec::new();
 6723                    let mut read_ranges = Vec::new();
 6724                    for highlight in highlights {
 6725                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6726                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6727                        {
 6728                            let start = highlight
 6729                                .range
 6730                                .start
 6731                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6732                            let end = highlight
 6733                                .range
 6734                                .end
 6735                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6736                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6737                                continue;
 6738                            }
 6739
 6740                            let range =
 6741                                Anchor::range_in_buffer(excerpt_id, buffer_id, *start..*end);
 6742                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6743                                write_ranges.push(range);
 6744                            } else {
 6745                                read_ranges.push(range);
 6746                            }
 6747                        }
 6748                    }
 6749
 6750                    this.highlight_background::<DocumentHighlightRead>(
 6751                        &read_ranges,
 6752                        |theme| theme.colors().editor_document_highlight_read_background,
 6753                        cx,
 6754                    );
 6755                    this.highlight_background::<DocumentHighlightWrite>(
 6756                        &write_ranges,
 6757                        |theme| theme.colors().editor_document_highlight_write_background,
 6758                        cx,
 6759                    );
 6760                    cx.notify();
 6761                })
 6762                .log_err();
 6763            }
 6764        }));
 6765        None
 6766    }
 6767
 6768    fn prepare_highlight_query_from_selection(
 6769        &mut self,
 6770        window: &Window,
 6771        cx: &mut Context<Editor>,
 6772    ) -> Option<(String, Range<Anchor>)> {
 6773        if matches!(self.mode, EditorMode::SingleLine) {
 6774            return None;
 6775        }
 6776        if !EditorSettings::get_global(cx).selection_highlight {
 6777            return None;
 6778        }
 6779        if self.selections.count() != 1 || self.selections.line_mode() {
 6780            return None;
 6781        }
 6782        let snapshot = self.snapshot(window, cx);
 6783        let selection = self.selections.newest::<Point>(&snapshot);
 6784        // If the selection spans multiple rows OR it is empty
 6785        if selection.start.row != selection.end.row
 6786            || selection.start.column == selection.end.column
 6787        {
 6788            return None;
 6789        }
 6790        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 6791        let query = snapshot
 6792            .buffer_snapshot()
 6793            .text_for_range(selection_anchor_range.clone())
 6794            .collect::<String>();
 6795        if query.trim().is_empty() {
 6796            return None;
 6797        }
 6798        Some((query, selection_anchor_range))
 6799    }
 6800
 6801    fn update_selection_occurrence_highlights(
 6802        &mut self,
 6803        query_text: String,
 6804        query_range: Range<Anchor>,
 6805        multi_buffer_range_to_query: Range<Point>,
 6806        use_debounce: bool,
 6807        window: &mut Window,
 6808        cx: &mut Context<Editor>,
 6809    ) -> Task<()> {
 6810        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6811        cx.spawn_in(window, async move |editor, cx| {
 6812            if use_debounce {
 6813                cx.background_executor()
 6814                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6815                    .await;
 6816            }
 6817            let match_task = cx.background_spawn(async move {
 6818                let buffer_ranges = multi_buffer_snapshot
 6819                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6820                    .into_iter()
 6821                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6822                let mut match_ranges = Vec::new();
 6823                let Ok(regex) = project::search::SearchQuery::text(
 6824                    query_text.clone(),
 6825                    false,
 6826                    false,
 6827                    false,
 6828                    Default::default(),
 6829                    Default::default(),
 6830                    false,
 6831                    None,
 6832                ) else {
 6833                    return Vec::default();
 6834                };
 6835                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 6836                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6837                    match_ranges.extend(
 6838                        regex
 6839                            .search(buffer_snapshot, Some(search_range.clone()))
 6840                            .await
 6841                            .into_iter()
 6842                            .filter_map(|match_range| {
 6843                                let match_start = buffer_snapshot
 6844                                    .anchor_after(search_range.start + match_range.start);
 6845                                let match_end = buffer_snapshot
 6846                                    .anchor_before(search_range.start + match_range.end);
 6847                                let match_anchor_range = Anchor::range_in_buffer(
 6848                                    excerpt_id,
 6849                                    buffer_snapshot.remote_id(),
 6850                                    match_start..match_end,
 6851                                );
 6852                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6853                            }),
 6854                    );
 6855                }
 6856                match_ranges
 6857            });
 6858            let match_ranges = match_task.await;
 6859            editor
 6860                .update_in(cx, |editor, _, cx| {
 6861                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6862                    if !match_ranges.is_empty() {
 6863                        editor.highlight_background::<SelectedTextHighlight>(
 6864                            &match_ranges,
 6865                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6866                            cx,
 6867                        )
 6868                    }
 6869                })
 6870                .log_err();
 6871        })
 6872    }
 6873
 6874    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6875        struct NewlineFold;
 6876        let type_id = std::any::TypeId::of::<NewlineFold>();
 6877        if !self.mode.is_single_line() {
 6878            return;
 6879        }
 6880        let snapshot = self.snapshot(window, cx);
 6881        if snapshot.buffer_snapshot().max_point().row == 0 {
 6882            return;
 6883        }
 6884        let task = cx.background_spawn(async move {
 6885            let new_newlines = snapshot
 6886                .buffer_chars_at(0)
 6887                .filter_map(|(c, i)| {
 6888                    if c == '\n' {
 6889                        Some(
 6890                            snapshot.buffer_snapshot().anchor_after(i)
 6891                                ..snapshot.buffer_snapshot().anchor_before(i + 1),
 6892                        )
 6893                    } else {
 6894                        None
 6895                    }
 6896                })
 6897                .collect::<Vec<_>>();
 6898            let existing_newlines = snapshot
 6899                .folds_in_range(0..snapshot.buffer_snapshot().len())
 6900                .filter_map(|fold| {
 6901                    if fold.placeholder.type_tag == Some(type_id) {
 6902                        Some(fold.range.start..fold.range.end)
 6903                    } else {
 6904                        None
 6905                    }
 6906                })
 6907                .collect::<Vec<_>>();
 6908
 6909            (new_newlines, existing_newlines)
 6910        });
 6911        self.folding_newlines = cx.spawn(async move |this, cx| {
 6912            let (new_newlines, existing_newlines) = task.await;
 6913            if new_newlines == existing_newlines {
 6914                return;
 6915            }
 6916            let placeholder = FoldPlaceholder {
 6917                render: Arc::new(move |_, _, cx| {
 6918                    div()
 6919                        .bg(cx.theme().status().hint_background)
 6920                        .border_b_1()
 6921                        .size_full()
 6922                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6923                        .border_color(cx.theme().status().hint)
 6924                        .child("\\n")
 6925                        .into_any()
 6926                }),
 6927                constrain_width: false,
 6928                merge_adjacent: false,
 6929                type_tag: Some(type_id),
 6930            };
 6931            let creases = new_newlines
 6932                .into_iter()
 6933                .map(|range| Crease::simple(range, placeholder.clone()))
 6934                .collect();
 6935            this.update(cx, |this, cx| {
 6936                this.display_map.update(cx, |display_map, cx| {
 6937                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6938                    display_map.fold(creases, cx);
 6939                });
 6940            })
 6941            .ok();
 6942        });
 6943    }
 6944
 6945    fn refresh_selected_text_highlights(
 6946        &mut self,
 6947        on_buffer_edit: bool,
 6948        window: &mut Window,
 6949        cx: &mut Context<Editor>,
 6950    ) {
 6951        let Some((query_text, query_range)) =
 6952            self.prepare_highlight_query_from_selection(window, cx)
 6953        else {
 6954            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6955            self.quick_selection_highlight_task.take();
 6956            self.debounced_selection_highlight_task.take();
 6957            return;
 6958        };
 6959        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6960        if on_buffer_edit
 6961            || self
 6962                .quick_selection_highlight_task
 6963                .as_ref()
 6964                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 6965        {
 6966            let multi_buffer_visible_start = self
 6967                .scroll_manager
 6968                .anchor()
 6969                .anchor
 6970                .to_point(&multi_buffer_snapshot);
 6971            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6972                multi_buffer_visible_start
 6973                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6974                Bias::Left,
 6975            );
 6976            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6977            self.quick_selection_highlight_task = Some((
 6978                query_range.clone(),
 6979                self.update_selection_occurrence_highlights(
 6980                    query_text.clone(),
 6981                    query_range.clone(),
 6982                    multi_buffer_visible_range,
 6983                    false,
 6984                    window,
 6985                    cx,
 6986                ),
 6987            ));
 6988        }
 6989        if on_buffer_edit
 6990            || self
 6991                .debounced_selection_highlight_task
 6992                .as_ref()
 6993                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 6994        {
 6995            let multi_buffer_start = multi_buffer_snapshot
 6996                .anchor_before(0)
 6997                .to_point(&multi_buffer_snapshot);
 6998            let multi_buffer_end = multi_buffer_snapshot
 6999                .anchor_after(multi_buffer_snapshot.len())
 7000                .to_point(&multi_buffer_snapshot);
 7001            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7002            self.debounced_selection_highlight_task = Some((
 7003                query_range.clone(),
 7004                self.update_selection_occurrence_highlights(
 7005                    query_text,
 7006                    query_range,
 7007                    multi_buffer_full_range,
 7008                    true,
 7009                    window,
 7010                    cx,
 7011                ),
 7012            ));
 7013        }
 7014    }
 7015
 7016    pub fn refresh_edit_prediction(
 7017        &mut self,
 7018        debounce: bool,
 7019        user_requested: bool,
 7020        window: &mut Window,
 7021        cx: &mut Context<Self>,
 7022    ) -> Option<()> {
 7023        if DisableAiSettings::get_global(cx).disable_ai {
 7024            return None;
 7025        }
 7026
 7027        let provider = self.edit_prediction_provider()?;
 7028        let cursor = self.selections.newest_anchor().head();
 7029        let (buffer, cursor_buffer_position) =
 7030            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7031
 7032        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7033            self.discard_edit_prediction(false, cx);
 7034            return None;
 7035        }
 7036
 7037        self.update_visible_edit_prediction(window, cx);
 7038
 7039        if !user_requested
 7040            && (!self.should_show_edit_predictions()
 7041                || !self.is_focused(window)
 7042                || buffer.read(cx).is_empty())
 7043        {
 7044            self.discard_edit_prediction(false, cx);
 7045            return None;
 7046        }
 7047
 7048        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7049        Some(())
 7050    }
 7051
 7052    fn show_edit_predictions_in_menu(&self) -> bool {
 7053        match self.edit_prediction_settings {
 7054            EditPredictionSettings::Disabled => false,
 7055            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7056        }
 7057    }
 7058
 7059    pub fn edit_predictions_enabled(&self) -> bool {
 7060        match self.edit_prediction_settings {
 7061            EditPredictionSettings::Disabled => false,
 7062            EditPredictionSettings::Enabled { .. } => true,
 7063        }
 7064    }
 7065
 7066    fn edit_prediction_requires_modifier(&self) -> bool {
 7067        match self.edit_prediction_settings {
 7068            EditPredictionSettings::Disabled => false,
 7069            EditPredictionSettings::Enabled {
 7070                preview_requires_modifier,
 7071                ..
 7072            } => preview_requires_modifier,
 7073        }
 7074    }
 7075
 7076    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7077        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7078            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7079            self.discard_edit_prediction(false, cx);
 7080        } else {
 7081            let selection = self.selections.newest_anchor();
 7082            let cursor = selection.head();
 7083
 7084            if let Some((buffer, cursor_buffer_position)) =
 7085                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7086            {
 7087                self.edit_prediction_settings =
 7088                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7089            }
 7090        }
 7091    }
 7092
 7093    fn edit_prediction_settings_at_position(
 7094        &self,
 7095        buffer: &Entity<Buffer>,
 7096        buffer_position: language::Anchor,
 7097        cx: &App,
 7098    ) -> EditPredictionSettings {
 7099        if !self.mode.is_full()
 7100            || !self.show_edit_predictions_override.unwrap_or(true)
 7101            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7102        {
 7103            return EditPredictionSettings::Disabled;
 7104        }
 7105
 7106        let buffer = buffer.read(cx);
 7107
 7108        let file = buffer.file();
 7109
 7110        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7111            return EditPredictionSettings::Disabled;
 7112        };
 7113
 7114        let by_provider = matches!(
 7115            self.menu_edit_predictions_policy,
 7116            MenuEditPredictionsPolicy::ByProvider
 7117        );
 7118
 7119        let show_in_menu = by_provider
 7120            && self
 7121                .edit_prediction_provider
 7122                .as_ref()
 7123                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7124
 7125        let preview_requires_modifier =
 7126            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7127
 7128        EditPredictionSettings::Enabled {
 7129            show_in_menu,
 7130            preview_requires_modifier,
 7131        }
 7132    }
 7133
 7134    fn should_show_edit_predictions(&self) -> bool {
 7135        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7136    }
 7137
 7138    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7139        matches!(
 7140            self.edit_prediction_preview,
 7141            EditPredictionPreview::Active { .. }
 7142        )
 7143    }
 7144
 7145    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7146        let cursor = self.selections.newest_anchor().head();
 7147        if let Some((buffer, cursor_position)) =
 7148            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7149        {
 7150            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7151        } else {
 7152            false
 7153        }
 7154    }
 7155
 7156    pub fn supports_minimap(&self, cx: &App) -> bool {
 7157        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7158    }
 7159
 7160    fn edit_predictions_enabled_in_buffer(
 7161        &self,
 7162        buffer: &Entity<Buffer>,
 7163        buffer_position: language::Anchor,
 7164        cx: &App,
 7165    ) -> bool {
 7166        maybe!({
 7167            if self.read_only(cx) {
 7168                return Some(false);
 7169            }
 7170            let provider = self.edit_prediction_provider()?;
 7171            if !provider.is_enabled(buffer, buffer_position, cx) {
 7172                return Some(false);
 7173            }
 7174            let buffer = buffer.read(cx);
 7175            let Some(file) = buffer.file() else {
 7176                return Some(true);
 7177            };
 7178            let settings = all_language_settings(Some(file), cx);
 7179            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7180        })
 7181        .unwrap_or(false)
 7182    }
 7183
 7184    fn cycle_edit_prediction(
 7185        &mut self,
 7186        direction: Direction,
 7187        window: &mut Window,
 7188        cx: &mut Context<Self>,
 7189    ) -> Option<()> {
 7190        let provider = self.edit_prediction_provider()?;
 7191        let cursor = self.selections.newest_anchor().head();
 7192        let (buffer, cursor_buffer_position) =
 7193            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7194        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7195            return None;
 7196        }
 7197
 7198        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7199        self.update_visible_edit_prediction(window, cx);
 7200
 7201        Some(())
 7202    }
 7203
 7204    pub fn show_edit_prediction(
 7205        &mut self,
 7206        _: &ShowEditPrediction,
 7207        window: &mut Window,
 7208        cx: &mut Context<Self>,
 7209    ) {
 7210        if !self.has_active_edit_prediction() {
 7211            self.refresh_edit_prediction(false, true, window, cx);
 7212            return;
 7213        }
 7214
 7215        self.update_visible_edit_prediction(window, cx);
 7216    }
 7217
 7218    pub fn display_cursor_names(
 7219        &mut self,
 7220        _: &DisplayCursorNames,
 7221        window: &mut Window,
 7222        cx: &mut Context<Self>,
 7223    ) {
 7224        self.show_cursor_names(window, cx);
 7225    }
 7226
 7227    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7228        self.show_cursor_names = true;
 7229        cx.notify();
 7230        cx.spawn_in(window, async move |this, cx| {
 7231            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7232            this.update(cx, |this, cx| {
 7233                this.show_cursor_names = false;
 7234                cx.notify()
 7235            })
 7236            .ok()
 7237        })
 7238        .detach();
 7239    }
 7240
 7241    pub fn next_edit_prediction(
 7242        &mut self,
 7243        _: &NextEditPrediction,
 7244        window: &mut Window,
 7245        cx: &mut Context<Self>,
 7246    ) {
 7247        if self.has_active_edit_prediction() {
 7248            self.cycle_edit_prediction(Direction::Next, window, cx);
 7249        } else {
 7250            let is_copilot_disabled = self
 7251                .refresh_edit_prediction(false, true, window, cx)
 7252                .is_none();
 7253            if is_copilot_disabled {
 7254                cx.propagate();
 7255            }
 7256        }
 7257    }
 7258
 7259    pub fn previous_edit_prediction(
 7260        &mut self,
 7261        _: &PreviousEditPrediction,
 7262        window: &mut Window,
 7263        cx: &mut Context<Self>,
 7264    ) {
 7265        if self.has_active_edit_prediction() {
 7266            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7267        } else {
 7268            let is_copilot_disabled = self
 7269                .refresh_edit_prediction(false, true, window, cx)
 7270                .is_none();
 7271            if is_copilot_disabled {
 7272                cx.propagate();
 7273            }
 7274        }
 7275    }
 7276
 7277    pub fn accept_edit_prediction(
 7278        &mut self,
 7279        _: &AcceptEditPrediction,
 7280        window: &mut Window,
 7281        cx: &mut Context<Self>,
 7282    ) {
 7283        if self.show_edit_predictions_in_menu() {
 7284            self.hide_context_menu(window, cx);
 7285        }
 7286
 7287        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7288            return;
 7289        };
 7290
 7291        match &active_edit_prediction.completion {
 7292            EditPrediction::MoveWithin { target, .. } => {
 7293                let target = *target;
 7294
 7295                if let Some(position_map) = &self.last_position_map {
 7296                    if position_map
 7297                        .visible_row_range
 7298                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7299                        || !self.edit_prediction_requires_modifier()
 7300                    {
 7301                        self.unfold_ranges(&[target..target], true, false, cx);
 7302                        // Note that this is also done in vim's handler of the Tab action.
 7303                        self.change_selections(
 7304                            SelectionEffects::scroll(Autoscroll::newest()),
 7305                            window,
 7306                            cx,
 7307                            |selections| {
 7308                                selections.select_anchor_ranges([target..target]);
 7309                            },
 7310                        );
 7311                        self.clear_row_highlights::<EditPredictionPreview>();
 7312
 7313                        self.edit_prediction_preview
 7314                            .set_previous_scroll_position(None);
 7315                    } else {
 7316                        self.edit_prediction_preview
 7317                            .set_previous_scroll_position(Some(
 7318                                position_map.snapshot.scroll_anchor,
 7319                            ));
 7320
 7321                        self.highlight_rows::<EditPredictionPreview>(
 7322                            target..target,
 7323                            cx.theme().colors().editor_highlighted_line_background,
 7324                            RowHighlightOptions {
 7325                                autoscroll: true,
 7326                                ..Default::default()
 7327                            },
 7328                            cx,
 7329                        );
 7330                        self.request_autoscroll(Autoscroll::fit(), cx);
 7331                    }
 7332                }
 7333            }
 7334            EditPrediction::MoveOutside { snapshot, target } => {
 7335                if let Some(workspace) = self.workspace() {
 7336                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7337                        .detach_and_log_err(cx);
 7338                }
 7339            }
 7340            EditPrediction::Edit { edits, .. } => {
 7341                self.report_edit_prediction_event(
 7342                    active_edit_prediction.completion_id.clone(),
 7343                    true,
 7344                    cx,
 7345                );
 7346
 7347                if let Some(provider) = self.edit_prediction_provider() {
 7348                    provider.accept(cx);
 7349                }
 7350
 7351                // Store the transaction ID and selections before applying the edit
 7352                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7353
 7354                let snapshot = self.buffer.read(cx).snapshot(cx);
 7355                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7356
 7357                self.buffer.update(cx, |buffer, cx| {
 7358                    buffer.edit(edits.iter().cloned(), None, cx)
 7359                });
 7360
 7361                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7362                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7363                });
 7364
 7365                let selections = self.selections.disjoint_anchors_arc();
 7366                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7367                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7368                    if has_new_transaction {
 7369                        self.selection_history
 7370                            .insert_transaction(transaction_id_now, selections);
 7371                    }
 7372                }
 7373
 7374                self.update_visible_edit_prediction(window, cx);
 7375                if self.active_edit_prediction.is_none() {
 7376                    self.refresh_edit_prediction(true, true, window, cx);
 7377                }
 7378
 7379                cx.notify();
 7380            }
 7381        }
 7382
 7383        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7384    }
 7385
 7386    pub fn accept_partial_edit_prediction(
 7387        &mut self,
 7388        _: &AcceptPartialEditPrediction,
 7389        window: &mut Window,
 7390        cx: &mut Context<Self>,
 7391    ) {
 7392        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7393            return;
 7394        };
 7395        if self.selections.count() != 1 {
 7396            return;
 7397        }
 7398
 7399        match &active_edit_prediction.completion {
 7400            EditPrediction::MoveWithin { target, .. } => {
 7401                let target = *target;
 7402                self.change_selections(
 7403                    SelectionEffects::scroll(Autoscroll::newest()),
 7404                    window,
 7405                    cx,
 7406                    |selections| {
 7407                        selections.select_anchor_ranges([target..target]);
 7408                    },
 7409                );
 7410            }
 7411            EditPrediction::MoveOutside { snapshot, target } => {
 7412                if let Some(workspace) = self.workspace() {
 7413                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7414                        .detach_and_log_err(cx);
 7415                }
 7416            }
 7417            EditPrediction::Edit { edits, .. } => {
 7418                self.report_edit_prediction_event(
 7419                    active_edit_prediction.completion_id.clone(),
 7420                    true,
 7421                    cx,
 7422                );
 7423
 7424                // Find an insertion that starts at the cursor position.
 7425                let snapshot = self.buffer.read(cx).snapshot(cx);
 7426                let cursor_offset = self
 7427                    .selections
 7428                    .newest::<usize>(&self.display_snapshot(cx))
 7429                    .head();
 7430                let insertion = edits.iter().find_map(|(range, text)| {
 7431                    let range = range.to_offset(&snapshot);
 7432                    if range.is_empty() && range.start == cursor_offset {
 7433                        Some(text)
 7434                    } else {
 7435                        None
 7436                    }
 7437                });
 7438
 7439                if let Some(text) = insertion {
 7440                    let mut partial_completion = text
 7441                        .chars()
 7442                        .by_ref()
 7443                        .take_while(|c| c.is_alphabetic())
 7444                        .collect::<String>();
 7445                    if partial_completion.is_empty() {
 7446                        partial_completion = text
 7447                            .chars()
 7448                            .by_ref()
 7449                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7450                            .collect::<String>();
 7451                    }
 7452
 7453                    cx.emit(EditorEvent::InputHandled {
 7454                        utf16_range_to_replace: None,
 7455                        text: partial_completion.clone().into(),
 7456                    });
 7457
 7458                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7459
 7460                    self.refresh_edit_prediction(true, true, window, cx);
 7461                    cx.notify();
 7462                } else {
 7463                    self.accept_edit_prediction(&Default::default(), window, cx);
 7464                }
 7465            }
 7466        }
 7467    }
 7468
 7469    fn discard_edit_prediction(
 7470        &mut self,
 7471        should_report_edit_prediction_event: bool,
 7472        cx: &mut Context<Self>,
 7473    ) -> bool {
 7474        if should_report_edit_prediction_event {
 7475            let completion_id = self
 7476                .active_edit_prediction
 7477                .as_ref()
 7478                .and_then(|active_completion| active_completion.completion_id.clone());
 7479
 7480            self.report_edit_prediction_event(completion_id, false, cx);
 7481        }
 7482
 7483        if let Some(provider) = self.edit_prediction_provider() {
 7484            provider.discard(cx);
 7485        }
 7486
 7487        self.take_active_edit_prediction(cx)
 7488    }
 7489
 7490    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7491        let Some(provider) = self.edit_prediction_provider() else {
 7492            return;
 7493        };
 7494
 7495        let Some((_, buffer, _)) = self
 7496            .buffer
 7497            .read(cx)
 7498            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7499        else {
 7500            return;
 7501        };
 7502
 7503        let extension = buffer
 7504            .read(cx)
 7505            .file()
 7506            .and_then(|file| Some(file.path().extension()?.to_string()));
 7507
 7508        let event_type = match accepted {
 7509            true => "Edit Prediction Accepted",
 7510            false => "Edit Prediction Discarded",
 7511        };
 7512        telemetry::event!(
 7513            event_type,
 7514            provider = provider.name(),
 7515            prediction_id = id,
 7516            suggestion_accepted = accepted,
 7517            file_extension = extension,
 7518        );
 7519    }
 7520
 7521    fn open_editor_at_anchor(
 7522        snapshot: &language::BufferSnapshot,
 7523        target: language::Anchor,
 7524        workspace: &Entity<Workspace>,
 7525        window: &mut Window,
 7526        cx: &mut App,
 7527    ) -> Task<Result<()>> {
 7528        workspace.update(cx, |workspace, cx| {
 7529            let path = snapshot.file().map(|file| file.full_path(cx));
 7530            let Some(path) =
 7531                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7532            else {
 7533                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7534            };
 7535            let target = text::ToPoint::to_point(&target, snapshot);
 7536            let item = workspace.open_path(path, None, true, window, cx);
 7537            window.spawn(cx, async move |cx| {
 7538                let Some(editor) = item.await?.downcast::<Editor>() else {
 7539                    return Ok(());
 7540                };
 7541                editor
 7542                    .update_in(cx, |editor, window, cx| {
 7543                        editor.go_to_singleton_buffer_point(target, window, cx);
 7544                    })
 7545                    .ok();
 7546                anyhow::Ok(())
 7547            })
 7548        })
 7549    }
 7550
 7551    pub fn has_active_edit_prediction(&self) -> bool {
 7552        self.active_edit_prediction.is_some()
 7553    }
 7554
 7555    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7556        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7557            return false;
 7558        };
 7559
 7560        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7561        self.clear_highlights::<EditPredictionHighlight>(cx);
 7562        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7563        true
 7564    }
 7565
 7566    /// Returns true when we're displaying the edit prediction popover below the cursor
 7567    /// like we are not previewing and the LSP autocomplete menu is visible
 7568    /// or we are in `when_holding_modifier` mode.
 7569    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7570        if self.edit_prediction_preview_is_active()
 7571            || !self.show_edit_predictions_in_menu()
 7572            || !self.edit_predictions_enabled()
 7573        {
 7574            return false;
 7575        }
 7576
 7577        if self.has_visible_completions_menu() {
 7578            return true;
 7579        }
 7580
 7581        has_completion && self.edit_prediction_requires_modifier()
 7582    }
 7583
 7584    fn handle_modifiers_changed(
 7585        &mut self,
 7586        modifiers: Modifiers,
 7587        position_map: &PositionMap,
 7588        window: &mut Window,
 7589        cx: &mut Context<Self>,
 7590    ) {
 7591        // Ensure that the edit prediction preview is updated, even when not
 7592        // enabled, if there's an active edit prediction preview.
 7593        if self.show_edit_predictions_in_menu()
 7594            || matches!(
 7595                self.edit_prediction_preview,
 7596                EditPredictionPreview::Active { .. }
 7597            )
 7598        {
 7599            self.update_edit_prediction_preview(&modifiers, window, cx);
 7600        }
 7601
 7602        self.update_selection_mode(&modifiers, position_map, window, cx);
 7603
 7604        let mouse_position = window.mouse_position();
 7605        if !position_map.text_hitbox.is_hovered(window) {
 7606            return;
 7607        }
 7608
 7609        self.update_hovered_link(
 7610            position_map.point_for_position(mouse_position),
 7611            &position_map.snapshot,
 7612            modifiers,
 7613            window,
 7614            cx,
 7615        )
 7616    }
 7617
 7618    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7619        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7620            MultiCursorModifier::Alt => modifiers.secondary(),
 7621            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7622        }
 7623    }
 7624
 7625    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7626        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7627            MultiCursorModifier::Alt => modifiers.alt,
 7628            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7629        }
 7630    }
 7631
 7632    fn columnar_selection_mode(
 7633        modifiers: &Modifiers,
 7634        cx: &mut Context<Self>,
 7635    ) -> Option<ColumnarMode> {
 7636        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7637            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 7638                Some(ColumnarMode::FromMouse)
 7639            } else if Self::is_alt_pressed(modifiers, cx) {
 7640                Some(ColumnarMode::FromSelection)
 7641            } else {
 7642                None
 7643            }
 7644        } else {
 7645            None
 7646        }
 7647    }
 7648
 7649    fn update_selection_mode(
 7650        &mut self,
 7651        modifiers: &Modifiers,
 7652        position_map: &PositionMap,
 7653        window: &mut Window,
 7654        cx: &mut Context<Self>,
 7655    ) {
 7656        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7657            return;
 7658        };
 7659        if self.selections.pending_anchor().is_none() {
 7660            return;
 7661        }
 7662
 7663        let mouse_position = window.mouse_position();
 7664        let point_for_position = position_map.point_for_position(mouse_position);
 7665        let position = point_for_position.previous_valid;
 7666
 7667        self.select(
 7668            SelectPhase::BeginColumnar {
 7669                position,
 7670                reset: false,
 7671                mode,
 7672                goal_column: point_for_position.exact_unclipped.column(),
 7673            },
 7674            window,
 7675            cx,
 7676        );
 7677    }
 7678
 7679    fn update_edit_prediction_preview(
 7680        &mut self,
 7681        modifiers: &Modifiers,
 7682        window: &mut Window,
 7683        cx: &mut Context<Self>,
 7684    ) {
 7685        let mut modifiers_held = false;
 7686        if let Some(accept_keystroke) = self
 7687            .accept_edit_prediction_keybind(false, window, cx)
 7688            .keystroke()
 7689        {
 7690            modifiers_held = modifiers_held
 7691                || (accept_keystroke.modifiers() == modifiers
 7692                    && accept_keystroke.modifiers().modified());
 7693        };
 7694        if let Some(accept_partial_keystroke) = self
 7695            .accept_edit_prediction_keybind(true, window, cx)
 7696            .keystroke()
 7697        {
 7698            modifiers_held = modifiers_held
 7699                || (accept_partial_keystroke.modifiers() == modifiers
 7700                    && accept_partial_keystroke.modifiers().modified());
 7701        }
 7702
 7703        if modifiers_held {
 7704            if matches!(
 7705                self.edit_prediction_preview,
 7706                EditPredictionPreview::Inactive { .. }
 7707            ) {
 7708                self.edit_prediction_preview = EditPredictionPreview::Active {
 7709                    previous_scroll_position: None,
 7710                    since: Instant::now(),
 7711                };
 7712
 7713                self.update_visible_edit_prediction(window, cx);
 7714                cx.notify();
 7715            }
 7716        } else if let EditPredictionPreview::Active {
 7717            previous_scroll_position,
 7718            since,
 7719        } = self.edit_prediction_preview
 7720        {
 7721            if let (Some(previous_scroll_position), Some(position_map)) =
 7722                (previous_scroll_position, self.last_position_map.as_ref())
 7723            {
 7724                self.set_scroll_position(
 7725                    previous_scroll_position
 7726                        .scroll_position(&position_map.snapshot.display_snapshot),
 7727                    window,
 7728                    cx,
 7729                );
 7730            }
 7731
 7732            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7733                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7734            };
 7735            self.clear_row_highlights::<EditPredictionPreview>();
 7736            self.update_visible_edit_prediction(window, cx);
 7737            cx.notify();
 7738        }
 7739    }
 7740
 7741    fn update_visible_edit_prediction(
 7742        &mut self,
 7743        _window: &mut Window,
 7744        cx: &mut Context<Self>,
 7745    ) -> Option<()> {
 7746        if DisableAiSettings::get_global(cx).disable_ai {
 7747            return None;
 7748        }
 7749
 7750        if self.ime_transaction.is_some() {
 7751            self.discard_edit_prediction(false, cx);
 7752            return None;
 7753        }
 7754
 7755        let selection = self.selections.newest_anchor();
 7756        let cursor = selection.head();
 7757        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7758        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7759        let excerpt_id = cursor.excerpt_id;
 7760
 7761        let show_in_menu = self.show_edit_predictions_in_menu();
 7762        let completions_menu_has_precedence = !show_in_menu
 7763            && (self.context_menu.borrow().is_some()
 7764                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7765
 7766        if completions_menu_has_precedence
 7767            || !offset_selection.is_empty()
 7768            || self
 7769                .active_edit_prediction
 7770                .as_ref()
 7771                .is_some_and(|completion| {
 7772                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7773                        return false;
 7774                    };
 7775                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7776                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7777                    !invalidation_range.contains(&offset_selection.head())
 7778                })
 7779        {
 7780            self.discard_edit_prediction(false, cx);
 7781            return None;
 7782        }
 7783
 7784        self.take_active_edit_prediction(cx);
 7785        let Some(provider) = self.edit_prediction_provider() else {
 7786            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7787            return None;
 7788        };
 7789
 7790        let (buffer, cursor_buffer_position) =
 7791            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7792
 7793        self.edit_prediction_settings =
 7794            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7795
 7796        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7797
 7798        if self.edit_prediction_indent_conflict {
 7799            let cursor_point = cursor.to_point(&multibuffer);
 7800
 7801            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7802
 7803            if let Some((_, indent)) = indents.iter().next()
 7804                && indent.len == cursor_point.column
 7805            {
 7806                self.edit_prediction_indent_conflict = false;
 7807            }
 7808        }
 7809
 7810        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7811
 7812        let (completion_id, edits, edit_preview) = match edit_prediction {
 7813            edit_prediction::EditPrediction::Local {
 7814                id,
 7815                edits,
 7816                edit_preview,
 7817            } => (id, edits, edit_preview),
 7818            edit_prediction::EditPrediction::Jump {
 7819                id,
 7820                snapshot,
 7821                target,
 7822            } => {
 7823                self.stale_edit_prediction_in_menu = None;
 7824                self.active_edit_prediction = Some(EditPredictionState {
 7825                    inlay_ids: vec![],
 7826                    completion: EditPrediction::MoveOutside { snapshot, target },
 7827                    completion_id: id,
 7828                    invalidation_range: None,
 7829                });
 7830                cx.notify();
 7831                return Some(());
 7832            }
 7833        };
 7834
 7835        let edits = edits
 7836            .into_iter()
 7837            .flat_map(|(range, new_text)| {
 7838                Some((
 7839                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 7840                    new_text,
 7841                ))
 7842            })
 7843            .collect::<Vec<_>>();
 7844        if edits.is_empty() {
 7845            return None;
 7846        }
 7847
 7848        let first_edit_start = edits.first().unwrap().0.start;
 7849        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7850        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7851
 7852        let last_edit_end = edits.last().unwrap().0.end;
 7853        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7854        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7855
 7856        let cursor_row = cursor.to_point(&multibuffer).row;
 7857
 7858        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7859
 7860        let mut inlay_ids = Vec::new();
 7861        let invalidation_row_range;
 7862        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7863            Some(cursor_row..edit_end_row)
 7864        } else if cursor_row > edit_end_row {
 7865            Some(edit_start_row..cursor_row)
 7866        } else {
 7867            None
 7868        };
 7869        let supports_jump = self
 7870            .edit_prediction_provider
 7871            .as_ref()
 7872            .map(|provider| provider.provider.supports_jump_to_edit())
 7873            .unwrap_or(true);
 7874
 7875        let is_move = supports_jump
 7876            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7877        let completion = if is_move {
 7878            invalidation_row_range =
 7879                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7880            let target = first_edit_start;
 7881            EditPrediction::MoveWithin { target, snapshot }
 7882        } else {
 7883            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7884                && !self.edit_predictions_hidden_for_vim_mode;
 7885
 7886            if show_completions_in_buffer {
 7887                if edits
 7888                    .iter()
 7889                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7890                {
 7891                    let mut inlays = Vec::new();
 7892                    for (range, new_text) in &edits {
 7893                        let inlay = Inlay::edit_prediction(
 7894                            post_inc(&mut self.next_inlay_id),
 7895                            range.start,
 7896                            new_text.as_str(),
 7897                        );
 7898                        inlay_ids.push(inlay.id);
 7899                        inlays.push(inlay);
 7900                    }
 7901
 7902                    self.splice_inlays(&[], inlays, cx);
 7903                } else {
 7904                    let background_color = cx.theme().status().deleted_background;
 7905                    self.highlight_text::<EditPredictionHighlight>(
 7906                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7907                        HighlightStyle {
 7908                            background_color: Some(background_color),
 7909                            ..Default::default()
 7910                        },
 7911                        cx,
 7912                    );
 7913                }
 7914            }
 7915
 7916            invalidation_row_range = edit_start_row..edit_end_row;
 7917
 7918            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7919                if provider.show_tab_accept_marker() {
 7920                    EditDisplayMode::TabAccept
 7921                } else {
 7922                    EditDisplayMode::Inline
 7923                }
 7924            } else {
 7925                EditDisplayMode::DiffPopover
 7926            };
 7927
 7928            EditPrediction::Edit {
 7929                edits,
 7930                edit_preview,
 7931                display_mode,
 7932                snapshot,
 7933            }
 7934        };
 7935
 7936        let invalidation_range = multibuffer
 7937            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7938            ..multibuffer.anchor_after(Point::new(
 7939                invalidation_row_range.end,
 7940                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7941            ));
 7942
 7943        self.stale_edit_prediction_in_menu = None;
 7944        self.active_edit_prediction = Some(EditPredictionState {
 7945            inlay_ids,
 7946            completion,
 7947            completion_id,
 7948            invalidation_range: Some(invalidation_range),
 7949        });
 7950
 7951        cx.notify();
 7952
 7953        Some(())
 7954    }
 7955
 7956    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7957        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7958    }
 7959
 7960    fn clear_tasks(&mut self) {
 7961        self.tasks.clear()
 7962    }
 7963
 7964    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7965        if self.tasks.insert(key, value).is_some() {
 7966            // This case should hopefully be rare, but just in case...
 7967            log::error!(
 7968                "multiple different run targets found on a single line, only the last target will be rendered"
 7969            )
 7970        }
 7971    }
 7972
 7973    /// Get all display points of breakpoints that will be rendered within editor
 7974    ///
 7975    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7976    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7977    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7978    fn active_breakpoints(
 7979        &self,
 7980        range: Range<DisplayRow>,
 7981        window: &mut Window,
 7982        cx: &mut Context<Self>,
 7983    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7984        let mut breakpoint_display_points = HashMap::default();
 7985
 7986        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7987            return breakpoint_display_points;
 7988        };
 7989
 7990        let snapshot = self.snapshot(window, cx);
 7991
 7992        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 7993        let Some(project) = self.project() else {
 7994            return breakpoint_display_points;
 7995        };
 7996
 7997        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7998            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7999
 8000        for (buffer_snapshot, range, excerpt_id) in
 8001            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8002        {
 8003            let Some(buffer) = project
 8004                .read(cx)
 8005                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8006            else {
 8007                continue;
 8008            };
 8009            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8010                &buffer,
 8011                Some(
 8012                    buffer_snapshot.anchor_before(range.start)
 8013                        ..buffer_snapshot.anchor_after(range.end),
 8014                ),
 8015                buffer_snapshot,
 8016                cx,
 8017            );
 8018            for (breakpoint, state) in breakpoints {
 8019                let multi_buffer_anchor =
 8020                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8021                let position = multi_buffer_anchor
 8022                    .to_point(&multi_buffer_snapshot)
 8023                    .to_display_point(&snapshot);
 8024
 8025                breakpoint_display_points.insert(
 8026                    position.row(),
 8027                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8028                );
 8029            }
 8030        }
 8031
 8032        breakpoint_display_points
 8033    }
 8034
 8035    fn breakpoint_context_menu(
 8036        &self,
 8037        anchor: Anchor,
 8038        window: &mut Window,
 8039        cx: &mut Context<Self>,
 8040    ) -> Entity<ui::ContextMenu> {
 8041        let weak_editor = cx.weak_entity();
 8042        let focus_handle = self.focus_handle(cx);
 8043
 8044        let row = self
 8045            .buffer
 8046            .read(cx)
 8047            .snapshot(cx)
 8048            .summary_for_anchor::<Point>(&anchor)
 8049            .row;
 8050
 8051        let breakpoint = self
 8052            .breakpoint_at_row(row, window, cx)
 8053            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8054
 8055        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8056            "Edit Log Breakpoint"
 8057        } else {
 8058            "Set Log Breakpoint"
 8059        };
 8060
 8061        let condition_breakpoint_msg = if breakpoint
 8062            .as_ref()
 8063            .is_some_and(|bp| bp.1.condition.is_some())
 8064        {
 8065            "Edit Condition Breakpoint"
 8066        } else {
 8067            "Set Condition Breakpoint"
 8068        };
 8069
 8070        let hit_condition_breakpoint_msg = if breakpoint
 8071            .as_ref()
 8072            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8073        {
 8074            "Edit Hit Condition Breakpoint"
 8075        } else {
 8076            "Set Hit Condition Breakpoint"
 8077        };
 8078
 8079        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8080            "Unset Breakpoint"
 8081        } else {
 8082            "Set Breakpoint"
 8083        };
 8084
 8085        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8086
 8087        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8088            BreakpointState::Enabled => Some("Disable"),
 8089            BreakpointState::Disabled => Some("Enable"),
 8090        });
 8091
 8092        let (anchor, breakpoint) =
 8093            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8094
 8095        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8096            menu.on_blur_subscription(Subscription::new(|| {}))
 8097                .context(focus_handle)
 8098                .when(run_to_cursor, |this| {
 8099                    let weak_editor = weak_editor.clone();
 8100                    this.entry("Run to cursor", None, move |window, cx| {
 8101                        weak_editor
 8102                            .update(cx, |editor, cx| {
 8103                                editor.change_selections(
 8104                                    SelectionEffects::no_scroll(),
 8105                                    window,
 8106                                    cx,
 8107                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8108                                );
 8109                            })
 8110                            .ok();
 8111
 8112                        window.dispatch_action(Box::new(RunToCursor), cx);
 8113                    })
 8114                    .separator()
 8115                })
 8116                .when_some(toggle_state_msg, |this, msg| {
 8117                    this.entry(msg, None, {
 8118                        let weak_editor = weak_editor.clone();
 8119                        let breakpoint = breakpoint.clone();
 8120                        move |_window, cx| {
 8121                            weak_editor
 8122                                .update(cx, |this, cx| {
 8123                                    this.edit_breakpoint_at_anchor(
 8124                                        anchor,
 8125                                        breakpoint.as_ref().clone(),
 8126                                        BreakpointEditAction::InvertState,
 8127                                        cx,
 8128                                    );
 8129                                })
 8130                                .log_err();
 8131                        }
 8132                    })
 8133                })
 8134                .entry(set_breakpoint_msg, None, {
 8135                    let weak_editor = weak_editor.clone();
 8136                    let breakpoint = breakpoint.clone();
 8137                    move |_window, cx| {
 8138                        weak_editor
 8139                            .update(cx, |this, cx| {
 8140                                this.edit_breakpoint_at_anchor(
 8141                                    anchor,
 8142                                    breakpoint.as_ref().clone(),
 8143                                    BreakpointEditAction::Toggle,
 8144                                    cx,
 8145                                );
 8146                            })
 8147                            .log_err();
 8148                    }
 8149                })
 8150                .entry(log_breakpoint_msg, None, {
 8151                    let breakpoint = breakpoint.clone();
 8152                    let weak_editor = weak_editor.clone();
 8153                    move |window, cx| {
 8154                        weak_editor
 8155                            .update(cx, |this, cx| {
 8156                                this.add_edit_breakpoint_block(
 8157                                    anchor,
 8158                                    breakpoint.as_ref(),
 8159                                    BreakpointPromptEditAction::Log,
 8160                                    window,
 8161                                    cx,
 8162                                );
 8163                            })
 8164                            .log_err();
 8165                    }
 8166                })
 8167                .entry(condition_breakpoint_msg, None, {
 8168                    let breakpoint = breakpoint.clone();
 8169                    let weak_editor = weak_editor.clone();
 8170                    move |window, cx| {
 8171                        weak_editor
 8172                            .update(cx, |this, cx| {
 8173                                this.add_edit_breakpoint_block(
 8174                                    anchor,
 8175                                    breakpoint.as_ref(),
 8176                                    BreakpointPromptEditAction::Condition,
 8177                                    window,
 8178                                    cx,
 8179                                );
 8180                            })
 8181                            .log_err();
 8182                    }
 8183                })
 8184                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8185                    weak_editor
 8186                        .update(cx, |this, cx| {
 8187                            this.add_edit_breakpoint_block(
 8188                                anchor,
 8189                                breakpoint.as_ref(),
 8190                                BreakpointPromptEditAction::HitCondition,
 8191                                window,
 8192                                cx,
 8193                            );
 8194                        })
 8195                        .log_err();
 8196                })
 8197        })
 8198    }
 8199
 8200    fn render_breakpoint(
 8201        &self,
 8202        position: Anchor,
 8203        row: DisplayRow,
 8204        breakpoint: &Breakpoint,
 8205        state: Option<BreakpointSessionState>,
 8206        cx: &mut Context<Self>,
 8207    ) -> IconButton {
 8208        let is_rejected = state.is_some_and(|s| !s.verified);
 8209        // Is it a breakpoint that shows up when hovering over gutter?
 8210        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8211            (false, false),
 8212            |PhantomBreakpointIndicator {
 8213                 is_active,
 8214                 display_row,
 8215                 collides_with_existing_breakpoint,
 8216             }| {
 8217                (
 8218                    is_active && display_row == row,
 8219                    collides_with_existing_breakpoint,
 8220                )
 8221            },
 8222        );
 8223
 8224        let (color, icon) = {
 8225            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8226                (false, false) => ui::IconName::DebugBreakpoint,
 8227                (true, false) => ui::IconName::DebugLogBreakpoint,
 8228                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8229                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8230            };
 8231
 8232            let color = if is_phantom {
 8233                Color::Hint
 8234            } else if is_rejected {
 8235                Color::Disabled
 8236            } else {
 8237                Color::Debugger
 8238            };
 8239
 8240            (color, icon)
 8241        };
 8242
 8243        let breakpoint = Arc::from(breakpoint.clone());
 8244
 8245        let alt_as_text = gpui::Keystroke {
 8246            modifiers: Modifiers::secondary_key(),
 8247            ..Default::default()
 8248        };
 8249        let primary_action_text = if breakpoint.is_disabled() {
 8250            "Enable breakpoint"
 8251        } else if is_phantom && !collides_with_existing {
 8252            "Set breakpoint"
 8253        } else {
 8254            "Unset breakpoint"
 8255        };
 8256        let focus_handle = self.focus_handle.clone();
 8257
 8258        let meta = if is_rejected {
 8259            SharedString::from("No executable code is associated with this line.")
 8260        } else if collides_with_existing && !breakpoint.is_disabled() {
 8261            SharedString::from(format!(
 8262                "{alt_as_text}-click to disable,\nright-click for more options."
 8263            ))
 8264        } else {
 8265            SharedString::from("Right-click for more options.")
 8266        };
 8267        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8268            .icon_size(IconSize::XSmall)
 8269            .size(ui::ButtonSize::None)
 8270            .when(is_rejected, |this| {
 8271                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8272            })
 8273            .icon_color(color)
 8274            .style(ButtonStyle::Transparent)
 8275            .on_click(cx.listener({
 8276                move |editor, event: &ClickEvent, window, cx| {
 8277                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8278                        BreakpointEditAction::InvertState
 8279                    } else {
 8280                        BreakpointEditAction::Toggle
 8281                    };
 8282
 8283                    window.focus(&editor.focus_handle(cx));
 8284                    editor.edit_breakpoint_at_anchor(
 8285                        position,
 8286                        breakpoint.as_ref().clone(),
 8287                        edit_action,
 8288                        cx,
 8289                    );
 8290                }
 8291            }))
 8292            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8293                editor.set_breakpoint_context_menu(
 8294                    row,
 8295                    Some(position),
 8296                    event.position(),
 8297                    window,
 8298                    cx,
 8299                );
 8300            }))
 8301            .tooltip(move |_window, cx| {
 8302                Tooltip::with_meta_in(
 8303                    primary_action_text,
 8304                    Some(&ToggleBreakpoint),
 8305                    meta.clone(),
 8306                    &focus_handle,
 8307                    cx,
 8308                )
 8309            })
 8310    }
 8311
 8312    fn build_tasks_context(
 8313        project: &Entity<Project>,
 8314        buffer: &Entity<Buffer>,
 8315        buffer_row: u32,
 8316        tasks: &Arc<RunnableTasks>,
 8317        cx: &mut Context<Self>,
 8318    ) -> Task<Option<task::TaskContext>> {
 8319        let position = Point::new(buffer_row, tasks.column);
 8320        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8321        let location = Location {
 8322            buffer: buffer.clone(),
 8323            range: range_start..range_start,
 8324        };
 8325        // Fill in the environmental variables from the tree-sitter captures
 8326        let mut captured_task_variables = TaskVariables::default();
 8327        for (capture_name, value) in tasks.extra_variables.clone() {
 8328            captured_task_variables.insert(
 8329                task::VariableName::Custom(capture_name.into()),
 8330                value.clone(),
 8331            );
 8332        }
 8333        project.update(cx, |project, cx| {
 8334            project.task_store().update(cx, |task_store, cx| {
 8335                task_store.task_context_for_location(captured_task_variables, location, cx)
 8336            })
 8337        })
 8338    }
 8339
 8340    pub fn spawn_nearest_task(
 8341        &mut self,
 8342        action: &SpawnNearestTask,
 8343        window: &mut Window,
 8344        cx: &mut Context<Self>,
 8345    ) {
 8346        let Some((workspace, _)) = self.workspace.clone() else {
 8347            return;
 8348        };
 8349        let Some(project) = self.project.clone() else {
 8350            return;
 8351        };
 8352
 8353        // Try to find a closest, enclosing node using tree-sitter that has a task
 8354        let Some((buffer, buffer_row, tasks)) = self
 8355            .find_enclosing_node_task(cx)
 8356            // Or find the task that's closest in row-distance.
 8357            .or_else(|| self.find_closest_task(cx))
 8358        else {
 8359            return;
 8360        };
 8361
 8362        let reveal_strategy = action.reveal;
 8363        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8364        cx.spawn_in(window, async move |_, cx| {
 8365            let context = task_context.await?;
 8366            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8367
 8368            let resolved = &mut resolved_task.resolved;
 8369            resolved.reveal = reveal_strategy;
 8370
 8371            workspace
 8372                .update_in(cx, |workspace, window, cx| {
 8373                    workspace.schedule_resolved_task(
 8374                        task_source_kind,
 8375                        resolved_task,
 8376                        false,
 8377                        window,
 8378                        cx,
 8379                    );
 8380                })
 8381                .ok()
 8382        })
 8383        .detach();
 8384    }
 8385
 8386    fn find_closest_task(
 8387        &mut self,
 8388        cx: &mut Context<Self>,
 8389    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8390        let cursor_row = self
 8391            .selections
 8392            .newest_adjusted(&self.display_snapshot(cx))
 8393            .head()
 8394            .row;
 8395
 8396        let ((buffer_id, row), tasks) = self
 8397            .tasks
 8398            .iter()
 8399            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8400
 8401        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8402        let tasks = Arc::new(tasks.to_owned());
 8403        Some((buffer, *row, tasks))
 8404    }
 8405
 8406    fn find_enclosing_node_task(
 8407        &mut self,
 8408        cx: &mut Context<Self>,
 8409    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8410        let snapshot = self.buffer.read(cx).snapshot(cx);
 8411        let offset = self
 8412            .selections
 8413            .newest::<usize>(&self.display_snapshot(cx))
 8414            .head();
 8415        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8416        let buffer_id = excerpt.buffer().remote_id();
 8417
 8418        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8419        let mut cursor = layer.node().walk();
 8420
 8421        while cursor.goto_first_child_for_byte(offset).is_some() {
 8422            if cursor.node().end_byte() == offset {
 8423                cursor.goto_next_sibling();
 8424            }
 8425        }
 8426
 8427        // Ascend to the smallest ancestor that contains the range and has a task.
 8428        loop {
 8429            let node = cursor.node();
 8430            let node_range = node.byte_range();
 8431            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8432
 8433            // Check if this node contains our offset
 8434            if node_range.start <= offset && node_range.end >= offset {
 8435                // If it contains offset, check for task
 8436                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8437                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8438                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8439                }
 8440            }
 8441
 8442            if !cursor.goto_parent() {
 8443                break;
 8444            }
 8445        }
 8446        None
 8447    }
 8448
 8449    fn render_run_indicator(
 8450        &self,
 8451        _style: &EditorStyle,
 8452        is_active: bool,
 8453        row: DisplayRow,
 8454        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8455        cx: &mut Context<Self>,
 8456    ) -> IconButton {
 8457        let color = Color::Muted;
 8458        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8459
 8460        IconButton::new(
 8461            ("run_indicator", row.0 as usize),
 8462            ui::IconName::PlayOutlined,
 8463        )
 8464        .shape(ui::IconButtonShape::Square)
 8465        .icon_size(IconSize::XSmall)
 8466        .icon_color(color)
 8467        .toggle_state(is_active)
 8468        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8469            let quick_launch = match e {
 8470                ClickEvent::Keyboard(_) => true,
 8471                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8472            };
 8473
 8474            window.focus(&editor.focus_handle(cx));
 8475            editor.toggle_code_actions(
 8476                &ToggleCodeActions {
 8477                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8478                    quick_launch,
 8479                },
 8480                window,
 8481                cx,
 8482            );
 8483        }))
 8484        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8485            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8486        }))
 8487    }
 8488
 8489    pub fn context_menu_visible(&self) -> bool {
 8490        !self.edit_prediction_preview_is_active()
 8491            && self
 8492                .context_menu
 8493                .borrow()
 8494                .as_ref()
 8495                .is_some_and(|menu| menu.visible())
 8496    }
 8497
 8498    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8499        self.context_menu
 8500            .borrow()
 8501            .as_ref()
 8502            .map(|menu| menu.origin())
 8503    }
 8504
 8505    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8506        self.context_menu_options = Some(options);
 8507    }
 8508
 8509    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8510    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8511
 8512    fn render_edit_prediction_popover(
 8513        &mut self,
 8514        text_bounds: &Bounds<Pixels>,
 8515        content_origin: gpui::Point<Pixels>,
 8516        right_margin: Pixels,
 8517        editor_snapshot: &EditorSnapshot,
 8518        visible_row_range: Range<DisplayRow>,
 8519        scroll_top: ScrollOffset,
 8520        scroll_bottom: ScrollOffset,
 8521        line_layouts: &[LineWithInvisibles],
 8522        line_height: Pixels,
 8523        scroll_position: gpui::Point<ScrollOffset>,
 8524        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8525        newest_selection_head: Option<DisplayPoint>,
 8526        editor_width: Pixels,
 8527        style: &EditorStyle,
 8528        window: &mut Window,
 8529        cx: &mut App,
 8530    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8531        if self.mode().is_minimap() {
 8532            return None;
 8533        }
 8534        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8535
 8536        if self.edit_prediction_visible_in_cursor_popover(true) {
 8537            return None;
 8538        }
 8539
 8540        match &active_edit_prediction.completion {
 8541            EditPrediction::MoveWithin { target, .. } => {
 8542                let target_display_point = target.to_display_point(editor_snapshot);
 8543
 8544                if self.edit_prediction_requires_modifier() {
 8545                    if !self.edit_prediction_preview_is_active() {
 8546                        return None;
 8547                    }
 8548
 8549                    self.render_edit_prediction_modifier_jump_popover(
 8550                        text_bounds,
 8551                        content_origin,
 8552                        visible_row_range,
 8553                        line_layouts,
 8554                        line_height,
 8555                        scroll_pixel_position,
 8556                        newest_selection_head,
 8557                        target_display_point,
 8558                        window,
 8559                        cx,
 8560                    )
 8561                } else {
 8562                    self.render_edit_prediction_eager_jump_popover(
 8563                        text_bounds,
 8564                        content_origin,
 8565                        editor_snapshot,
 8566                        visible_row_range,
 8567                        scroll_top,
 8568                        scroll_bottom,
 8569                        line_height,
 8570                        scroll_pixel_position,
 8571                        target_display_point,
 8572                        editor_width,
 8573                        window,
 8574                        cx,
 8575                    )
 8576                }
 8577            }
 8578            EditPrediction::Edit {
 8579                display_mode: EditDisplayMode::Inline,
 8580                ..
 8581            } => None,
 8582            EditPrediction::Edit {
 8583                display_mode: EditDisplayMode::TabAccept,
 8584                edits,
 8585                ..
 8586            } => {
 8587                let range = &edits.first()?.0;
 8588                let target_display_point = range.end.to_display_point(editor_snapshot);
 8589
 8590                self.render_edit_prediction_end_of_line_popover(
 8591                    "Accept",
 8592                    editor_snapshot,
 8593                    visible_row_range,
 8594                    target_display_point,
 8595                    line_height,
 8596                    scroll_pixel_position,
 8597                    content_origin,
 8598                    editor_width,
 8599                    window,
 8600                    cx,
 8601                )
 8602            }
 8603            EditPrediction::Edit {
 8604                edits,
 8605                edit_preview,
 8606                display_mode: EditDisplayMode::DiffPopover,
 8607                snapshot,
 8608            } => self.render_edit_prediction_diff_popover(
 8609                text_bounds,
 8610                content_origin,
 8611                right_margin,
 8612                editor_snapshot,
 8613                visible_row_range,
 8614                line_layouts,
 8615                line_height,
 8616                scroll_position,
 8617                scroll_pixel_position,
 8618                newest_selection_head,
 8619                editor_width,
 8620                style,
 8621                edits,
 8622                edit_preview,
 8623                snapshot,
 8624                window,
 8625                cx,
 8626            ),
 8627            EditPrediction::MoveOutside { snapshot, .. } => {
 8628                let file_name = snapshot
 8629                    .file()
 8630                    .map(|file| file.file_name(cx))
 8631                    .unwrap_or("untitled");
 8632                let mut element = self
 8633                    .render_edit_prediction_line_popover(
 8634                        format!("Jump to {file_name}"),
 8635                        Some(IconName::ZedPredict),
 8636                        window,
 8637                        cx,
 8638                    )
 8639                    .into_any();
 8640
 8641                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8642                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8643                let origin_y = text_bounds.size.height - size.height - px(30.);
 8644                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8645                element.prepaint_at(origin, window, cx);
 8646
 8647                Some((element, origin))
 8648            }
 8649        }
 8650    }
 8651
 8652    fn render_edit_prediction_modifier_jump_popover(
 8653        &mut self,
 8654        text_bounds: &Bounds<Pixels>,
 8655        content_origin: gpui::Point<Pixels>,
 8656        visible_row_range: Range<DisplayRow>,
 8657        line_layouts: &[LineWithInvisibles],
 8658        line_height: Pixels,
 8659        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8660        newest_selection_head: Option<DisplayPoint>,
 8661        target_display_point: DisplayPoint,
 8662        window: &mut Window,
 8663        cx: &mut App,
 8664    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8665        let scrolled_content_origin =
 8666            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8667
 8668        const SCROLL_PADDING_Y: Pixels = px(12.);
 8669
 8670        if target_display_point.row() < visible_row_range.start {
 8671            return self.render_edit_prediction_scroll_popover(
 8672                |_| SCROLL_PADDING_Y,
 8673                IconName::ArrowUp,
 8674                visible_row_range,
 8675                line_layouts,
 8676                newest_selection_head,
 8677                scrolled_content_origin,
 8678                window,
 8679                cx,
 8680            );
 8681        } else if target_display_point.row() >= visible_row_range.end {
 8682            return self.render_edit_prediction_scroll_popover(
 8683                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8684                IconName::ArrowDown,
 8685                visible_row_range,
 8686                line_layouts,
 8687                newest_selection_head,
 8688                scrolled_content_origin,
 8689                window,
 8690                cx,
 8691            );
 8692        }
 8693
 8694        const POLE_WIDTH: Pixels = px(2.);
 8695
 8696        let line_layout =
 8697            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8698        let target_column = target_display_point.column() as usize;
 8699
 8700        let target_x = line_layout.x_for_index(target_column);
 8701        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8702            - scroll_pixel_position.y;
 8703
 8704        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8705
 8706        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8707        border_color.l += 0.001;
 8708
 8709        let mut element = v_flex()
 8710            .items_end()
 8711            .when(flag_on_right, |el| el.items_start())
 8712            .child(if flag_on_right {
 8713                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8714                    .rounded_bl(px(0.))
 8715                    .rounded_tl(px(0.))
 8716                    .border_l_2()
 8717                    .border_color(border_color)
 8718            } else {
 8719                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8720                    .rounded_br(px(0.))
 8721                    .rounded_tr(px(0.))
 8722                    .border_r_2()
 8723                    .border_color(border_color)
 8724            })
 8725            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8726            .into_any();
 8727
 8728        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8729
 8730        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8731            - point(
 8732                if flag_on_right {
 8733                    POLE_WIDTH
 8734                } else {
 8735                    size.width - POLE_WIDTH
 8736                },
 8737                size.height - line_height,
 8738            );
 8739
 8740        origin.x = origin.x.max(content_origin.x);
 8741
 8742        element.prepaint_at(origin, window, cx);
 8743
 8744        Some((element, origin))
 8745    }
 8746
 8747    fn render_edit_prediction_scroll_popover(
 8748        &mut self,
 8749        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8750        scroll_icon: IconName,
 8751        visible_row_range: Range<DisplayRow>,
 8752        line_layouts: &[LineWithInvisibles],
 8753        newest_selection_head: Option<DisplayPoint>,
 8754        scrolled_content_origin: gpui::Point<Pixels>,
 8755        window: &mut Window,
 8756        cx: &mut App,
 8757    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8758        let mut element = self
 8759            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8760            .into_any();
 8761
 8762        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8763
 8764        let cursor = newest_selection_head?;
 8765        let cursor_row_layout =
 8766            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8767        let cursor_column = cursor.column() as usize;
 8768
 8769        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8770
 8771        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8772
 8773        element.prepaint_at(origin, window, cx);
 8774        Some((element, origin))
 8775    }
 8776
 8777    fn render_edit_prediction_eager_jump_popover(
 8778        &mut self,
 8779        text_bounds: &Bounds<Pixels>,
 8780        content_origin: gpui::Point<Pixels>,
 8781        editor_snapshot: &EditorSnapshot,
 8782        visible_row_range: Range<DisplayRow>,
 8783        scroll_top: ScrollOffset,
 8784        scroll_bottom: ScrollOffset,
 8785        line_height: Pixels,
 8786        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8787        target_display_point: DisplayPoint,
 8788        editor_width: Pixels,
 8789        window: &mut Window,
 8790        cx: &mut App,
 8791    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8792        if target_display_point.row().as_f64() < scroll_top {
 8793            let mut element = self
 8794                .render_edit_prediction_line_popover(
 8795                    "Jump to Edit",
 8796                    Some(IconName::ArrowUp),
 8797                    window,
 8798                    cx,
 8799                )
 8800                .into_any();
 8801
 8802            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8803            let offset = point(
 8804                (text_bounds.size.width - size.width) / 2.,
 8805                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8806            );
 8807
 8808            let origin = text_bounds.origin + offset;
 8809            element.prepaint_at(origin, window, cx);
 8810            Some((element, origin))
 8811        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 8812            let mut element = self
 8813                .render_edit_prediction_line_popover(
 8814                    "Jump to Edit",
 8815                    Some(IconName::ArrowDown),
 8816                    window,
 8817                    cx,
 8818                )
 8819                .into_any();
 8820
 8821            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8822            let offset = point(
 8823                (text_bounds.size.width - size.width) / 2.,
 8824                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8825            );
 8826
 8827            let origin = text_bounds.origin + offset;
 8828            element.prepaint_at(origin, window, cx);
 8829            Some((element, origin))
 8830        } else {
 8831            self.render_edit_prediction_end_of_line_popover(
 8832                "Jump to Edit",
 8833                editor_snapshot,
 8834                visible_row_range,
 8835                target_display_point,
 8836                line_height,
 8837                scroll_pixel_position,
 8838                content_origin,
 8839                editor_width,
 8840                window,
 8841                cx,
 8842            )
 8843        }
 8844    }
 8845
 8846    fn render_edit_prediction_end_of_line_popover(
 8847        self: &mut Editor,
 8848        label: &'static str,
 8849        editor_snapshot: &EditorSnapshot,
 8850        visible_row_range: Range<DisplayRow>,
 8851        target_display_point: DisplayPoint,
 8852        line_height: Pixels,
 8853        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8854        content_origin: gpui::Point<Pixels>,
 8855        editor_width: Pixels,
 8856        window: &mut Window,
 8857        cx: &mut App,
 8858    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8859        let target_line_end = DisplayPoint::new(
 8860            target_display_point.row(),
 8861            editor_snapshot.line_len(target_display_point.row()),
 8862        );
 8863
 8864        let mut element = self
 8865            .render_edit_prediction_line_popover(label, None, window, cx)
 8866            .into_any();
 8867
 8868        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8869
 8870        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8871
 8872        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 8873        let mut origin = start_point
 8874            + line_origin
 8875            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8876        origin.x = origin.x.max(content_origin.x);
 8877
 8878        let max_x = content_origin.x + editor_width - size.width;
 8879
 8880        if origin.x > max_x {
 8881            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8882
 8883            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8884                origin.y += offset;
 8885                IconName::ArrowUp
 8886            } else {
 8887                origin.y -= offset;
 8888                IconName::ArrowDown
 8889            };
 8890
 8891            element = self
 8892                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 8893                .into_any();
 8894
 8895            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8896
 8897            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8898        }
 8899
 8900        element.prepaint_at(origin, window, cx);
 8901        Some((element, origin))
 8902    }
 8903
 8904    fn render_edit_prediction_diff_popover(
 8905        self: &Editor,
 8906        text_bounds: &Bounds<Pixels>,
 8907        content_origin: gpui::Point<Pixels>,
 8908        right_margin: Pixels,
 8909        editor_snapshot: &EditorSnapshot,
 8910        visible_row_range: Range<DisplayRow>,
 8911        line_layouts: &[LineWithInvisibles],
 8912        line_height: Pixels,
 8913        scroll_position: gpui::Point<ScrollOffset>,
 8914        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8915        newest_selection_head: Option<DisplayPoint>,
 8916        editor_width: Pixels,
 8917        style: &EditorStyle,
 8918        edits: &Vec<(Range<Anchor>, String)>,
 8919        edit_preview: &Option<language::EditPreview>,
 8920        snapshot: &language::BufferSnapshot,
 8921        window: &mut Window,
 8922        cx: &mut App,
 8923    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8924        let edit_start = edits
 8925            .first()
 8926            .unwrap()
 8927            .0
 8928            .start
 8929            .to_display_point(editor_snapshot);
 8930        let edit_end = edits
 8931            .last()
 8932            .unwrap()
 8933            .0
 8934            .end
 8935            .to_display_point(editor_snapshot);
 8936
 8937        let is_visible = visible_row_range.contains(&edit_start.row())
 8938            || visible_row_range.contains(&edit_end.row());
 8939        if !is_visible {
 8940            return None;
 8941        }
 8942
 8943        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8944            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8945        } else {
 8946            // Fallback for providers without edit_preview
 8947            crate::edit_prediction_fallback_text(edits, cx)
 8948        };
 8949
 8950        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8951        let line_count = highlighted_edits.text.lines().count();
 8952
 8953        const BORDER_WIDTH: Pixels = px(1.);
 8954
 8955        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8956        let has_keybind = keybind.is_some();
 8957
 8958        let mut element = h_flex()
 8959            .items_start()
 8960            .child(
 8961                h_flex()
 8962                    .bg(cx.theme().colors().editor_background)
 8963                    .border(BORDER_WIDTH)
 8964                    .shadow_xs()
 8965                    .border_color(cx.theme().colors().border)
 8966                    .rounded_l_lg()
 8967                    .when(line_count > 1, |el| el.rounded_br_lg())
 8968                    .pr_1()
 8969                    .child(styled_text),
 8970            )
 8971            .child(
 8972                h_flex()
 8973                    .h(line_height + BORDER_WIDTH * 2.)
 8974                    .px_1p5()
 8975                    .gap_1()
 8976                    // Workaround: For some reason, there's a gap if we don't do this
 8977                    .ml(-BORDER_WIDTH)
 8978                    .shadow(vec![gpui::BoxShadow {
 8979                        color: gpui::black().opacity(0.05),
 8980                        offset: point(px(1.), px(1.)),
 8981                        blur_radius: px(2.),
 8982                        spread_radius: px(0.),
 8983                    }])
 8984                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8985                    .border(BORDER_WIDTH)
 8986                    .border_color(cx.theme().colors().border)
 8987                    .rounded_r_lg()
 8988                    .id("edit_prediction_diff_popover_keybind")
 8989                    .when(!has_keybind, |el| {
 8990                        let status_colors = cx.theme().status();
 8991
 8992                        el.bg(status_colors.error_background)
 8993                            .border_color(status_colors.error.opacity(0.6))
 8994                            .child(Icon::new(IconName::Info).color(Color::Error))
 8995                            .cursor_default()
 8996                            .hoverable_tooltip(move |_window, cx| {
 8997                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8998                            })
 8999                    })
 9000                    .children(keybind),
 9001            )
 9002            .into_any();
 9003
 9004        let longest_row =
 9005            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9006        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9007            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9008        } else {
 9009            layout_line(
 9010                longest_row,
 9011                editor_snapshot,
 9012                style,
 9013                editor_width,
 9014                |_| false,
 9015                window,
 9016                cx,
 9017            )
 9018            .width
 9019        };
 9020
 9021        let viewport_bounds =
 9022            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9023                right: -right_margin,
 9024                ..Default::default()
 9025            });
 9026
 9027        let x_after_longest = Pixels::from(
 9028            ScrollPixelOffset::from(
 9029                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9030            ) - scroll_pixel_position.x,
 9031        );
 9032
 9033        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9034
 9035        // Fully visible if it can be displayed within the window (allow overlapping other
 9036        // panes). However, this is only allowed if the popover starts within text_bounds.
 9037        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9038            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9039
 9040        let mut origin = if can_position_to_the_right {
 9041            point(
 9042                x_after_longest,
 9043                text_bounds.origin.y
 9044                    + Pixels::from(
 9045                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9046                            - scroll_pixel_position.y,
 9047                    ),
 9048            )
 9049        } else {
 9050            let cursor_row = newest_selection_head.map(|head| head.row());
 9051            let above_edit = edit_start
 9052                .row()
 9053                .0
 9054                .checked_sub(line_count as u32)
 9055                .map(DisplayRow);
 9056            let below_edit = Some(edit_end.row() + 1);
 9057            let above_cursor =
 9058                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9059            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9060
 9061            // Place the edit popover adjacent to the edit if there is a location
 9062            // available that is onscreen and does not obscure the cursor. Otherwise,
 9063            // place it adjacent to the cursor.
 9064            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9065                .into_iter()
 9066                .flatten()
 9067                .find(|&start_row| {
 9068                    let end_row = start_row + line_count as u32;
 9069                    visible_row_range.contains(&start_row)
 9070                        && visible_row_range.contains(&end_row)
 9071                        && cursor_row
 9072                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9073                })?;
 9074
 9075            content_origin
 9076                + point(
 9077                    Pixels::from(-scroll_pixel_position.x),
 9078                    Pixels::from(
 9079                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9080                    ),
 9081                )
 9082        };
 9083
 9084        origin.x -= BORDER_WIDTH;
 9085
 9086        window.defer_draw(element, origin, 1);
 9087
 9088        // Do not return an element, since it will already be drawn due to defer_draw.
 9089        None
 9090    }
 9091
 9092    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9093        px(30.)
 9094    }
 9095
 9096    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9097        if self.read_only(cx) {
 9098            cx.theme().players().read_only()
 9099        } else {
 9100            self.style.as_ref().unwrap().local_player
 9101        }
 9102    }
 9103
 9104    fn render_edit_prediction_accept_keybind(
 9105        &self,
 9106        window: &mut Window,
 9107        cx: &mut App,
 9108    ) -> Option<AnyElement> {
 9109        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9110        let accept_keystroke = accept_binding.keystroke()?;
 9111
 9112        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9113
 9114        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9115            Color::Accent
 9116        } else {
 9117            Color::Muted
 9118        };
 9119
 9120        h_flex()
 9121            .px_0p5()
 9122            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9123            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9124            .text_size(TextSize::XSmall.rems(cx))
 9125            .child(h_flex().children(ui::render_modifiers(
 9126                accept_keystroke.modifiers(),
 9127                PlatformStyle::platform(),
 9128                Some(modifiers_color),
 9129                Some(IconSize::XSmall.rems().into()),
 9130                true,
 9131            )))
 9132            .when(is_platform_style_mac, |parent| {
 9133                parent.child(accept_keystroke.key().to_string())
 9134            })
 9135            .when(!is_platform_style_mac, |parent| {
 9136                parent.child(
 9137                    Key::new(
 9138                        util::capitalize(accept_keystroke.key()),
 9139                        Some(Color::Default),
 9140                    )
 9141                    .size(Some(IconSize::XSmall.rems().into())),
 9142                )
 9143            })
 9144            .into_any()
 9145            .into()
 9146    }
 9147
 9148    fn render_edit_prediction_line_popover(
 9149        &self,
 9150        label: impl Into<SharedString>,
 9151        icon: Option<IconName>,
 9152        window: &mut Window,
 9153        cx: &mut App,
 9154    ) -> Stateful<Div> {
 9155        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9156
 9157        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9158        let has_keybind = keybind.is_some();
 9159
 9160        h_flex()
 9161            .id("ep-line-popover")
 9162            .py_0p5()
 9163            .pl_1()
 9164            .pr(padding_right)
 9165            .gap_1()
 9166            .rounded_md()
 9167            .border_1()
 9168            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9169            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9170            .shadow_xs()
 9171            .when(!has_keybind, |el| {
 9172                let status_colors = cx.theme().status();
 9173
 9174                el.bg(status_colors.error_background)
 9175                    .border_color(status_colors.error.opacity(0.6))
 9176                    .pl_2()
 9177                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9178                    .cursor_default()
 9179                    .hoverable_tooltip(move |_window, cx| {
 9180                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9181                    })
 9182            })
 9183            .children(keybind)
 9184            .child(
 9185                Label::new(label)
 9186                    .size(LabelSize::Small)
 9187                    .when(!has_keybind, |el| {
 9188                        el.color(cx.theme().status().error.into()).strikethrough()
 9189                    }),
 9190            )
 9191            .when(!has_keybind, |el| {
 9192                el.child(
 9193                    h_flex().ml_1().child(
 9194                        Icon::new(IconName::Info)
 9195                            .size(IconSize::Small)
 9196                            .color(cx.theme().status().error.into()),
 9197                    ),
 9198                )
 9199            })
 9200            .when_some(icon, |element, icon| {
 9201                element.child(
 9202                    div()
 9203                        .mt(px(1.5))
 9204                        .child(Icon::new(icon).size(IconSize::Small)),
 9205                )
 9206            })
 9207    }
 9208
 9209    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9210        let accent_color = cx.theme().colors().text_accent;
 9211        let editor_bg_color = cx.theme().colors().editor_background;
 9212        editor_bg_color.blend(accent_color.opacity(0.1))
 9213    }
 9214
 9215    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9216        let accent_color = cx.theme().colors().text_accent;
 9217        let editor_bg_color = cx.theme().colors().editor_background;
 9218        editor_bg_color.blend(accent_color.opacity(0.6))
 9219    }
 9220    fn get_prediction_provider_icon_name(
 9221        provider: &Option<RegisteredEditPredictionProvider>,
 9222    ) -> IconName {
 9223        match provider {
 9224            Some(provider) => match provider.provider.name() {
 9225                "copilot" => IconName::Copilot,
 9226                "supermaven" => IconName::Supermaven,
 9227                _ => IconName::ZedPredict,
 9228            },
 9229            None => IconName::ZedPredict,
 9230        }
 9231    }
 9232
 9233    fn render_edit_prediction_cursor_popover(
 9234        &self,
 9235        min_width: Pixels,
 9236        max_width: Pixels,
 9237        cursor_point: Point,
 9238        style: &EditorStyle,
 9239        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9240        _window: &Window,
 9241        cx: &mut Context<Editor>,
 9242    ) -> Option<AnyElement> {
 9243        let provider = self.edit_prediction_provider.as_ref()?;
 9244        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9245
 9246        let is_refreshing = provider.provider.is_refreshing(cx);
 9247
 9248        fn pending_completion_container(icon: IconName) -> Div {
 9249            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9250        }
 9251
 9252        let completion = match &self.active_edit_prediction {
 9253            Some(prediction) => {
 9254                if !self.has_visible_completions_menu() {
 9255                    const RADIUS: Pixels = px(6.);
 9256                    const BORDER_WIDTH: Pixels = px(1.);
 9257
 9258                    return Some(
 9259                        h_flex()
 9260                            .elevation_2(cx)
 9261                            .border(BORDER_WIDTH)
 9262                            .border_color(cx.theme().colors().border)
 9263                            .when(accept_keystroke.is_none(), |el| {
 9264                                el.border_color(cx.theme().status().error)
 9265                            })
 9266                            .rounded(RADIUS)
 9267                            .rounded_tl(px(0.))
 9268                            .overflow_hidden()
 9269                            .child(div().px_1p5().child(match &prediction.completion {
 9270                                EditPrediction::MoveWithin { target, snapshot } => {
 9271                                    use text::ToPoint as _;
 9272                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9273                                    {
 9274                                        Icon::new(IconName::ZedPredictDown)
 9275                                    } else {
 9276                                        Icon::new(IconName::ZedPredictUp)
 9277                                    }
 9278                                }
 9279                                EditPrediction::MoveOutside { .. } => {
 9280                                    // TODO [zeta2] custom icon for external jump?
 9281                                    Icon::new(provider_icon)
 9282                                }
 9283                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9284                            }))
 9285                            .child(
 9286                                h_flex()
 9287                                    .gap_1()
 9288                                    .py_1()
 9289                                    .px_2()
 9290                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9291                                    .border_l_1()
 9292                                    .border_color(cx.theme().colors().border)
 9293                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9294                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9295                                        el.child(
 9296                                            Label::new("Hold")
 9297                                                .size(LabelSize::Small)
 9298                                                .when(accept_keystroke.is_none(), |el| {
 9299                                                    el.strikethrough()
 9300                                                })
 9301                                                .line_height_style(LineHeightStyle::UiLabel),
 9302                                        )
 9303                                    })
 9304                                    .id("edit_prediction_cursor_popover_keybind")
 9305                                    .when(accept_keystroke.is_none(), |el| {
 9306                                        let status_colors = cx.theme().status();
 9307
 9308                                        el.bg(status_colors.error_background)
 9309                                            .border_color(status_colors.error.opacity(0.6))
 9310                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9311                                            .cursor_default()
 9312                                            .hoverable_tooltip(move |_window, cx| {
 9313                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9314                                                    .into()
 9315                                            })
 9316                                    })
 9317                                    .when_some(
 9318                                        accept_keystroke.as_ref(),
 9319                                        |el, accept_keystroke| {
 9320                                            el.child(h_flex().children(ui::render_modifiers(
 9321                                                accept_keystroke.modifiers(),
 9322                                                PlatformStyle::platform(),
 9323                                                Some(Color::Default),
 9324                                                Some(IconSize::XSmall.rems().into()),
 9325                                                false,
 9326                                            )))
 9327                                        },
 9328                                    ),
 9329                            )
 9330                            .into_any(),
 9331                    );
 9332                }
 9333
 9334                self.render_edit_prediction_cursor_popover_preview(
 9335                    prediction,
 9336                    cursor_point,
 9337                    style,
 9338                    cx,
 9339                )?
 9340            }
 9341
 9342            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9343                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9344                    stale_completion,
 9345                    cursor_point,
 9346                    style,
 9347                    cx,
 9348                )?,
 9349
 9350                None => pending_completion_container(provider_icon)
 9351                    .child(Label::new("...").size(LabelSize::Small)),
 9352            },
 9353
 9354            None => pending_completion_container(provider_icon)
 9355                .child(Label::new("...").size(LabelSize::Small)),
 9356        };
 9357
 9358        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9359            completion
 9360                .with_animation(
 9361                    "loading-completion",
 9362                    Animation::new(Duration::from_secs(2))
 9363                        .repeat()
 9364                        .with_easing(pulsating_between(0.4, 0.8)),
 9365                    |label, delta| label.opacity(delta),
 9366                )
 9367                .into_any_element()
 9368        } else {
 9369            completion.into_any_element()
 9370        };
 9371
 9372        let has_completion = self.active_edit_prediction.is_some();
 9373
 9374        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9375        Some(
 9376            h_flex()
 9377                .min_w(min_width)
 9378                .max_w(max_width)
 9379                .flex_1()
 9380                .elevation_2(cx)
 9381                .border_color(cx.theme().colors().border)
 9382                .child(
 9383                    div()
 9384                        .flex_1()
 9385                        .py_1()
 9386                        .px_2()
 9387                        .overflow_hidden()
 9388                        .child(completion),
 9389                )
 9390                .when_some(accept_keystroke, |el, accept_keystroke| {
 9391                    if !accept_keystroke.modifiers().modified() {
 9392                        return el;
 9393                    }
 9394
 9395                    el.child(
 9396                        h_flex()
 9397                            .h_full()
 9398                            .border_l_1()
 9399                            .rounded_r_lg()
 9400                            .border_color(cx.theme().colors().border)
 9401                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9402                            .gap_1()
 9403                            .py_1()
 9404                            .px_2()
 9405                            .child(
 9406                                h_flex()
 9407                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9408                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9409                                    .child(h_flex().children(ui::render_modifiers(
 9410                                        accept_keystroke.modifiers(),
 9411                                        PlatformStyle::platform(),
 9412                                        Some(if !has_completion {
 9413                                            Color::Muted
 9414                                        } else {
 9415                                            Color::Default
 9416                                        }),
 9417                                        None,
 9418                                        false,
 9419                                    ))),
 9420                            )
 9421                            .child(Label::new("Preview").into_any_element())
 9422                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9423                    )
 9424                })
 9425                .into_any(),
 9426        )
 9427    }
 9428
 9429    fn render_edit_prediction_cursor_popover_preview(
 9430        &self,
 9431        completion: &EditPredictionState,
 9432        cursor_point: Point,
 9433        style: &EditorStyle,
 9434        cx: &mut Context<Editor>,
 9435    ) -> Option<Div> {
 9436        use text::ToPoint as _;
 9437
 9438        fn render_relative_row_jump(
 9439            prefix: impl Into<String>,
 9440            current_row: u32,
 9441            target_row: u32,
 9442        ) -> Div {
 9443            let (row_diff, arrow) = if target_row < current_row {
 9444                (current_row - target_row, IconName::ArrowUp)
 9445            } else {
 9446                (target_row - current_row, IconName::ArrowDown)
 9447            };
 9448
 9449            h_flex()
 9450                .child(
 9451                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9452                        .color(Color::Muted)
 9453                        .size(LabelSize::Small),
 9454                )
 9455                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9456        }
 9457
 9458        let supports_jump = self
 9459            .edit_prediction_provider
 9460            .as_ref()
 9461            .map(|provider| provider.provider.supports_jump_to_edit())
 9462            .unwrap_or(true);
 9463
 9464        match &completion.completion {
 9465            EditPrediction::MoveWithin {
 9466                target, snapshot, ..
 9467            } => {
 9468                if !supports_jump {
 9469                    return None;
 9470                }
 9471
 9472                Some(
 9473                    h_flex()
 9474                        .px_2()
 9475                        .gap_2()
 9476                        .flex_1()
 9477                        .child(
 9478                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9479                                Icon::new(IconName::ZedPredictDown)
 9480                            } else {
 9481                                Icon::new(IconName::ZedPredictUp)
 9482                            },
 9483                        )
 9484                        .child(Label::new("Jump to Edit")),
 9485                )
 9486            }
 9487            EditPrediction::MoveOutside { snapshot, .. } => {
 9488                let file_name = snapshot
 9489                    .file()
 9490                    .map(|file| file.file_name(cx))
 9491                    .unwrap_or("untitled");
 9492                Some(
 9493                    h_flex()
 9494                        .px_2()
 9495                        .gap_2()
 9496                        .flex_1()
 9497                        .child(Icon::new(IconName::ZedPredict))
 9498                        .child(Label::new(format!("Jump to {file_name}"))),
 9499                )
 9500            }
 9501            EditPrediction::Edit {
 9502                edits,
 9503                edit_preview,
 9504                snapshot,
 9505                display_mode: _,
 9506            } => {
 9507                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9508
 9509                let (highlighted_edits, has_more_lines) =
 9510                    if let Some(edit_preview) = edit_preview.as_ref() {
 9511                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9512                            .first_line_preview()
 9513                    } else {
 9514                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9515                    };
 9516
 9517                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9518                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9519
 9520                let preview = h_flex()
 9521                    .gap_1()
 9522                    .min_w_16()
 9523                    .child(styled_text)
 9524                    .when(has_more_lines, |parent| parent.child(""));
 9525
 9526                let left = if supports_jump && first_edit_row != cursor_point.row {
 9527                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9528                        .into_any_element()
 9529                } else {
 9530                    let icon_name =
 9531                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9532                    Icon::new(icon_name).into_any_element()
 9533                };
 9534
 9535                Some(
 9536                    h_flex()
 9537                        .h_full()
 9538                        .flex_1()
 9539                        .gap_2()
 9540                        .pr_1()
 9541                        .overflow_x_hidden()
 9542                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9543                        .child(left)
 9544                        .child(preview),
 9545                )
 9546            }
 9547        }
 9548    }
 9549
 9550    pub fn render_context_menu(
 9551        &self,
 9552        style: &EditorStyle,
 9553        max_height_in_lines: u32,
 9554        window: &mut Window,
 9555        cx: &mut Context<Editor>,
 9556    ) -> Option<AnyElement> {
 9557        let menu = self.context_menu.borrow();
 9558        let menu = menu.as_ref()?;
 9559        if !menu.visible() {
 9560            return None;
 9561        };
 9562        Some(menu.render(style, max_height_in_lines, window, cx))
 9563    }
 9564
 9565    fn render_context_menu_aside(
 9566        &mut self,
 9567        max_size: Size<Pixels>,
 9568        window: &mut Window,
 9569        cx: &mut Context<Editor>,
 9570    ) -> Option<AnyElement> {
 9571        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9572            if menu.visible() {
 9573                menu.render_aside(max_size, window, cx)
 9574            } else {
 9575                None
 9576            }
 9577        })
 9578    }
 9579
 9580    fn hide_context_menu(
 9581        &mut self,
 9582        window: &mut Window,
 9583        cx: &mut Context<Self>,
 9584    ) -> Option<CodeContextMenu> {
 9585        cx.notify();
 9586        self.completion_tasks.clear();
 9587        let context_menu = self.context_menu.borrow_mut().take();
 9588        self.stale_edit_prediction_in_menu.take();
 9589        self.update_visible_edit_prediction(window, cx);
 9590        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9591            && let Some(completion_provider) = &self.completion_provider
 9592        {
 9593            completion_provider.selection_changed(None, window, cx);
 9594        }
 9595        context_menu
 9596    }
 9597
 9598    fn show_snippet_choices(
 9599        &mut self,
 9600        choices: &Vec<String>,
 9601        selection: Range<Anchor>,
 9602        cx: &mut Context<Self>,
 9603    ) {
 9604        let Some((_, buffer, _)) = self
 9605            .buffer()
 9606            .read(cx)
 9607            .excerpt_containing(selection.start, cx)
 9608        else {
 9609            return;
 9610        };
 9611        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9612        else {
 9613            return;
 9614        };
 9615        if buffer != end_buffer {
 9616            log::error!("expected anchor range to have matching buffer IDs");
 9617            return;
 9618        }
 9619
 9620        let id = post_inc(&mut self.next_completion_id);
 9621        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9622        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9623            CompletionsMenu::new_snippet_choices(
 9624                id,
 9625                true,
 9626                choices,
 9627                selection,
 9628                buffer,
 9629                snippet_sort_order,
 9630            ),
 9631        ));
 9632    }
 9633
 9634    pub fn insert_snippet(
 9635        &mut self,
 9636        insertion_ranges: &[Range<usize>],
 9637        snippet: Snippet,
 9638        window: &mut Window,
 9639        cx: &mut Context<Self>,
 9640    ) -> Result<()> {
 9641        struct Tabstop<T> {
 9642            is_end_tabstop: bool,
 9643            ranges: Vec<Range<T>>,
 9644            choices: Option<Vec<String>>,
 9645        }
 9646
 9647        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9648            let snippet_text: Arc<str> = snippet.text.clone().into();
 9649            let edits = insertion_ranges
 9650                .iter()
 9651                .cloned()
 9652                .map(|range| (range, snippet_text.clone()));
 9653            let autoindent_mode = AutoindentMode::Block {
 9654                original_indent_columns: Vec::new(),
 9655            };
 9656            buffer.edit(edits, Some(autoindent_mode), cx);
 9657
 9658            let snapshot = &*buffer.read(cx);
 9659            let snippet = &snippet;
 9660            snippet
 9661                .tabstops
 9662                .iter()
 9663                .map(|tabstop| {
 9664                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9665                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9666                    });
 9667                    let mut tabstop_ranges = tabstop
 9668                        .ranges
 9669                        .iter()
 9670                        .flat_map(|tabstop_range| {
 9671                            let mut delta = 0_isize;
 9672                            insertion_ranges.iter().map(move |insertion_range| {
 9673                                let insertion_start = insertion_range.start as isize + delta;
 9674                                delta +=
 9675                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9676
 9677                                let start = ((insertion_start + tabstop_range.start) as usize)
 9678                                    .min(snapshot.len());
 9679                                let end = ((insertion_start + tabstop_range.end) as usize)
 9680                                    .min(snapshot.len());
 9681                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9682                            })
 9683                        })
 9684                        .collect::<Vec<_>>();
 9685                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9686
 9687                    Tabstop {
 9688                        is_end_tabstop,
 9689                        ranges: tabstop_ranges,
 9690                        choices: tabstop.choices.clone(),
 9691                    }
 9692                })
 9693                .collect::<Vec<_>>()
 9694        });
 9695        if let Some(tabstop) = tabstops.first() {
 9696            self.change_selections(Default::default(), window, cx, |s| {
 9697                // Reverse order so that the first range is the newest created selection.
 9698                // Completions will use it and autoscroll will prioritize it.
 9699                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9700            });
 9701
 9702            if let Some(choices) = &tabstop.choices
 9703                && let Some(selection) = tabstop.ranges.first()
 9704            {
 9705                self.show_snippet_choices(choices, selection.clone(), cx)
 9706            }
 9707
 9708            // If we're already at the last tabstop and it's at the end of the snippet,
 9709            // we're done, we don't need to keep the state around.
 9710            if !tabstop.is_end_tabstop {
 9711                let choices = tabstops
 9712                    .iter()
 9713                    .map(|tabstop| tabstop.choices.clone())
 9714                    .collect();
 9715
 9716                let ranges = tabstops
 9717                    .into_iter()
 9718                    .map(|tabstop| tabstop.ranges)
 9719                    .collect::<Vec<_>>();
 9720
 9721                self.snippet_stack.push(SnippetState {
 9722                    active_index: 0,
 9723                    ranges,
 9724                    choices,
 9725                });
 9726            }
 9727
 9728            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9729            if self.autoclose_regions.is_empty() {
 9730                let snapshot = self.buffer.read(cx).snapshot(cx);
 9731                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
 9732                    let selection_head = selection.head();
 9733                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9734                        continue;
 9735                    };
 9736
 9737                    let mut bracket_pair = None;
 9738                    let max_lookup_length = scope
 9739                        .brackets()
 9740                        .map(|(pair, _)| {
 9741                            pair.start
 9742                                .as_str()
 9743                                .chars()
 9744                                .count()
 9745                                .max(pair.end.as_str().chars().count())
 9746                        })
 9747                        .max();
 9748                    if let Some(max_lookup_length) = max_lookup_length {
 9749                        let next_text = snapshot
 9750                            .chars_at(selection_head)
 9751                            .take(max_lookup_length)
 9752                            .collect::<String>();
 9753                        let prev_text = snapshot
 9754                            .reversed_chars_at(selection_head)
 9755                            .take(max_lookup_length)
 9756                            .collect::<String>();
 9757
 9758                        for (pair, enabled) in scope.brackets() {
 9759                            if enabled
 9760                                && pair.close
 9761                                && prev_text.starts_with(pair.start.as_str())
 9762                                && next_text.starts_with(pair.end.as_str())
 9763                            {
 9764                                bracket_pair = Some(pair.clone());
 9765                                break;
 9766                            }
 9767                        }
 9768                    }
 9769
 9770                    if let Some(pair) = bracket_pair {
 9771                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9772                        let autoclose_enabled =
 9773                            self.use_autoclose && snapshot_settings.use_autoclose;
 9774                        if autoclose_enabled {
 9775                            let start = snapshot.anchor_after(selection_head);
 9776                            let end = snapshot.anchor_after(selection_head);
 9777                            self.autoclose_regions.push(AutocloseRegion {
 9778                                selection_id: selection.id,
 9779                                range: start..end,
 9780                                pair,
 9781                            });
 9782                        }
 9783                    }
 9784                }
 9785            }
 9786        }
 9787        Ok(())
 9788    }
 9789
 9790    pub fn move_to_next_snippet_tabstop(
 9791        &mut self,
 9792        window: &mut Window,
 9793        cx: &mut Context<Self>,
 9794    ) -> bool {
 9795        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9796    }
 9797
 9798    pub fn move_to_prev_snippet_tabstop(
 9799        &mut self,
 9800        window: &mut Window,
 9801        cx: &mut Context<Self>,
 9802    ) -> bool {
 9803        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9804    }
 9805
 9806    pub fn move_to_snippet_tabstop(
 9807        &mut self,
 9808        bias: Bias,
 9809        window: &mut Window,
 9810        cx: &mut Context<Self>,
 9811    ) -> bool {
 9812        if let Some(mut snippet) = self.snippet_stack.pop() {
 9813            match bias {
 9814                Bias::Left => {
 9815                    if snippet.active_index > 0 {
 9816                        snippet.active_index -= 1;
 9817                    } else {
 9818                        self.snippet_stack.push(snippet);
 9819                        return false;
 9820                    }
 9821                }
 9822                Bias::Right => {
 9823                    if snippet.active_index + 1 < snippet.ranges.len() {
 9824                        snippet.active_index += 1;
 9825                    } else {
 9826                        self.snippet_stack.push(snippet);
 9827                        return false;
 9828                    }
 9829                }
 9830            }
 9831            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9832                self.change_selections(Default::default(), window, cx, |s| {
 9833                    // Reverse order so that the first range is the newest created selection.
 9834                    // Completions will use it and autoscroll will prioritize it.
 9835                    s.select_ranges(current_ranges.iter().rev().cloned())
 9836                });
 9837
 9838                if let Some(choices) = &snippet.choices[snippet.active_index]
 9839                    && let Some(selection) = current_ranges.first()
 9840                {
 9841                    self.show_snippet_choices(choices, selection.clone(), cx);
 9842                }
 9843
 9844                // If snippet state is not at the last tabstop, push it back on the stack
 9845                if snippet.active_index + 1 < snippet.ranges.len() {
 9846                    self.snippet_stack.push(snippet);
 9847                }
 9848                return true;
 9849            }
 9850        }
 9851
 9852        false
 9853    }
 9854
 9855    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9856        self.transact(window, cx, |this, window, cx| {
 9857            this.select_all(&SelectAll, window, cx);
 9858            this.insert("", window, cx);
 9859        });
 9860    }
 9861
 9862    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9863        if self.read_only(cx) {
 9864            return;
 9865        }
 9866        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9867        self.transact(window, cx, |this, window, cx| {
 9868            this.select_autoclose_pair(window, cx);
 9869
 9870            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9871
 9872            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9873            if !this.linked_edit_ranges.is_empty() {
 9874                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
 9875                let snapshot = this.buffer.read(cx).snapshot(cx);
 9876
 9877                for selection in selections.iter() {
 9878                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9879                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9880                    if selection_start.buffer_id != selection_end.buffer_id {
 9881                        continue;
 9882                    }
 9883                    if let Some(ranges) =
 9884                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9885                    {
 9886                        for (buffer, entries) in ranges {
 9887                            linked_ranges.entry(buffer).or_default().extend(entries);
 9888                        }
 9889                    }
 9890                }
 9891            }
 9892
 9893            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
 9894            for selection in &mut selections {
 9895                if selection.is_empty() {
 9896                    let old_head = selection.head();
 9897                    let mut new_head =
 9898                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9899                            .to_point(&display_map);
 9900                    if let Some((buffer, line_buffer_range)) = display_map
 9901                        .buffer_snapshot()
 9902                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9903                    {
 9904                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9905                        let indent_len = match indent_size.kind {
 9906                            IndentKind::Space => {
 9907                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9908                            }
 9909                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9910                        };
 9911                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9912                            let indent_len = indent_len.get();
 9913                            new_head = cmp::min(
 9914                                new_head,
 9915                                MultiBufferPoint::new(
 9916                                    old_head.row,
 9917                                    ((old_head.column - 1) / indent_len) * indent_len,
 9918                                ),
 9919                            );
 9920                        }
 9921                    }
 9922
 9923                    selection.set_head(new_head, SelectionGoal::None);
 9924                }
 9925            }
 9926
 9927            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9928            this.insert("", window, cx);
 9929            let empty_str: Arc<str> = Arc::from("");
 9930            for (buffer, edits) in linked_ranges {
 9931                let snapshot = buffer.read(cx).snapshot();
 9932                use text::ToPoint as TP;
 9933
 9934                let edits = edits
 9935                    .into_iter()
 9936                    .map(|range| {
 9937                        let end_point = TP::to_point(&range.end, &snapshot);
 9938                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9939
 9940                        if end_point == start_point {
 9941                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9942                                .saturating_sub(1);
 9943                            start_point =
 9944                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9945                        };
 9946
 9947                        (start_point..end_point, empty_str.clone())
 9948                    })
 9949                    .sorted_by_key(|(range, _)| range.start)
 9950                    .collect::<Vec<_>>();
 9951                buffer.update(cx, |this, cx| {
 9952                    this.edit(edits, None, cx);
 9953                })
 9954            }
 9955            this.refresh_edit_prediction(true, false, window, cx);
 9956            refresh_linked_ranges(this, window, cx);
 9957        });
 9958    }
 9959
 9960    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9961        if self.read_only(cx) {
 9962            return;
 9963        }
 9964        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9965        self.transact(window, cx, |this, window, cx| {
 9966            this.change_selections(Default::default(), window, cx, |s| {
 9967                s.move_with(|map, selection| {
 9968                    if selection.is_empty() {
 9969                        let cursor = movement::right(map, selection.head());
 9970                        selection.end = cursor;
 9971                        selection.reversed = true;
 9972                        selection.goal = SelectionGoal::None;
 9973                    }
 9974                })
 9975            });
 9976            this.insert("", window, cx);
 9977            this.refresh_edit_prediction(true, false, window, cx);
 9978        });
 9979    }
 9980
 9981    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9982        if self.mode.is_single_line() {
 9983            cx.propagate();
 9984            return;
 9985        }
 9986
 9987        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9988        if self.move_to_prev_snippet_tabstop(window, cx) {
 9989            return;
 9990        }
 9991        self.outdent(&Outdent, window, cx);
 9992    }
 9993
 9994    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
 9995        if self.mode.is_single_line() {
 9996            cx.propagate();
 9997            return;
 9998        }
 9999
10000        if self.move_to_next_snippet_tabstop(window, cx) {
10001            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10002            return;
10003        }
10004        if self.read_only(cx) {
10005            return;
10006        }
10007        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10008        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10009        let buffer = self.buffer.read(cx);
10010        let snapshot = buffer.snapshot(cx);
10011        let rows_iter = selections.iter().map(|s| s.head().row);
10012        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10013
10014        let has_some_cursor_in_whitespace = selections
10015            .iter()
10016            .filter(|selection| selection.is_empty())
10017            .any(|selection| {
10018                let cursor = selection.head();
10019                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10020                cursor.column < current_indent.len
10021            });
10022
10023        let mut edits = Vec::new();
10024        let mut prev_edited_row = 0;
10025        let mut row_delta = 0;
10026        for selection in &mut selections {
10027            if selection.start.row != prev_edited_row {
10028                row_delta = 0;
10029            }
10030            prev_edited_row = selection.end.row;
10031
10032            // If the selection is non-empty, then increase the indentation of the selected lines.
10033            if !selection.is_empty() {
10034                row_delta =
10035                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10036                continue;
10037            }
10038
10039            let cursor = selection.head();
10040            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10041            if let Some(suggested_indent) =
10042                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10043            {
10044                // Don't do anything if already at suggested indent
10045                // and there is any other cursor which is not
10046                if has_some_cursor_in_whitespace
10047                    && cursor.column == current_indent.len
10048                    && current_indent.len == suggested_indent.len
10049                {
10050                    continue;
10051                }
10052
10053                // Adjust line and move cursor to suggested indent
10054                // if cursor is not at suggested indent
10055                if cursor.column < suggested_indent.len
10056                    && cursor.column <= current_indent.len
10057                    && current_indent.len <= suggested_indent.len
10058                {
10059                    selection.start = Point::new(cursor.row, suggested_indent.len);
10060                    selection.end = selection.start;
10061                    if row_delta == 0 {
10062                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10063                            cursor.row,
10064                            current_indent,
10065                            suggested_indent,
10066                        ));
10067                        row_delta = suggested_indent.len - current_indent.len;
10068                    }
10069                    continue;
10070                }
10071
10072                // If current indent is more than suggested indent
10073                // only move cursor to current indent and skip indent
10074                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10075                    selection.start = Point::new(cursor.row, current_indent.len);
10076                    selection.end = selection.start;
10077                    continue;
10078                }
10079            }
10080
10081            // Otherwise, insert a hard or soft tab.
10082            let settings = buffer.language_settings_at(cursor, cx);
10083            let tab_size = if settings.hard_tabs {
10084                IndentSize::tab()
10085            } else {
10086                let tab_size = settings.tab_size.get();
10087                let indent_remainder = snapshot
10088                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10089                    .flat_map(str::chars)
10090                    .fold(row_delta % tab_size, |counter: u32, c| {
10091                        if c == '\t' {
10092                            0
10093                        } else {
10094                            (counter + 1) % tab_size
10095                        }
10096                    });
10097
10098                let chars_to_next_tab_stop = tab_size - indent_remainder;
10099                IndentSize::spaces(chars_to_next_tab_stop)
10100            };
10101            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10102            selection.end = selection.start;
10103            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10104            row_delta += tab_size.len;
10105        }
10106
10107        self.transact(window, cx, |this, window, cx| {
10108            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10109            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10110            this.refresh_edit_prediction(true, false, window, cx);
10111        });
10112    }
10113
10114    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10115        if self.read_only(cx) {
10116            return;
10117        }
10118        if self.mode.is_single_line() {
10119            cx.propagate();
10120            return;
10121        }
10122
10123        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10124        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10125        let mut prev_edited_row = 0;
10126        let mut row_delta = 0;
10127        let mut edits = Vec::new();
10128        let buffer = self.buffer.read(cx);
10129        let snapshot = buffer.snapshot(cx);
10130        for selection in &mut selections {
10131            if selection.start.row != prev_edited_row {
10132                row_delta = 0;
10133            }
10134            prev_edited_row = selection.end.row;
10135
10136            row_delta =
10137                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10138        }
10139
10140        self.transact(window, cx, |this, window, cx| {
10141            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10142            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10143        });
10144    }
10145
10146    fn indent_selection(
10147        buffer: &MultiBuffer,
10148        snapshot: &MultiBufferSnapshot,
10149        selection: &mut Selection<Point>,
10150        edits: &mut Vec<(Range<Point>, String)>,
10151        delta_for_start_row: u32,
10152        cx: &App,
10153    ) -> u32 {
10154        let settings = buffer.language_settings_at(selection.start, cx);
10155        let tab_size = settings.tab_size.get();
10156        let indent_kind = if settings.hard_tabs {
10157            IndentKind::Tab
10158        } else {
10159            IndentKind::Space
10160        };
10161        let mut start_row = selection.start.row;
10162        let mut end_row = selection.end.row + 1;
10163
10164        // If a selection ends at the beginning of a line, don't indent
10165        // that last line.
10166        if selection.end.column == 0 && selection.end.row > selection.start.row {
10167            end_row -= 1;
10168        }
10169
10170        // Avoid re-indenting a row that has already been indented by a
10171        // previous selection, but still update this selection's column
10172        // to reflect that indentation.
10173        if delta_for_start_row > 0 {
10174            start_row += 1;
10175            selection.start.column += delta_for_start_row;
10176            if selection.end.row == selection.start.row {
10177                selection.end.column += delta_for_start_row;
10178            }
10179        }
10180
10181        let mut delta_for_end_row = 0;
10182        let has_multiple_rows = start_row + 1 != end_row;
10183        for row in start_row..end_row {
10184            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10185            let indent_delta = match (current_indent.kind, indent_kind) {
10186                (IndentKind::Space, IndentKind::Space) => {
10187                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10188                    IndentSize::spaces(columns_to_next_tab_stop)
10189                }
10190                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10191                (_, IndentKind::Tab) => IndentSize::tab(),
10192            };
10193
10194            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10195                0
10196            } else {
10197                selection.start.column
10198            };
10199            let row_start = Point::new(row, start);
10200            edits.push((
10201                row_start..row_start,
10202                indent_delta.chars().collect::<String>(),
10203            ));
10204
10205            // Update this selection's endpoints to reflect the indentation.
10206            if row == selection.start.row {
10207                selection.start.column += indent_delta.len;
10208            }
10209            if row == selection.end.row {
10210                selection.end.column += indent_delta.len;
10211                delta_for_end_row = indent_delta.len;
10212            }
10213        }
10214
10215        if selection.start.row == selection.end.row {
10216            delta_for_start_row + delta_for_end_row
10217        } else {
10218            delta_for_end_row
10219        }
10220    }
10221
10222    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10223        if self.read_only(cx) {
10224            return;
10225        }
10226        if self.mode.is_single_line() {
10227            cx.propagate();
10228            return;
10229        }
10230
10231        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10232        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10233        let selections = self.selections.all::<Point>(&display_map);
10234        let mut deletion_ranges = Vec::new();
10235        let mut last_outdent = None;
10236        {
10237            let buffer = self.buffer.read(cx);
10238            let snapshot = buffer.snapshot(cx);
10239            for selection in &selections {
10240                let settings = buffer.language_settings_at(selection.start, cx);
10241                let tab_size = settings.tab_size.get();
10242                let mut rows = selection.spanned_rows(false, &display_map);
10243
10244                // Avoid re-outdenting a row that has already been outdented by a
10245                // previous selection.
10246                if let Some(last_row) = last_outdent
10247                    && last_row == rows.start
10248                {
10249                    rows.start = rows.start.next_row();
10250                }
10251                let has_multiple_rows = rows.len() > 1;
10252                for row in rows.iter_rows() {
10253                    let indent_size = snapshot.indent_size_for_line(row);
10254                    if indent_size.len > 0 {
10255                        let deletion_len = match indent_size.kind {
10256                            IndentKind::Space => {
10257                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10258                                if columns_to_prev_tab_stop == 0 {
10259                                    tab_size
10260                                } else {
10261                                    columns_to_prev_tab_stop
10262                                }
10263                            }
10264                            IndentKind::Tab => 1,
10265                        };
10266                        let start = if has_multiple_rows
10267                            || deletion_len > selection.start.column
10268                            || indent_size.len < selection.start.column
10269                        {
10270                            0
10271                        } else {
10272                            selection.start.column - deletion_len
10273                        };
10274                        deletion_ranges.push(
10275                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10276                        );
10277                        last_outdent = Some(row);
10278                    }
10279                }
10280            }
10281        }
10282
10283        self.transact(window, cx, |this, window, cx| {
10284            this.buffer.update(cx, |buffer, cx| {
10285                let empty_str: Arc<str> = Arc::default();
10286                buffer.edit(
10287                    deletion_ranges
10288                        .into_iter()
10289                        .map(|range| (range, empty_str.clone())),
10290                    None,
10291                    cx,
10292                );
10293            });
10294            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10295            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10296        });
10297    }
10298
10299    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10300        if self.read_only(cx) {
10301            return;
10302        }
10303        if self.mode.is_single_line() {
10304            cx.propagate();
10305            return;
10306        }
10307
10308        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10309        let selections = self
10310            .selections
10311            .all::<usize>(&self.display_snapshot(cx))
10312            .into_iter()
10313            .map(|s| s.range());
10314
10315        self.transact(window, cx, |this, window, cx| {
10316            this.buffer.update(cx, |buffer, cx| {
10317                buffer.autoindent_ranges(selections, cx);
10318            });
10319            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10320            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10321        });
10322    }
10323
10324    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10325        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10326        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10327        let selections = self.selections.all::<Point>(&display_map);
10328
10329        let mut new_cursors = Vec::new();
10330        let mut edit_ranges = Vec::new();
10331        let mut selections = selections.iter().peekable();
10332        while let Some(selection) = selections.next() {
10333            let mut rows = selection.spanned_rows(false, &display_map);
10334
10335            // Accumulate contiguous regions of rows that we want to delete.
10336            while let Some(next_selection) = selections.peek() {
10337                let next_rows = next_selection.spanned_rows(false, &display_map);
10338                if next_rows.start <= rows.end {
10339                    rows.end = next_rows.end;
10340                    selections.next().unwrap();
10341                } else {
10342                    break;
10343                }
10344            }
10345
10346            let buffer = display_map.buffer_snapshot();
10347            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10348            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10349                // If there's a line after the range, delete the \n from the end of the row range
10350                (
10351                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10352                    rows.end,
10353                )
10354            } else {
10355                // If there isn't a line after the range, delete the \n from the line before the
10356                // start of the row range
10357                edit_start = edit_start.saturating_sub(1);
10358                (buffer.len(), rows.start.previous_row())
10359            };
10360
10361            let text_layout_details = self.text_layout_details(window);
10362            let x = display_map.x_for_display_point(
10363                selection.head().to_display_point(&display_map),
10364                &text_layout_details,
10365            );
10366            let row = Point::new(target_row.0, 0)
10367                .to_display_point(&display_map)
10368                .row();
10369            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10370
10371            new_cursors.push((
10372                selection.id,
10373                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10374                SelectionGoal::None,
10375            ));
10376            edit_ranges.push(edit_start..edit_end);
10377        }
10378
10379        self.transact(window, cx, |this, window, cx| {
10380            let buffer = this.buffer.update(cx, |buffer, cx| {
10381                let empty_str: Arc<str> = Arc::default();
10382                buffer.edit(
10383                    edit_ranges
10384                        .into_iter()
10385                        .map(|range| (range, empty_str.clone())),
10386                    None,
10387                    cx,
10388                );
10389                buffer.snapshot(cx)
10390            });
10391            let new_selections = new_cursors
10392                .into_iter()
10393                .map(|(id, cursor, goal)| {
10394                    let cursor = cursor.to_point(&buffer);
10395                    Selection {
10396                        id,
10397                        start: cursor,
10398                        end: cursor,
10399                        reversed: false,
10400                        goal,
10401                    }
10402                })
10403                .collect();
10404
10405            this.change_selections(Default::default(), window, cx, |s| {
10406                s.select(new_selections);
10407            });
10408        });
10409    }
10410
10411    pub fn join_lines_impl(
10412        &mut self,
10413        insert_whitespace: bool,
10414        window: &mut Window,
10415        cx: &mut Context<Self>,
10416    ) {
10417        if self.read_only(cx) {
10418            return;
10419        }
10420        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10421        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10422            let start = MultiBufferRow(selection.start.row);
10423            // Treat single line selections as if they include the next line. Otherwise this action
10424            // would do nothing for single line selections individual cursors.
10425            let end = if selection.start.row == selection.end.row {
10426                MultiBufferRow(selection.start.row + 1)
10427            } else {
10428                MultiBufferRow(selection.end.row)
10429            };
10430
10431            if let Some(last_row_range) = row_ranges.last_mut()
10432                && start <= last_row_range.end
10433            {
10434                last_row_range.end = end;
10435                continue;
10436            }
10437            row_ranges.push(start..end);
10438        }
10439
10440        let snapshot = self.buffer.read(cx).snapshot(cx);
10441        let mut cursor_positions = Vec::new();
10442        for row_range in &row_ranges {
10443            let anchor = snapshot.anchor_before(Point::new(
10444                row_range.end.previous_row().0,
10445                snapshot.line_len(row_range.end.previous_row()),
10446            ));
10447            cursor_positions.push(anchor..anchor);
10448        }
10449
10450        self.transact(window, cx, |this, window, cx| {
10451            for row_range in row_ranges.into_iter().rev() {
10452                for row in row_range.iter_rows().rev() {
10453                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10454                    let next_line_row = row.next_row();
10455                    let indent = snapshot.indent_size_for_line(next_line_row);
10456                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10457
10458                    let replace =
10459                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10460                            " "
10461                        } else {
10462                            ""
10463                        };
10464
10465                    this.buffer.update(cx, |buffer, cx| {
10466                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10467                    });
10468                }
10469            }
10470
10471            this.change_selections(Default::default(), window, cx, |s| {
10472                s.select_anchor_ranges(cursor_positions)
10473            });
10474        });
10475    }
10476
10477    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10478        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10479        self.join_lines_impl(true, window, cx);
10480    }
10481
10482    pub fn sort_lines_case_sensitive(
10483        &mut self,
10484        _: &SortLinesCaseSensitive,
10485        window: &mut Window,
10486        cx: &mut Context<Self>,
10487    ) {
10488        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10489    }
10490
10491    pub fn sort_lines_by_length(
10492        &mut self,
10493        _: &SortLinesByLength,
10494        window: &mut Window,
10495        cx: &mut Context<Self>,
10496    ) {
10497        self.manipulate_immutable_lines(window, cx, |lines| {
10498            lines.sort_by_key(|&line| line.chars().count())
10499        })
10500    }
10501
10502    pub fn sort_lines_case_insensitive(
10503        &mut self,
10504        _: &SortLinesCaseInsensitive,
10505        window: &mut Window,
10506        cx: &mut Context<Self>,
10507    ) {
10508        self.manipulate_immutable_lines(window, cx, |lines| {
10509            lines.sort_by_key(|line| line.to_lowercase())
10510        })
10511    }
10512
10513    pub fn unique_lines_case_insensitive(
10514        &mut self,
10515        _: &UniqueLinesCaseInsensitive,
10516        window: &mut Window,
10517        cx: &mut Context<Self>,
10518    ) {
10519        self.manipulate_immutable_lines(window, cx, |lines| {
10520            let mut seen = HashSet::default();
10521            lines.retain(|line| seen.insert(line.to_lowercase()));
10522        })
10523    }
10524
10525    pub fn unique_lines_case_sensitive(
10526        &mut self,
10527        _: &UniqueLinesCaseSensitive,
10528        window: &mut Window,
10529        cx: &mut Context<Self>,
10530    ) {
10531        self.manipulate_immutable_lines(window, cx, |lines| {
10532            let mut seen = HashSet::default();
10533            lines.retain(|line| seen.insert(*line));
10534        })
10535    }
10536
10537    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10538        let snapshot = self.buffer.read(cx).snapshot(cx);
10539        for selection in self.selections.disjoint_anchors_arc().iter() {
10540            if snapshot
10541                .language_at(selection.start)
10542                .and_then(|lang| lang.config().wrap_characters.as_ref())
10543                .is_some()
10544            {
10545                return true;
10546            }
10547        }
10548        false
10549    }
10550
10551    fn wrap_selections_in_tag(
10552        &mut self,
10553        _: &WrapSelectionsInTag,
10554        window: &mut Window,
10555        cx: &mut Context<Self>,
10556    ) {
10557        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10558
10559        let snapshot = self.buffer.read(cx).snapshot(cx);
10560
10561        let mut edits = Vec::new();
10562        let mut boundaries = Vec::new();
10563
10564        for selection in self
10565            .selections
10566            .all_adjusted(&self.display_snapshot(cx))
10567            .iter()
10568        {
10569            let Some(wrap_config) = snapshot
10570                .language_at(selection.start)
10571                .and_then(|lang| lang.config().wrap_characters.clone())
10572            else {
10573                continue;
10574            };
10575
10576            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10577            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10578
10579            let start_before = snapshot.anchor_before(selection.start);
10580            let end_after = snapshot.anchor_after(selection.end);
10581
10582            edits.push((start_before..start_before, open_tag));
10583            edits.push((end_after..end_after, close_tag));
10584
10585            boundaries.push((
10586                start_before,
10587                end_after,
10588                wrap_config.start_prefix.len(),
10589                wrap_config.end_suffix.len(),
10590            ));
10591        }
10592
10593        if edits.is_empty() {
10594            return;
10595        }
10596
10597        self.transact(window, cx, |this, window, cx| {
10598            let buffer = this.buffer.update(cx, |buffer, cx| {
10599                buffer.edit(edits, None, cx);
10600                buffer.snapshot(cx)
10601            });
10602
10603            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10604            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10605                boundaries.into_iter()
10606            {
10607                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10608                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10609                new_selections.push(open_offset..open_offset);
10610                new_selections.push(close_offset..close_offset);
10611            }
10612
10613            this.change_selections(Default::default(), window, cx, |s| {
10614                s.select_ranges(new_selections);
10615            });
10616
10617            this.request_autoscroll(Autoscroll::fit(), cx);
10618        });
10619    }
10620
10621    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10622        let Some(project) = self.project.clone() else {
10623            return;
10624        };
10625        self.reload(project, window, cx)
10626            .detach_and_notify_err(window, cx);
10627    }
10628
10629    pub fn restore_file(
10630        &mut self,
10631        _: &::git::RestoreFile,
10632        window: &mut Window,
10633        cx: &mut Context<Self>,
10634    ) {
10635        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10636        let mut buffer_ids = HashSet::default();
10637        let snapshot = self.buffer().read(cx).snapshot(cx);
10638        for selection in self.selections.all::<usize>(&self.display_snapshot(cx)) {
10639            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10640        }
10641
10642        let buffer = self.buffer().read(cx);
10643        let ranges = buffer_ids
10644            .into_iter()
10645            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10646            .collect::<Vec<_>>();
10647
10648        self.restore_hunks_in_ranges(ranges, window, cx);
10649    }
10650
10651    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10652        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10653        let selections = self
10654            .selections
10655            .all(&self.display_snapshot(cx))
10656            .into_iter()
10657            .map(|s| s.range())
10658            .collect();
10659        self.restore_hunks_in_ranges(selections, window, cx);
10660    }
10661
10662    pub fn restore_hunks_in_ranges(
10663        &mut self,
10664        ranges: Vec<Range<Point>>,
10665        window: &mut Window,
10666        cx: &mut Context<Editor>,
10667    ) {
10668        let mut revert_changes = HashMap::default();
10669        let chunk_by = self
10670            .snapshot(window, cx)
10671            .hunks_for_ranges(ranges)
10672            .into_iter()
10673            .chunk_by(|hunk| hunk.buffer_id);
10674        for (buffer_id, hunks) in &chunk_by {
10675            let hunks = hunks.collect::<Vec<_>>();
10676            for hunk in &hunks {
10677                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10678            }
10679            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10680        }
10681        drop(chunk_by);
10682        if !revert_changes.is_empty() {
10683            self.transact(window, cx, |editor, window, cx| {
10684                editor.restore(revert_changes, window, cx);
10685            });
10686        }
10687    }
10688
10689    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
10690        if let Some(status) = self
10691            .addons
10692            .iter()
10693            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
10694        {
10695            return Some(status);
10696        }
10697        self.project
10698            .as_ref()?
10699            .read(cx)
10700            .status_for_buffer_id(buffer_id, cx)
10701    }
10702
10703    pub fn open_active_item_in_terminal(
10704        &mut self,
10705        _: &OpenInTerminal,
10706        window: &mut Window,
10707        cx: &mut Context<Self>,
10708    ) {
10709        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10710            let project_path = buffer.read(cx).project_path(cx)?;
10711            let project = self.project()?.read(cx);
10712            let entry = project.entry_for_path(&project_path, cx)?;
10713            let parent = match &entry.canonical_path {
10714                Some(canonical_path) => canonical_path.to_path_buf(),
10715                None => project.absolute_path(&project_path, cx)?,
10716            }
10717            .parent()?
10718            .to_path_buf();
10719            Some(parent)
10720        }) {
10721            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10722        }
10723    }
10724
10725    fn set_breakpoint_context_menu(
10726        &mut self,
10727        display_row: DisplayRow,
10728        position: Option<Anchor>,
10729        clicked_point: gpui::Point<Pixels>,
10730        window: &mut Window,
10731        cx: &mut Context<Self>,
10732    ) {
10733        let source = self
10734            .buffer
10735            .read(cx)
10736            .snapshot(cx)
10737            .anchor_before(Point::new(display_row.0, 0u32));
10738
10739        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10740
10741        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10742            self,
10743            source,
10744            clicked_point,
10745            context_menu,
10746            window,
10747            cx,
10748        );
10749    }
10750
10751    fn add_edit_breakpoint_block(
10752        &mut self,
10753        anchor: Anchor,
10754        breakpoint: &Breakpoint,
10755        edit_action: BreakpointPromptEditAction,
10756        window: &mut Window,
10757        cx: &mut Context<Self>,
10758    ) {
10759        let weak_editor = cx.weak_entity();
10760        let bp_prompt = cx.new(|cx| {
10761            BreakpointPromptEditor::new(
10762                weak_editor,
10763                anchor,
10764                breakpoint.clone(),
10765                edit_action,
10766                window,
10767                cx,
10768            )
10769        });
10770
10771        let height = bp_prompt.update(cx, |this, cx| {
10772            this.prompt
10773                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10774        });
10775        let cloned_prompt = bp_prompt.clone();
10776        let blocks = vec![BlockProperties {
10777            style: BlockStyle::Sticky,
10778            placement: BlockPlacement::Above(anchor),
10779            height: Some(height),
10780            render: Arc::new(move |cx| {
10781                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10782                cloned_prompt.clone().into_any_element()
10783            }),
10784            priority: 0,
10785        }];
10786
10787        let focus_handle = bp_prompt.focus_handle(cx);
10788        window.focus(&focus_handle);
10789
10790        let block_ids = self.insert_blocks(blocks, None, cx);
10791        bp_prompt.update(cx, |prompt, _| {
10792            prompt.add_block_ids(block_ids);
10793        });
10794    }
10795
10796    pub(crate) fn breakpoint_at_row(
10797        &self,
10798        row: u32,
10799        window: &mut Window,
10800        cx: &mut Context<Self>,
10801    ) -> Option<(Anchor, Breakpoint)> {
10802        let snapshot = self.snapshot(window, cx);
10803        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
10804
10805        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10806    }
10807
10808    pub(crate) fn breakpoint_at_anchor(
10809        &self,
10810        breakpoint_position: Anchor,
10811        snapshot: &EditorSnapshot,
10812        cx: &mut Context<Self>,
10813    ) -> Option<(Anchor, Breakpoint)> {
10814        let buffer = self
10815            .buffer
10816            .read(cx)
10817            .buffer_for_anchor(breakpoint_position, cx)?;
10818
10819        let enclosing_excerpt = breakpoint_position.excerpt_id;
10820        let buffer_snapshot = buffer.read(cx).snapshot();
10821
10822        let row = buffer_snapshot
10823            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10824            .row;
10825
10826        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
10827        let anchor_end = snapshot
10828            .buffer_snapshot()
10829            .anchor_after(Point::new(row, line_len));
10830
10831        self.breakpoint_store
10832            .as_ref()?
10833            .read_with(cx, |breakpoint_store, cx| {
10834                breakpoint_store
10835                    .breakpoints(
10836                        &buffer,
10837                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10838                        &buffer_snapshot,
10839                        cx,
10840                    )
10841                    .next()
10842                    .and_then(|(bp, _)| {
10843                        let breakpoint_row = buffer_snapshot
10844                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10845                            .row;
10846
10847                        if breakpoint_row == row {
10848                            snapshot
10849                                .buffer_snapshot()
10850                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10851                                .map(|position| (position, bp.bp.clone()))
10852                        } else {
10853                            None
10854                        }
10855                    })
10856            })
10857    }
10858
10859    pub fn edit_log_breakpoint(
10860        &mut self,
10861        _: &EditLogBreakpoint,
10862        window: &mut Window,
10863        cx: &mut Context<Self>,
10864    ) {
10865        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10866            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10867                message: None,
10868                state: BreakpointState::Enabled,
10869                condition: None,
10870                hit_condition: None,
10871            });
10872
10873            self.add_edit_breakpoint_block(
10874                anchor,
10875                &breakpoint,
10876                BreakpointPromptEditAction::Log,
10877                window,
10878                cx,
10879            );
10880        }
10881    }
10882
10883    fn breakpoints_at_cursors(
10884        &self,
10885        window: &mut Window,
10886        cx: &mut Context<Self>,
10887    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10888        let snapshot = self.snapshot(window, cx);
10889        let cursors = self
10890            .selections
10891            .disjoint_anchors_arc()
10892            .iter()
10893            .map(|selection| {
10894                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
10895
10896                let breakpoint_position = self
10897                    .breakpoint_at_row(cursor_position.row, window, cx)
10898                    .map(|bp| bp.0)
10899                    .unwrap_or_else(|| {
10900                        snapshot
10901                            .display_snapshot
10902                            .buffer_snapshot()
10903                            .anchor_after(Point::new(cursor_position.row, 0))
10904                    });
10905
10906                let breakpoint = self
10907                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10908                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10909
10910                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10911            })
10912            // 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.
10913            .collect::<HashMap<Anchor, _>>();
10914
10915        cursors.into_iter().collect()
10916    }
10917
10918    pub fn enable_breakpoint(
10919        &mut self,
10920        _: &crate::actions::EnableBreakpoint,
10921        window: &mut Window,
10922        cx: &mut Context<Self>,
10923    ) {
10924        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10925            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10926                continue;
10927            };
10928            self.edit_breakpoint_at_anchor(
10929                anchor,
10930                breakpoint,
10931                BreakpointEditAction::InvertState,
10932                cx,
10933            );
10934        }
10935    }
10936
10937    pub fn disable_breakpoint(
10938        &mut self,
10939        _: &crate::actions::DisableBreakpoint,
10940        window: &mut Window,
10941        cx: &mut Context<Self>,
10942    ) {
10943        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10944            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10945                continue;
10946            };
10947            self.edit_breakpoint_at_anchor(
10948                anchor,
10949                breakpoint,
10950                BreakpointEditAction::InvertState,
10951                cx,
10952            );
10953        }
10954    }
10955
10956    pub fn toggle_breakpoint(
10957        &mut self,
10958        _: &crate::actions::ToggleBreakpoint,
10959        window: &mut Window,
10960        cx: &mut Context<Self>,
10961    ) {
10962        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10963            if let Some(breakpoint) = breakpoint {
10964                self.edit_breakpoint_at_anchor(
10965                    anchor,
10966                    breakpoint,
10967                    BreakpointEditAction::Toggle,
10968                    cx,
10969                );
10970            } else {
10971                self.edit_breakpoint_at_anchor(
10972                    anchor,
10973                    Breakpoint::new_standard(),
10974                    BreakpointEditAction::Toggle,
10975                    cx,
10976                );
10977            }
10978        }
10979    }
10980
10981    pub fn edit_breakpoint_at_anchor(
10982        &mut self,
10983        breakpoint_position: Anchor,
10984        breakpoint: Breakpoint,
10985        edit_action: BreakpointEditAction,
10986        cx: &mut Context<Self>,
10987    ) {
10988        let Some(breakpoint_store) = &self.breakpoint_store else {
10989            return;
10990        };
10991
10992        let Some(buffer) = self
10993            .buffer
10994            .read(cx)
10995            .buffer_for_anchor(breakpoint_position, cx)
10996        else {
10997            return;
10998        };
10999
11000        breakpoint_store.update(cx, |breakpoint_store, cx| {
11001            breakpoint_store.toggle_breakpoint(
11002                buffer,
11003                BreakpointWithPosition {
11004                    position: breakpoint_position.text_anchor,
11005                    bp: breakpoint,
11006                },
11007                edit_action,
11008                cx,
11009            );
11010        });
11011
11012        cx.notify();
11013    }
11014
11015    #[cfg(any(test, feature = "test-support"))]
11016    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11017        self.breakpoint_store.clone()
11018    }
11019
11020    pub fn prepare_restore_change(
11021        &self,
11022        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11023        hunk: &MultiBufferDiffHunk,
11024        cx: &mut App,
11025    ) -> Option<()> {
11026        if hunk.is_created_file() {
11027            return None;
11028        }
11029        let buffer = self.buffer.read(cx);
11030        let diff = buffer.diff_for(hunk.buffer_id)?;
11031        let buffer = buffer.buffer(hunk.buffer_id)?;
11032        let buffer = buffer.read(cx);
11033        let original_text = diff
11034            .read(cx)
11035            .base_text()
11036            .as_rope()
11037            .slice(hunk.diff_base_byte_range.clone());
11038        let buffer_snapshot = buffer.snapshot();
11039        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11040        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11041            probe
11042                .0
11043                .start
11044                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11045                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11046        }) {
11047            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11048            Some(())
11049        } else {
11050            None
11051        }
11052    }
11053
11054    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11055        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11056    }
11057
11058    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11059        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11060    }
11061
11062    fn manipulate_lines<M>(
11063        &mut self,
11064        window: &mut Window,
11065        cx: &mut Context<Self>,
11066        mut manipulate: M,
11067    ) where
11068        M: FnMut(&str) -> LineManipulationResult,
11069    {
11070        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11071
11072        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11073        let buffer = self.buffer.read(cx).snapshot(cx);
11074
11075        let mut edits = Vec::new();
11076
11077        let selections = self.selections.all::<Point>(&display_map);
11078        let mut selections = selections.iter().peekable();
11079        let mut contiguous_row_selections = Vec::new();
11080        let mut new_selections = Vec::new();
11081        let mut added_lines = 0;
11082        let mut removed_lines = 0;
11083
11084        while let Some(selection) = selections.next() {
11085            let (start_row, end_row) = consume_contiguous_rows(
11086                &mut contiguous_row_selections,
11087                selection,
11088                &display_map,
11089                &mut selections,
11090            );
11091
11092            let start_point = Point::new(start_row.0, 0);
11093            let end_point = Point::new(
11094                end_row.previous_row().0,
11095                buffer.line_len(end_row.previous_row()),
11096            );
11097            let text = buffer
11098                .text_for_range(start_point..end_point)
11099                .collect::<String>();
11100
11101            let LineManipulationResult {
11102                new_text,
11103                line_count_before,
11104                line_count_after,
11105            } = manipulate(&text);
11106
11107            edits.push((start_point..end_point, new_text));
11108
11109            // Selections must change based on added and removed line count
11110            let start_row =
11111                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11112            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11113            new_selections.push(Selection {
11114                id: selection.id,
11115                start: start_row,
11116                end: end_row,
11117                goal: SelectionGoal::None,
11118                reversed: selection.reversed,
11119            });
11120
11121            if line_count_after > line_count_before {
11122                added_lines += line_count_after - line_count_before;
11123            } else if line_count_before > line_count_after {
11124                removed_lines += line_count_before - line_count_after;
11125            }
11126        }
11127
11128        self.transact(window, cx, |this, window, cx| {
11129            let buffer = this.buffer.update(cx, |buffer, cx| {
11130                buffer.edit(edits, None, cx);
11131                buffer.snapshot(cx)
11132            });
11133
11134            // Recalculate offsets on newly edited buffer
11135            let new_selections = new_selections
11136                .iter()
11137                .map(|s| {
11138                    let start_point = Point::new(s.start.0, 0);
11139                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11140                    Selection {
11141                        id: s.id,
11142                        start: buffer.point_to_offset(start_point),
11143                        end: buffer.point_to_offset(end_point),
11144                        goal: s.goal,
11145                        reversed: s.reversed,
11146                    }
11147                })
11148                .collect();
11149
11150            this.change_selections(Default::default(), window, cx, |s| {
11151                s.select(new_selections);
11152            });
11153
11154            this.request_autoscroll(Autoscroll::fit(), cx);
11155        });
11156    }
11157
11158    fn manipulate_immutable_lines<Fn>(
11159        &mut self,
11160        window: &mut Window,
11161        cx: &mut Context<Self>,
11162        mut callback: Fn,
11163    ) where
11164        Fn: FnMut(&mut Vec<&str>),
11165    {
11166        self.manipulate_lines(window, cx, |text| {
11167            let mut lines: Vec<&str> = text.split('\n').collect();
11168            let line_count_before = lines.len();
11169
11170            callback(&mut lines);
11171
11172            LineManipulationResult {
11173                new_text: lines.join("\n"),
11174                line_count_before,
11175                line_count_after: lines.len(),
11176            }
11177        });
11178    }
11179
11180    fn manipulate_mutable_lines<Fn>(
11181        &mut self,
11182        window: &mut Window,
11183        cx: &mut Context<Self>,
11184        mut callback: Fn,
11185    ) where
11186        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11187    {
11188        self.manipulate_lines(window, cx, |text| {
11189            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11190            let line_count_before = lines.len();
11191
11192            callback(&mut lines);
11193
11194            LineManipulationResult {
11195                new_text: lines.join("\n"),
11196                line_count_before,
11197                line_count_after: lines.len(),
11198            }
11199        });
11200    }
11201
11202    pub fn convert_indentation_to_spaces(
11203        &mut self,
11204        _: &ConvertIndentationToSpaces,
11205        window: &mut Window,
11206        cx: &mut Context<Self>,
11207    ) {
11208        let settings = self.buffer.read(cx).language_settings(cx);
11209        let tab_size = settings.tab_size.get() as usize;
11210
11211        self.manipulate_mutable_lines(window, cx, |lines| {
11212            // Allocates a reasonably sized scratch buffer once for the whole loop
11213            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11214            // Avoids recomputing spaces that could be inserted many times
11215            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11216                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11217                .collect();
11218
11219            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11220                let mut chars = line.as_ref().chars();
11221                let mut col = 0;
11222                let mut changed = false;
11223
11224                for ch in chars.by_ref() {
11225                    match ch {
11226                        ' ' => {
11227                            reindented_line.push(' ');
11228                            col += 1;
11229                        }
11230                        '\t' => {
11231                            // \t are converted to spaces depending on the current column
11232                            let spaces_len = tab_size - (col % tab_size);
11233                            reindented_line.extend(&space_cache[spaces_len - 1]);
11234                            col += spaces_len;
11235                            changed = true;
11236                        }
11237                        _ => {
11238                            // If we dont append before break, the character is consumed
11239                            reindented_line.push(ch);
11240                            break;
11241                        }
11242                    }
11243                }
11244
11245                if !changed {
11246                    reindented_line.clear();
11247                    continue;
11248                }
11249                // Append the rest of the line and replace old reference with new one
11250                reindented_line.extend(chars);
11251                *line = Cow::Owned(reindented_line.clone());
11252                reindented_line.clear();
11253            }
11254        });
11255    }
11256
11257    pub fn convert_indentation_to_tabs(
11258        &mut self,
11259        _: &ConvertIndentationToTabs,
11260        window: &mut Window,
11261        cx: &mut Context<Self>,
11262    ) {
11263        let settings = self.buffer.read(cx).language_settings(cx);
11264        let tab_size = settings.tab_size.get() as usize;
11265
11266        self.manipulate_mutable_lines(window, cx, |lines| {
11267            // Allocates a reasonably sized buffer once for the whole loop
11268            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11269            // Avoids recomputing spaces that could be inserted many times
11270            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11271                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11272                .collect();
11273
11274            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11275                let mut chars = line.chars();
11276                let mut spaces_count = 0;
11277                let mut first_non_indent_char = None;
11278                let mut changed = false;
11279
11280                for ch in chars.by_ref() {
11281                    match ch {
11282                        ' ' => {
11283                            // Keep track of spaces. Append \t when we reach tab_size
11284                            spaces_count += 1;
11285                            changed = true;
11286                            if spaces_count == tab_size {
11287                                reindented_line.push('\t');
11288                                spaces_count = 0;
11289                            }
11290                        }
11291                        '\t' => {
11292                            reindented_line.push('\t');
11293                            spaces_count = 0;
11294                        }
11295                        _ => {
11296                            // Dont append it yet, we might have remaining spaces
11297                            first_non_indent_char = Some(ch);
11298                            break;
11299                        }
11300                    }
11301                }
11302
11303                if !changed {
11304                    reindented_line.clear();
11305                    continue;
11306                }
11307                // Remaining spaces that didn't make a full tab stop
11308                if spaces_count > 0 {
11309                    reindented_line.extend(&space_cache[spaces_count - 1]);
11310                }
11311                // If we consume an extra character that was not indentation, add it back
11312                if let Some(extra_char) = first_non_indent_char {
11313                    reindented_line.push(extra_char);
11314                }
11315                // Append the rest of the line and replace old reference with new one
11316                reindented_line.extend(chars);
11317                *line = Cow::Owned(reindented_line.clone());
11318                reindented_line.clear();
11319            }
11320        });
11321    }
11322
11323    pub fn convert_to_upper_case(
11324        &mut self,
11325        _: &ConvertToUpperCase,
11326        window: &mut Window,
11327        cx: &mut Context<Self>,
11328    ) {
11329        self.manipulate_text(window, cx, |text| text.to_uppercase())
11330    }
11331
11332    pub fn convert_to_lower_case(
11333        &mut self,
11334        _: &ConvertToLowerCase,
11335        window: &mut Window,
11336        cx: &mut Context<Self>,
11337    ) {
11338        self.manipulate_text(window, cx, |text| text.to_lowercase())
11339    }
11340
11341    pub fn convert_to_title_case(
11342        &mut self,
11343        _: &ConvertToTitleCase,
11344        window: &mut Window,
11345        cx: &mut Context<Self>,
11346    ) {
11347        self.manipulate_text(window, cx, |text| {
11348            text.split('\n')
11349                .map(|line| line.to_case(Case::Title))
11350                .join("\n")
11351        })
11352    }
11353
11354    pub fn convert_to_snake_case(
11355        &mut self,
11356        _: &ConvertToSnakeCase,
11357        window: &mut Window,
11358        cx: &mut Context<Self>,
11359    ) {
11360        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11361    }
11362
11363    pub fn convert_to_kebab_case(
11364        &mut self,
11365        _: &ConvertToKebabCase,
11366        window: &mut Window,
11367        cx: &mut Context<Self>,
11368    ) {
11369        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11370    }
11371
11372    pub fn convert_to_upper_camel_case(
11373        &mut self,
11374        _: &ConvertToUpperCamelCase,
11375        window: &mut Window,
11376        cx: &mut Context<Self>,
11377    ) {
11378        self.manipulate_text(window, cx, |text| {
11379            text.split('\n')
11380                .map(|line| line.to_case(Case::UpperCamel))
11381                .join("\n")
11382        })
11383    }
11384
11385    pub fn convert_to_lower_camel_case(
11386        &mut self,
11387        _: &ConvertToLowerCamelCase,
11388        window: &mut Window,
11389        cx: &mut Context<Self>,
11390    ) {
11391        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11392    }
11393
11394    pub fn convert_to_opposite_case(
11395        &mut self,
11396        _: &ConvertToOppositeCase,
11397        window: &mut Window,
11398        cx: &mut Context<Self>,
11399    ) {
11400        self.manipulate_text(window, cx, |text| {
11401            text.chars()
11402                .fold(String::with_capacity(text.len()), |mut t, c| {
11403                    if c.is_uppercase() {
11404                        t.extend(c.to_lowercase());
11405                    } else {
11406                        t.extend(c.to_uppercase());
11407                    }
11408                    t
11409                })
11410        })
11411    }
11412
11413    pub fn convert_to_sentence_case(
11414        &mut self,
11415        _: &ConvertToSentenceCase,
11416        window: &mut Window,
11417        cx: &mut Context<Self>,
11418    ) {
11419        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11420    }
11421
11422    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11423        self.manipulate_text(window, cx, |text| {
11424            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11425            if has_upper_case_characters {
11426                text.to_lowercase()
11427            } else {
11428                text.to_uppercase()
11429            }
11430        })
11431    }
11432
11433    pub fn convert_to_rot13(
11434        &mut self,
11435        _: &ConvertToRot13,
11436        window: &mut Window,
11437        cx: &mut Context<Self>,
11438    ) {
11439        self.manipulate_text(window, cx, |text| {
11440            text.chars()
11441                .map(|c| match c {
11442                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11443                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11444                    _ => c,
11445                })
11446                .collect()
11447        })
11448    }
11449
11450    pub fn convert_to_rot47(
11451        &mut self,
11452        _: &ConvertToRot47,
11453        window: &mut Window,
11454        cx: &mut Context<Self>,
11455    ) {
11456        self.manipulate_text(window, cx, |text| {
11457            text.chars()
11458                .map(|c| {
11459                    let code_point = c as u32;
11460                    if code_point >= 33 && code_point <= 126 {
11461                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11462                    }
11463                    c
11464                })
11465                .collect()
11466        })
11467    }
11468
11469    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11470    where
11471        Fn: FnMut(&str) -> String,
11472    {
11473        let buffer = self.buffer.read(cx).snapshot(cx);
11474
11475        let mut new_selections = Vec::new();
11476        let mut edits = Vec::new();
11477        let mut selection_adjustment = 0i32;
11478
11479        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
11480            let selection_is_empty = selection.is_empty();
11481
11482            let (start, end) = if selection_is_empty {
11483                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11484                (word_range.start, word_range.end)
11485            } else {
11486                (
11487                    buffer.point_to_offset(selection.start),
11488                    buffer.point_to_offset(selection.end),
11489                )
11490            };
11491
11492            let text = buffer.text_for_range(start..end).collect::<String>();
11493            let old_length = text.len() as i32;
11494            let text = callback(&text);
11495
11496            new_selections.push(Selection {
11497                start: (start as i32 - selection_adjustment) as usize,
11498                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11499                goal: SelectionGoal::None,
11500                id: selection.id,
11501                reversed: selection.reversed,
11502            });
11503
11504            selection_adjustment += old_length - text.len() as i32;
11505
11506            edits.push((start..end, text));
11507        }
11508
11509        self.transact(window, cx, |this, window, cx| {
11510            this.buffer.update(cx, |buffer, cx| {
11511                buffer.edit(edits, None, cx);
11512            });
11513
11514            this.change_selections(Default::default(), window, cx, |s| {
11515                s.select(new_selections);
11516            });
11517
11518            this.request_autoscroll(Autoscroll::fit(), cx);
11519        });
11520    }
11521
11522    pub fn move_selection_on_drop(
11523        &mut self,
11524        selection: &Selection<Anchor>,
11525        target: DisplayPoint,
11526        is_cut: bool,
11527        window: &mut Window,
11528        cx: &mut Context<Self>,
11529    ) {
11530        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11531        let buffer = display_map.buffer_snapshot();
11532        let mut edits = Vec::new();
11533        let insert_point = display_map
11534            .clip_point(target, Bias::Left)
11535            .to_point(&display_map);
11536        let text = buffer
11537            .text_for_range(selection.start..selection.end)
11538            .collect::<String>();
11539        if is_cut {
11540            edits.push(((selection.start..selection.end), String::new()));
11541        }
11542        let insert_anchor = buffer.anchor_before(insert_point);
11543        edits.push(((insert_anchor..insert_anchor), text));
11544        let last_edit_start = insert_anchor.bias_left(buffer);
11545        let last_edit_end = insert_anchor.bias_right(buffer);
11546        self.transact(window, cx, |this, window, cx| {
11547            this.buffer.update(cx, |buffer, cx| {
11548                buffer.edit(edits, None, cx);
11549            });
11550            this.change_selections(Default::default(), window, cx, |s| {
11551                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11552            });
11553        });
11554    }
11555
11556    pub fn clear_selection_drag_state(&mut self) {
11557        self.selection_drag_state = SelectionDragState::None;
11558    }
11559
11560    pub fn duplicate(
11561        &mut self,
11562        upwards: bool,
11563        whole_lines: bool,
11564        window: &mut Window,
11565        cx: &mut Context<Self>,
11566    ) {
11567        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11568
11569        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11570        let buffer = display_map.buffer_snapshot();
11571        let selections = self.selections.all::<Point>(&display_map);
11572
11573        let mut edits = Vec::new();
11574        let mut selections_iter = selections.iter().peekable();
11575        while let Some(selection) = selections_iter.next() {
11576            let mut rows = selection.spanned_rows(false, &display_map);
11577            // duplicate line-wise
11578            if whole_lines || selection.start == selection.end {
11579                // Avoid duplicating the same lines twice.
11580                while let Some(next_selection) = selections_iter.peek() {
11581                    let next_rows = next_selection.spanned_rows(false, &display_map);
11582                    if next_rows.start < rows.end {
11583                        rows.end = next_rows.end;
11584                        selections_iter.next().unwrap();
11585                    } else {
11586                        break;
11587                    }
11588                }
11589
11590                // Copy the text from the selected row region and splice it either at the start
11591                // or end of the region.
11592                let start = Point::new(rows.start.0, 0);
11593                let end = Point::new(
11594                    rows.end.previous_row().0,
11595                    buffer.line_len(rows.end.previous_row()),
11596                );
11597
11598                let mut text = buffer.text_for_range(start..end).collect::<String>();
11599
11600                let insert_location = if upwards {
11601                    // When duplicating upward, we need to insert before the current line.
11602                    // If we're on the last line and it doesn't end with a newline,
11603                    // we need to add a newline before the duplicated content.
11604                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11605                        && buffer.max_point().column > 0
11606                        && !text.ends_with('\n');
11607
11608                    if needs_leading_newline {
11609                        text.insert(0, '\n');
11610                        end
11611                    } else {
11612                        text.push('\n');
11613                        Point::new(rows.start.0, 0)
11614                    }
11615                } else {
11616                    text.push('\n');
11617                    start
11618                };
11619                edits.push((insert_location..insert_location, text));
11620            } else {
11621                // duplicate character-wise
11622                let start = selection.start;
11623                let end = selection.end;
11624                let text = buffer.text_for_range(start..end).collect::<String>();
11625                edits.push((selection.end..selection.end, text));
11626            }
11627        }
11628
11629        self.transact(window, cx, |this, window, cx| {
11630            this.buffer.update(cx, |buffer, cx| {
11631                buffer.edit(edits, None, cx);
11632            });
11633
11634            // When duplicating upward with whole lines, move the cursor to the duplicated line
11635            if upwards && whole_lines {
11636                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
11637
11638                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11639                    let mut new_ranges = Vec::new();
11640                    let selections = s.all::<Point>(&display_map);
11641                    let mut selections_iter = selections.iter().peekable();
11642
11643                    while let Some(first_selection) = selections_iter.next() {
11644                        // Group contiguous selections together to find the total row span
11645                        let mut group_selections = vec![first_selection];
11646                        let mut rows = first_selection.spanned_rows(false, &display_map);
11647
11648                        while let Some(next_selection) = selections_iter.peek() {
11649                            let next_rows = next_selection.spanned_rows(false, &display_map);
11650                            if next_rows.start < rows.end {
11651                                rows.end = next_rows.end;
11652                                group_selections.push(selections_iter.next().unwrap());
11653                            } else {
11654                                break;
11655                            }
11656                        }
11657
11658                        let row_count = rows.end.0 - rows.start.0;
11659
11660                        // Move all selections in this group up by the total number of duplicated rows
11661                        for selection in group_selections {
11662                            let new_start = Point::new(
11663                                selection.start.row.saturating_sub(row_count),
11664                                selection.start.column,
11665                            );
11666
11667                            let new_end = Point::new(
11668                                selection.end.row.saturating_sub(row_count),
11669                                selection.end.column,
11670                            );
11671
11672                            new_ranges.push(new_start..new_end);
11673                        }
11674                    }
11675
11676                    s.select_ranges(new_ranges);
11677                });
11678            }
11679
11680            this.request_autoscroll(Autoscroll::fit(), cx);
11681        });
11682    }
11683
11684    pub fn duplicate_line_up(
11685        &mut self,
11686        _: &DuplicateLineUp,
11687        window: &mut Window,
11688        cx: &mut Context<Self>,
11689    ) {
11690        self.duplicate(true, true, window, cx);
11691    }
11692
11693    pub fn duplicate_line_down(
11694        &mut self,
11695        _: &DuplicateLineDown,
11696        window: &mut Window,
11697        cx: &mut Context<Self>,
11698    ) {
11699        self.duplicate(false, true, window, cx);
11700    }
11701
11702    pub fn duplicate_selection(
11703        &mut self,
11704        _: &DuplicateSelection,
11705        window: &mut Window,
11706        cx: &mut Context<Self>,
11707    ) {
11708        self.duplicate(false, false, window, cx);
11709    }
11710
11711    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11712        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11713        if self.mode.is_single_line() {
11714            cx.propagate();
11715            return;
11716        }
11717
11718        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11719        let buffer = self.buffer.read(cx).snapshot(cx);
11720
11721        let mut edits = Vec::new();
11722        let mut unfold_ranges = Vec::new();
11723        let mut refold_creases = Vec::new();
11724
11725        let selections = self.selections.all::<Point>(&display_map);
11726        let mut selections = selections.iter().peekable();
11727        let mut contiguous_row_selections = Vec::new();
11728        let mut new_selections = Vec::new();
11729
11730        while let Some(selection) = selections.next() {
11731            // Find all the selections that span a contiguous row range
11732            let (start_row, end_row) = consume_contiguous_rows(
11733                &mut contiguous_row_selections,
11734                selection,
11735                &display_map,
11736                &mut selections,
11737            );
11738
11739            // Move the text spanned by the row range to be before the line preceding the row range
11740            if start_row.0 > 0 {
11741                let range_to_move = Point::new(
11742                    start_row.previous_row().0,
11743                    buffer.line_len(start_row.previous_row()),
11744                )
11745                    ..Point::new(
11746                        end_row.previous_row().0,
11747                        buffer.line_len(end_row.previous_row()),
11748                    );
11749                let insertion_point = display_map
11750                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11751                    .0;
11752
11753                // Don't move lines across excerpts
11754                if buffer
11755                    .excerpt_containing(insertion_point..range_to_move.end)
11756                    .is_some()
11757                {
11758                    let text = buffer
11759                        .text_for_range(range_to_move.clone())
11760                        .flat_map(|s| s.chars())
11761                        .skip(1)
11762                        .chain(['\n'])
11763                        .collect::<String>();
11764
11765                    edits.push((
11766                        buffer.anchor_after(range_to_move.start)
11767                            ..buffer.anchor_before(range_to_move.end),
11768                        String::new(),
11769                    ));
11770                    let insertion_anchor = buffer.anchor_after(insertion_point);
11771                    edits.push((insertion_anchor..insertion_anchor, text));
11772
11773                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11774
11775                    // Move selections up
11776                    new_selections.extend(contiguous_row_selections.drain(..).map(
11777                        |mut selection| {
11778                            selection.start.row -= row_delta;
11779                            selection.end.row -= row_delta;
11780                            selection
11781                        },
11782                    ));
11783
11784                    // Move folds up
11785                    unfold_ranges.push(range_to_move.clone());
11786                    for fold in display_map.folds_in_range(
11787                        buffer.anchor_before(range_to_move.start)
11788                            ..buffer.anchor_after(range_to_move.end),
11789                    ) {
11790                        let mut start = fold.range.start.to_point(&buffer);
11791                        let mut end = fold.range.end.to_point(&buffer);
11792                        start.row -= row_delta;
11793                        end.row -= row_delta;
11794                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11795                    }
11796                }
11797            }
11798
11799            // If we didn't move line(s), preserve the existing selections
11800            new_selections.append(&mut contiguous_row_selections);
11801        }
11802
11803        self.transact(window, cx, |this, window, cx| {
11804            this.unfold_ranges(&unfold_ranges, true, true, cx);
11805            this.buffer.update(cx, |buffer, cx| {
11806                for (range, text) in edits {
11807                    buffer.edit([(range, text)], None, cx);
11808                }
11809            });
11810            this.fold_creases(refold_creases, true, window, cx);
11811            this.change_selections(Default::default(), window, cx, |s| {
11812                s.select(new_selections);
11813            })
11814        });
11815    }
11816
11817    pub fn move_line_down(
11818        &mut self,
11819        _: &MoveLineDown,
11820        window: &mut Window,
11821        cx: &mut Context<Self>,
11822    ) {
11823        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11824        if self.mode.is_single_line() {
11825            cx.propagate();
11826            return;
11827        }
11828
11829        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11830        let buffer = self.buffer.read(cx).snapshot(cx);
11831
11832        let mut edits = Vec::new();
11833        let mut unfold_ranges = Vec::new();
11834        let mut refold_creases = Vec::new();
11835
11836        let selections = self.selections.all::<Point>(&display_map);
11837        let mut selections = selections.iter().peekable();
11838        let mut contiguous_row_selections = Vec::new();
11839        let mut new_selections = Vec::new();
11840
11841        while let Some(selection) = selections.next() {
11842            // Find all the selections that span a contiguous row range
11843            let (start_row, end_row) = consume_contiguous_rows(
11844                &mut contiguous_row_selections,
11845                selection,
11846                &display_map,
11847                &mut selections,
11848            );
11849
11850            // Move the text spanned by the row range to be after the last line of the row range
11851            if end_row.0 <= buffer.max_point().row {
11852                let range_to_move =
11853                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11854                let insertion_point = display_map
11855                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11856                    .0;
11857
11858                // Don't move lines across excerpt boundaries
11859                if buffer
11860                    .excerpt_containing(range_to_move.start..insertion_point)
11861                    .is_some()
11862                {
11863                    let mut text = String::from("\n");
11864                    text.extend(buffer.text_for_range(range_to_move.clone()));
11865                    text.pop(); // Drop trailing newline
11866                    edits.push((
11867                        buffer.anchor_after(range_to_move.start)
11868                            ..buffer.anchor_before(range_to_move.end),
11869                        String::new(),
11870                    ));
11871                    let insertion_anchor = buffer.anchor_after(insertion_point);
11872                    edits.push((insertion_anchor..insertion_anchor, text));
11873
11874                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11875
11876                    // Move selections down
11877                    new_selections.extend(contiguous_row_selections.drain(..).map(
11878                        |mut selection| {
11879                            selection.start.row += row_delta;
11880                            selection.end.row += row_delta;
11881                            selection
11882                        },
11883                    ));
11884
11885                    // Move folds down
11886                    unfold_ranges.push(range_to_move.clone());
11887                    for fold in display_map.folds_in_range(
11888                        buffer.anchor_before(range_to_move.start)
11889                            ..buffer.anchor_after(range_to_move.end),
11890                    ) {
11891                        let mut start = fold.range.start.to_point(&buffer);
11892                        let mut end = fold.range.end.to_point(&buffer);
11893                        start.row += row_delta;
11894                        end.row += row_delta;
11895                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11896                    }
11897                }
11898            }
11899
11900            // If we didn't move line(s), preserve the existing selections
11901            new_selections.append(&mut contiguous_row_selections);
11902        }
11903
11904        self.transact(window, cx, |this, window, cx| {
11905            this.unfold_ranges(&unfold_ranges, true, true, cx);
11906            this.buffer.update(cx, |buffer, cx| {
11907                for (range, text) in edits {
11908                    buffer.edit([(range, text)], None, cx);
11909                }
11910            });
11911            this.fold_creases(refold_creases, true, window, cx);
11912            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11913        });
11914    }
11915
11916    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11917        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11918        let text_layout_details = &self.text_layout_details(window);
11919        self.transact(window, cx, |this, window, cx| {
11920            let edits = this.change_selections(Default::default(), window, cx, |s| {
11921                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11922                s.move_with(|display_map, selection| {
11923                    if !selection.is_empty() {
11924                        return;
11925                    }
11926
11927                    let mut head = selection.head();
11928                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11929                    if head.column() == display_map.line_len(head.row()) {
11930                        transpose_offset = display_map
11931                            .buffer_snapshot()
11932                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11933                    }
11934
11935                    if transpose_offset == 0 {
11936                        return;
11937                    }
11938
11939                    *head.column_mut() += 1;
11940                    head = display_map.clip_point(head, Bias::Right);
11941                    let goal = SelectionGoal::HorizontalPosition(
11942                        display_map
11943                            .x_for_display_point(head, text_layout_details)
11944                            .into(),
11945                    );
11946                    selection.collapse_to(head, goal);
11947
11948                    let transpose_start = display_map
11949                        .buffer_snapshot()
11950                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11951                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11952                        let transpose_end = display_map
11953                            .buffer_snapshot()
11954                            .clip_offset(transpose_offset + 1, Bias::Right);
11955                        if let Some(ch) = display_map
11956                            .buffer_snapshot()
11957                            .chars_at(transpose_start)
11958                            .next()
11959                        {
11960                            edits.push((transpose_start..transpose_offset, String::new()));
11961                            edits.push((transpose_end..transpose_end, ch.to_string()));
11962                        }
11963                    }
11964                });
11965                edits
11966            });
11967            this.buffer
11968                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11969            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
11970            this.change_selections(Default::default(), window, cx, |s| {
11971                s.select(selections);
11972            });
11973        });
11974    }
11975
11976    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11977        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11978        if self.mode.is_single_line() {
11979            cx.propagate();
11980            return;
11981        }
11982
11983        self.rewrap_impl(RewrapOptions::default(), cx)
11984    }
11985
11986    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11987        let buffer = self.buffer.read(cx).snapshot(cx);
11988        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
11989
11990        #[derive(Clone, Debug, PartialEq)]
11991        enum CommentFormat {
11992            /// single line comment, with prefix for line
11993            Line(String),
11994            /// single line within a block comment, with prefix for line
11995            BlockLine(String),
11996            /// a single line of a block comment that includes the initial delimiter
11997            BlockCommentWithStart(BlockCommentConfig),
11998            /// a single line of a block comment that includes the ending delimiter
11999            BlockCommentWithEnd(BlockCommentConfig),
12000        }
12001
12002        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12003        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12004            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12005                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12006                .peekable();
12007
12008            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12009                row
12010            } else {
12011                return Vec::new();
12012            };
12013
12014            let language_settings = buffer.language_settings_at(selection.head(), cx);
12015            let language_scope = buffer.language_scope_at(selection.head());
12016
12017            let indent_and_prefix_for_row =
12018                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12019                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12020                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12021                        &language_scope
12022                    {
12023                        let indent_end = Point::new(row, indent.len);
12024                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12025                        let line_text_after_indent = buffer
12026                            .text_for_range(indent_end..line_end)
12027                            .collect::<String>();
12028
12029                        let is_within_comment_override = buffer
12030                            .language_scope_at(indent_end)
12031                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12032                        let comment_delimiters = if is_within_comment_override {
12033                            // we are within a comment syntax node, but we don't
12034                            // yet know what kind of comment: block, doc or line
12035                            match (
12036                                language_scope.documentation_comment(),
12037                                language_scope.block_comment(),
12038                            ) {
12039                                (Some(config), _) | (_, Some(config))
12040                                    if buffer.contains_str_at(indent_end, &config.start) =>
12041                                {
12042                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12043                                }
12044                                (Some(config), _) | (_, Some(config))
12045                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12046                                {
12047                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12048                                }
12049                                (Some(config), _) | (_, Some(config))
12050                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12051                                {
12052                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12053                                }
12054                                (_, _) => language_scope
12055                                    .line_comment_prefixes()
12056                                    .iter()
12057                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12058                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12059                            }
12060                        } else {
12061                            // we not in an overridden comment node, but we may
12062                            // be within a non-overridden line comment node
12063                            language_scope
12064                                .line_comment_prefixes()
12065                                .iter()
12066                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12067                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12068                        };
12069
12070                        let rewrap_prefix = language_scope
12071                            .rewrap_prefixes()
12072                            .iter()
12073                            .find_map(|prefix_regex| {
12074                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12075                                    if mat.start() == 0 {
12076                                        Some(mat.as_str().to_string())
12077                                    } else {
12078                                        None
12079                                    }
12080                                })
12081                            })
12082                            .flatten();
12083                        (comment_delimiters, rewrap_prefix)
12084                    } else {
12085                        (None, None)
12086                    };
12087                    (indent, comment_prefix, rewrap_prefix)
12088                };
12089
12090            let mut ranges = Vec::new();
12091            let from_empty_selection = selection.is_empty();
12092
12093            let mut current_range_start = first_row;
12094            let mut prev_row = first_row;
12095            let (
12096                mut current_range_indent,
12097                mut current_range_comment_delimiters,
12098                mut current_range_rewrap_prefix,
12099            ) = indent_and_prefix_for_row(first_row);
12100
12101            for row in non_blank_rows_iter.skip(1) {
12102                let has_paragraph_break = row > prev_row + 1;
12103
12104                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12105                    indent_and_prefix_for_row(row);
12106
12107                let has_indent_change = row_indent != current_range_indent;
12108                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12109
12110                let has_boundary_change = has_comment_change
12111                    || row_rewrap_prefix.is_some()
12112                    || (has_indent_change && current_range_comment_delimiters.is_some());
12113
12114                if has_paragraph_break || has_boundary_change {
12115                    ranges.push((
12116                        language_settings.clone(),
12117                        Point::new(current_range_start, 0)
12118                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12119                        current_range_indent,
12120                        current_range_comment_delimiters.clone(),
12121                        current_range_rewrap_prefix.clone(),
12122                        from_empty_selection,
12123                    ));
12124                    current_range_start = row;
12125                    current_range_indent = row_indent;
12126                    current_range_comment_delimiters = row_comment_delimiters;
12127                    current_range_rewrap_prefix = row_rewrap_prefix;
12128                }
12129                prev_row = row;
12130            }
12131
12132            ranges.push((
12133                language_settings.clone(),
12134                Point::new(current_range_start, 0)
12135                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12136                current_range_indent,
12137                current_range_comment_delimiters,
12138                current_range_rewrap_prefix,
12139                from_empty_selection,
12140            ));
12141
12142            ranges
12143        });
12144
12145        let mut edits = Vec::new();
12146        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12147
12148        for (
12149            language_settings,
12150            wrap_range,
12151            mut indent_size,
12152            comment_prefix,
12153            rewrap_prefix,
12154            from_empty_selection,
12155        ) in wrap_ranges
12156        {
12157            let mut start_row = wrap_range.start.row;
12158            let mut end_row = wrap_range.end.row;
12159
12160            // Skip selections that overlap with a range that has already been rewrapped.
12161            let selection_range = start_row..end_row;
12162            if rewrapped_row_ranges
12163                .iter()
12164                .any(|range| range.overlaps(&selection_range))
12165            {
12166                continue;
12167            }
12168
12169            let tab_size = language_settings.tab_size;
12170
12171            let (line_prefix, inside_comment) = match &comment_prefix {
12172                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12173                    (Some(prefix.as_str()), true)
12174                }
12175                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12176                    (Some(prefix.as_ref()), true)
12177                }
12178                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12179                    start: _,
12180                    end: _,
12181                    prefix,
12182                    tab_size,
12183                })) => {
12184                    indent_size.len += tab_size;
12185                    (Some(prefix.as_ref()), true)
12186                }
12187                None => (None, false),
12188            };
12189            let indent_prefix = indent_size.chars().collect::<String>();
12190            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12191
12192            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12193                RewrapBehavior::InComments => inside_comment,
12194                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12195                RewrapBehavior::Anywhere => true,
12196            };
12197
12198            let should_rewrap = options.override_language_settings
12199                || allow_rewrap_based_on_language
12200                || self.hard_wrap.is_some();
12201            if !should_rewrap {
12202                continue;
12203            }
12204
12205            if from_empty_selection {
12206                'expand_upwards: while start_row > 0 {
12207                    let prev_row = start_row - 1;
12208                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12209                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12210                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12211                    {
12212                        start_row = prev_row;
12213                    } else {
12214                        break 'expand_upwards;
12215                    }
12216                }
12217
12218                'expand_downwards: while end_row < buffer.max_point().row {
12219                    let next_row = end_row + 1;
12220                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12221                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12222                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12223                    {
12224                        end_row = next_row;
12225                    } else {
12226                        break 'expand_downwards;
12227                    }
12228                }
12229            }
12230
12231            let start = Point::new(start_row, 0);
12232            let start_offset = ToOffset::to_offset(&start, &buffer);
12233            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12234            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12235            let mut first_line_delimiter = None;
12236            let mut last_line_delimiter = None;
12237            let Some(lines_without_prefixes) = selection_text
12238                .lines()
12239                .enumerate()
12240                .map(|(ix, line)| {
12241                    let line_trimmed = line.trim_start();
12242                    if rewrap_prefix.is_some() && ix > 0 {
12243                        Ok(line_trimmed)
12244                    } else if let Some(
12245                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12246                            start,
12247                            prefix,
12248                            end,
12249                            tab_size,
12250                        })
12251                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12252                            start,
12253                            prefix,
12254                            end,
12255                            tab_size,
12256                        }),
12257                    ) = &comment_prefix
12258                    {
12259                        let line_trimmed = line_trimmed
12260                            .strip_prefix(start.as_ref())
12261                            .map(|s| {
12262                                let mut indent_size = indent_size;
12263                                indent_size.len -= tab_size;
12264                                let indent_prefix: String = indent_size.chars().collect();
12265                                first_line_delimiter = Some((indent_prefix, start));
12266                                s.trim_start()
12267                            })
12268                            .unwrap_or(line_trimmed);
12269                        let line_trimmed = line_trimmed
12270                            .strip_suffix(end.as_ref())
12271                            .map(|s| {
12272                                last_line_delimiter = Some(end);
12273                                s.trim_end()
12274                            })
12275                            .unwrap_or(line_trimmed);
12276                        let line_trimmed = line_trimmed
12277                            .strip_prefix(prefix.as_ref())
12278                            .unwrap_or(line_trimmed);
12279                        Ok(line_trimmed)
12280                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12281                        line_trimmed.strip_prefix(prefix).with_context(|| {
12282                            format!("line did not start with prefix {prefix:?}: {line:?}")
12283                        })
12284                    } else {
12285                        line_trimmed
12286                            .strip_prefix(&line_prefix.trim_start())
12287                            .with_context(|| {
12288                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12289                            })
12290                    }
12291                })
12292                .collect::<Result<Vec<_>, _>>()
12293                .log_err()
12294            else {
12295                continue;
12296            };
12297
12298            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12299                buffer
12300                    .language_settings_at(Point::new(start_row, 0), cx)
12301                    .preferred_line_length as usize
12302            });
12303
12304            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12305                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12306            } else {
12307                line_prefix.clone()
12308            };
12309
12310            let wrapped_text = {
12311                let mut wrapped_text = wrap_with_prefix(
12312                    line_prefix,
12313                    subsequent_lines_prefix,
12314                    lines_without_prefixes.join("\n"),
12315                    wrap_column,
12316                    tab_size,
12317                    options.preserve_existing_whitespace,
12318                );
12319
12320                if let Some((indent, delimiter)) = first_line_delimiter {
12321                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12322                }
12323                if let Some(last_line) = last_line_delimiter {
12324                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12325                }
12326
12327                wrapped_text
12328            };
12329
12330            // TODO: should always use char-based diff while still supporting cursor behavior that
12331            // matches vim.
12332            let mut diff_options = DiffOptions::default();
12333            if options.override_language_settings {
12334                diff_options.max_word_diff_len = 0;
12335                diff_options.max_word_diff_line_count = 0;
12336            } else {
12337                diff_options.max_word_diff_len = usize::MAX;
12338                diff_options.max_word_diff_line_count = usize::MAX;
12339            }
12340
12341            for (old_range, new_text) in
12342                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12343            {
12344                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12345                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12346                edits.push((edit_start..edit_end, new_text));
12347            }
12348
12349            rewrapped_row_ranges.push(start_row..=end_row);
12350        }
12351
12352        self.buffer
12353            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12354    }
12355
12356    pub fn cut_common(
12357        &mut self,
12358        cut_no_selection_line: bool,
12359        window: &mut Window,
12360        cx: &mut Context<Self>,
12361    ) -> ClipboardItem {
12362        let mut text = String::new();
12363        let buffer = self.buffer.read(cx).snapshot(cx);
12364        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12365        let mut clipboard_selections = Vec::with_capacity(selections.len());
12366        {
12367            let max_point = buffer.max_point();
12368            let mut is_first = true;
12369            for selection in &mut selections {
12370                let is_entire_line =
12371                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12372                if is_entire_line {
12373                    selection.start = Point::new(selection.start.row, 0);
12374                    if !selection.is_empty() && selection.end.column == 0 {
12375                        selection.end = cmp::min(max_point, selection.end);
12376                    } else {
12377                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12378                    }
12379                    selection.goal = SelectionGoal::None;
12380                }
12381                if is_first {
12382                    is_first = false;
12383                } else {
12384                    text += "\n";
12385                }
12386                let mut len = 0;
12387                for chunk in buffer.text_for_range(selection.start..selection.end) {
12388                    text.push_str(chunk);
12389                    len += chunk.len();
12390                }
12391                clipboard_selections.push(ClipboardSelection {
12392                    len,
12393                    is_entire_line,
12394                    first_line_indent: buffer
12395                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12396                        .len,
12397                });
12398            }
12399        }
12400
12401        self.transact(window, cx, |this, window, cx| {
12402            this.change_selections(Default::default(), window, cx, |s| {
12403                s.select(selections);
12404            });
12405            this.insert("", window, cx);
12406        });
12407        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12408    }
12409
12410    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12411        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12412        let item = self.cut_common(true, window, cx);
12413        cx.write_to_clipboard(item);
12414    }
12415
12416    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12417        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12418        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12419            s.move_with(|snapshot, sel| {
12420                if sel.is_empty() {
12421                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12422                }
12423                if sel.is_empty() {
12424                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12425                }
12426            });
12427        });
12428        let item = self.cut_common(false, window, cx);
12429        cx.set_global(KillRing(item))
12430    }
12431
12432    pub fn kill_ring_yank(
12433        &mut self,
12434        _: &KillRingYank,
12435        window: &mut Window,
12436        cx: &mut Context<Self>,
12437    ) {
12438        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12439        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12440            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12441                (kill_ring.text().to_string(), kill_ring.metadata_json())
12442            } else {
12443                return;
12444            }
12445        } else {
12446            return;
12447        };
12448        self.do_paste(&text, metadata, false, window, cx);
12449    }
12450
12451    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12452        self.do_copy(true, cx);
12453    }
12454
12455    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12456        self.do_copy(false, cx);
12457    }
12458
12459    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12460        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12461        let buffer = self.buffer.read(cx).read(cx);
12462        let mut text = String::new();
12463
12464        let mut clipboard_selections = Vec::with_capacity(selections.len());
12465        {
12466            let max_point = buffer.max_point();
12467            let mut is_first = true;
12468            for selection in &selections {
12469                let mut start = selection.start;
12470                let mut end = selection.end;
12471                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12472                let mut add_trailing_newline = false;
12473                if is_entire_line {
12474                    start = Point::new(start.row, 0);
12475                    let next_line_start = Point::new(end.row + 1, 0);
12476                    if next_line_start <= max_point {
12477                        end = next_line_start;
12478                    } else {
12479                        // We're on the last line without a trailing newline.
12480                        // Copy to the end of the line and add a newline afterwards.
12481                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12482                        add_trailing_newline = true;
12483                    }
12484                }
12485
12486                let mut trimmed_selections = Vec::new();
12487                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12488                    let row = MultiBufferRow(start.row);
12489                    let first_indent = buffer.indent_size_for_line(row);
12490                    if first_indent.len == 0 || start.column > first_indent.len {
12491                        trimmed_selections.push(start..end);
12492                    } else {
12493                        trimmed_selections.push(
12494                            Point::new(row.0, first_indent.len)
12495                                ..Point::new(row.0, buffer.line_len(row)),
12496                        );
12497                        for row in start.row + 1..=end.row {
12498                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12499                            if row == end.row {
12500                                line_len = end.column;
12501                            }
12502                            if line_len == 0 {
12503                                trimmed_selections
12504                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12505                                continue;
12506                            }
12507                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12508                            if row_indent_size.len >= first_indent.len {
12509                                trimmed_selections.push(
12510                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12511                                );
12512                            } else {
12513                                trimmed_selections.clear();
12514                                trimmed_selections.push(start..end);
12515                                break;
12516                            }
12517                        }
12518                    }
12519                } else {
12520                    trimmed_selections.push(start..end);
12521                }
12522
12523                for trimmed_range in trimmed_selections {
12524                    if is_first {
12525                        is_first = false;
12526                    } else {
12527                        text += "\n";
12528                    }
12529                    let mut len = 0;
12530                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12531                        text.push_str(chunk);
12532                        len += chunk.len();
12533                    }
12534                    if add_trailing_newline {
12535                        text.push('\n');
12536                        len += 1;
12537                    }
12538                    clipboard_selections.push(ClipboardSelection {
12539                        len,
12540                        is_entire_line,
12541                        first_line_indent: buffer
12542                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12543                            .len,
12544                    });
12545                }
12546            }
12547        }
12548
12549        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12550            text,
12551            clipboard_selections,
12552        ));
12553    }
12554
12555    pub fn do_paste(
12556        &mut self,
12557        text: &String,
12558        clipboard_selections: Option<Vec<ClipboardSelection>>,
12559        handle_entire_lines: bool,
12560        window: &mut Window,
12561        cx: &mut Context<Self>,
12562    ) {
12563        if self.read_only(cx) {
12564            return;
12565        }
12566
12567        let clipboard_text = Cow::Borrowed(text.as_str());
12568
12569        self.transact(window, cx, |this, window, cx| {
12570            let had_active_edit_prediction = this.has_active_edit_prediction();
12571            let display_map = this.display_snapshot(cx);
12572            let old_selections = this.selections.all::<usize>(&display_map);
12573            let cursor_offset = this.selections.last::<usize>(&display_map).head();
12574
12575            if let Some(mut clipboard_selections) = clipboard_selections {
12576                let all_selections_were_entire_line =
12577                    clipboard_selections.iter().all(|s| s.is_entire_line);
12578                let first_selection_indent_column =
12579                    clipboard_selections.first().map(|s| s.first_line_indent);
12580                if clipboard_selections.len() != old_selections.len() {
12581                    clipboard_selections.drain(..);
12582                }
12583                let mut auto_indent_on_paste = true;
12584
12585                this.buffer.update(cx, |buffer, cx| {
12586                    let snapshot = buffer.read(cx);
12587                    auto_indent_on_paste = snapshot
12588                        .language_settings_at(cursor_offset, cx)
12589                        .auto_indent_on_paste;
12590
12591                    let mut start_offset = 0;
12592                    let mut edits = Vec::new();
12593                    let mut original_indent_columns = Vec::new();
12594                    for (ix, selection) in old_selections.iter().enumerate() {
12595                        let to_insert;
12596                        let entire_line;
12597                        let original_indent_column;
12598                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12599                            let end_offset = start_offset + clipboard_selection.len;
12600                            to_insert = &clipboard_text[start_offset..end_offset];
12601                            entire_line = clipboard_selection.is_entire_line;
12602                            start_offset = end_offset + 1;
12603                            original_indent_column = Some(clipboard_selection.first_line_indent);
12604                        } else {
12605                            to_insert = &*clipboard_text;
12606                            entire_line = all_selections_were_entire_line;
12607                            original_indent_column = first_selection_indent_column
12608                        }
12609
12610                        let (range, to_insert) =
12611                            if selection.is_empty() && handle_entire_lines && entire_line {
12612                                // If the corresponding selection was empty when this slice of the
12613                                // clipboard text was written, then the entire line containing the
12614                                // selection was copied. If this selection is also currently empty,
12615                                // then paste the line before the current line of the buffer.
12616                                let column = selection.start.to_point(&snapshot).column as usize;
12617                                let line_start = selection.start - column;
12618                                (line_start..line_start, Cow::Borrowed(to_insert))
12619                            } else {
12620                                let language = snapshot.language_at(selection.head());
12621                                let range = selection.range();
12622                                if let Some(language) = language
12623                                    && language.name() == "Markdown".into()
12624                                {
12625                                    edit_for_markdown_paste(
12626                                        &snapshot,
12627                                        range,
12628                                        to_insert,
12629                                        url::Url::parse(to_insert).ok(),
12630                                    )
12631                                } else {
12632                                    (range, Cow::Borrowed(to_insert))
12633                                }
12634                            };
12635
12636                        edits.push((range, to_insert));
12637                        original_indent_columns.push(original_indent_column);
12638                    }
12639                    drop(snapshot);
12640
12641                    buffer.edit(
12642                        edits,
12643                        if auto_indent_on_paste {
12644                            Some(AutoindentMode::Block {
12645                                original_indent_columns,
12646                            })
12647                        } else {
12648                            None
12649                        },
12650                        cx,
12651                    );
12652                });
12653
12654                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12655                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12656            } else {
12657                let url = url::Url::parse(&clipboard_text).ok();
12658
12659                let auto_indent_mode = if !clipboard_text.is_empty() {
12660                    Some(AutoindentMode::Block {
12661                        original_indent_columns: Vec::new(),
12662                    })
12663                } else {
12664                    None
12665                };
12666
12667                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12668                    let snapshot = buffer.snapshot(cx);
12669
12670                    let anchors = old_selections
12671                        .iter()
12672                        .map(|s| {
12673                            let anchor = snapshot.anchor_after(s.head());
12674                            s.map(|_| anchor)
12675                        })
12676                        .collect::<Vec<_>>();
12677
12678                    let mut edits = Vec::new();
12679
12680                    for selection in old_selections.iter() {
12681                        let language = snapshot.language_at(selection.head());
12682                        let range = selection.range();
12683
12684                        let (edit_range, edit_text) = if let Some(language) = language
12685                            && language.name() == "Markdown".into()
12686                        {
12687                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12688                        } else {
12689                            (range, clipboard_text.clone())
12690                        };
12691
12692                        edits.push((edit_range, edit_text));
12693                    }
12694
12695                    drop(snapshot);
12696                    buffer.edit(edits, auto_indent_mode, cx);
12697
12698                    anchors
12699                });
12700
12701                this.change_selections(Default::default(), window, cx, |s| {
12702                    s.select_anchors(selection_anchors);
12703                });
12704            }
12705
12706            let trigger_in_words =
12707                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12708
12709            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12710        });
12711    }
12712
12713    pub fn diff_clipboard_with_selection(
12714        &mut self,
12715        _: &DiffClipboardWithSelection,
12716        window: &mut Window,
12717        cx: &mut Context<Self>,
12718    ) {
12719        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
12720
12721        if selections.is_empty() {
12722            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12723            return;
12724        };
12725
12726        let clipboard_text = match cx.read_from_clipboard() {
12727            Some(item) => match item.entries().first() {
12728                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12729                _ => None,
12730            },
12731            None => None,
12732        };
12733
12734        let Some(clipboard_text) = clipboard_text else {
12735            log::warn!("Clipboard doesn't contain text.");
12736            return;
12737        };
12738
12739        window.dispatch_action(
12740            Box::new(DiffClipboardWithSelectionData {
12741                clipboard_text,
12742                editor: cx.entity(),
12743            }),
12744            cx,
12745        );
12746    }
12747
12748    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12749        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12750        if let Some(item) = cx.read_from_clipboard() {
12751            let entries = item.entries();
12752
12753            match entries.first() {
12754                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12755                // of all the pasted entries.
12756                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12757                    .do_paste(
12758                        clipboard_string.text(),
12759                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12760                        true,
12761                        window,
12762                        cx,
12763                    ),
12764                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12765            }
12766        }
12767    }
12768
12769    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12770        if self.read_only(cx) {
12771            return;
12772        }
12773
12774        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12775
12776        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12777            if let Some((selections, _)) =
12778                self.selection_history.transaction(transaction_id).cloned()
12779            {
12780                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12781                    s.select_anchors(selections.to_vec());
12782                });
12783            } else {
12784                log::error!(
12785                    "No entry in selection_history found for undo. \
12786                     This may correspond to a bug where undo does not update the selection. \
12787                     If this is occurring, please add details to \
12788                     https://github.com/zed-industries/zed/issues/22692"
12789                );
12790            }
12791            self.request_autoscroll(Autoscroll::fit(), cx);
12792            self.unmark_text(window, cx);
12793            self.refresh_edit_prediction(true, false, window, cx);
12794            cx.emit(EditorEvent::Edited { transaction_id });
12795            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12796        }
12797    }
12798
12799    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12800        if self.read_only(cx) {
12801            return;
12802        }
12803
12804        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12805
12806        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12807            if let Some((_, Some(selections))) =
12808                self.selection_history.transaction(transaction_id).cloned()
12809            {
12810                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12811                    s.select_anchors(selections.to_vec());
12812                });
12813            } else {
12814                log::error!(
12815                    "No entry in selection_history found for redo. \
12816                     This may correspond to a bug where undo does not update the selection. \
12817                     If this is occurring, please add details to \
12818                     https://github.com/zed-industries/zed/issues/22692"
12819                );
12820            }
12821            self.request_autoscroll(Autoscroll::fit(), cx);
12822            self.unmark_text(window, cx);
12823            self.refresh_edit_prediction(true, false, window, cx);
12824            cx.emit(EditorEvent::Edited { transaction_id });
12825        }
12826    }
12827
12828    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12829        self.buffer
12830            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12831    }
12832
12833    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12834        self.buffer
12835            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12836    }
12837
12838    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12839        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12840        self.change_selections(Default::default(), window, cx, |s| {
12841            s.move_with(|map, selection| {
12842                let cursor = if selection.is_empty() {
12843                    movement::left(map, selection.start)
12844                } else {
12845                    selection.start
12846                };
12847                selection.collapse_to(cursor, SelectionGoal::None);
12848            });
12849        })
12850    }
12851
12852    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12853        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12854        self.change_selections(Default::default(), window, cx, |s| {
12855            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12856        })
12857    }
12858
12859    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12860        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12861        self.change_selections(Default::default(), window, cx, |s| {
12862            s.move_with(|map, selection| {
12863                let cursor = if selection.is_empty() {
12864                    movement::right(map, selection.end)
12865                } else {
12866                    selection.end
12867                };
12868                selection.collapse_to(cursor, SelectionGoal::None)
12869            });
12870        })
12871    }
12872
12873    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12874        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12875        self.change_selections(Default::default(), window, cx, |s| {
12876            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12877        });
12878    }
12879
12880    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12881        if self.take_rename(true, window, cx).is_some() {
12882            return;
12883        }
12884
12885        if self.mode.is_single_line() {
12886            cx.propagate();
12887            return;
12888        }
12889
12890        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12891
12892        let text_layout_details = &self.text_layout_details(window);
12893        let selection_count = self.selections.count();
12894        let first_selection = self.selections.first_anchor();
12895
12896        self.change_selections(Default::default(), window, cx, |s| {
12897            s.move_with(|map, selection| {
12898                if !selection.is_empty() {
12899                    selection.goal = SelectionGoal::None;
12900                }
12901                let (cursor, goal) = movement::up(
12902                    map,
12903                    selection.start,
12904                    selection.goal,
12905                    false,
12906                    text_layout_details,
12907                );
12908                selection.collapse_to(cursor, goal);
12909            });
12910        });
12911
12912        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12913        {
12914            cx.propagate();
12915        }
12916    }
12917
12918    pub fn move_up_by_lines(
12919        &mut self,
12920        action: &MoveUpByLines,
12921        window: &mut Window,
12922        cx: &mut Context<Self>,
12923    ) {
12924        if self.take_rename(true, window, cx).is_some() {
12925            return;
12926        }
12927
12928        if self.mode.is_single_line() {
12929            cx.propagate();
12930            return;
12931        }
12932
12933        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12934
12935        let text_layout_details = &self.text_layout_details(window);
12936
12937        self.change_selections(Default::default(), window, cx, |s| {
12938            s.move_with(|map, selection| {
12939                if !selection.is_empty() {
12940                    selection.goal = SelectionGoal::None;
12941                }
12942                let (cursor, goal) = movement::up_by_rows(
12943                    map,
12944                    selection.start,
12945                    action.lines,
12946                    selection.goal,
12947                    false,
12948                    text_layout_details,
12949                );
12950                selection.collapse_to(cursor, goal);
12951            });
12952        })
12953    }
12954
12955    pub fn move_down_by_lines(
12956        &mut self,
12957        action: &MoveDownByLines,
12958        window: &mut Window,
12959        cx: &mut Context<Self>,
12960    ) {
12961        if self.take_rename(true, window, cx).is_some() {
12962            return;
12963        }
12964
12965        if self.mode.is_single_line() {
12966            cx.propagate();
12967            return;
12968        }
12969
12970        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12971
12972        let text_layout_details = &self.text_layout_details(window);
12973
12974        self.change_selections(Default::default(), window, cx, |s| {
12975            s.move_with(|map, selection| {
12976                if !selection.is_empty() {
12977                    selection.goal = SelectionGoal::None;
12978                }
12979                let (cursor, goal) = movement::down_by_rows(
12980                    map,
12981                    selection.start,
12982                    action.lines,
12983                    selection.goal,
12984                    false,
12985                    text_layout_details,
12986                );
12987                selection.collapse_to(cursor, goal);
12988            });
12989        })
12990    }
12991
12992    pub fn select_down_by_lines(
12993        &mut self,
12994        action: &SelectDownByLines,
12995        window: &mut Window,
12996        cx: &mut Context<Self>,
12997    ) {
12998        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12999        let text_layout_details = &self.text_layout_details(window);
13000        self.change_selections(Default::default(), window, cx, |s| {
13001            s.move_heads_with(|map, head, goal| {
13002                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13003            })
13004        })
13005    }
13006
13007    pub fn select_up_by_lines(
13008        &mut self,
13009        action: &SelectUpByLines,
13010        window: &mut Window,
13011        cx: &mut Context<Self>,
13012    ) {
13013        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13014        let text_layout_details = &self.text_layout_details(window);
13015        self.change_selections(Default::default(), window, cx, |s| {
13016            s.move_heads_with(|map, head, goal| {
13017                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13018            })
13019        })
13020    }
13021
13022    pub fn select_page_up(
13023        &mut self,
13024        _: &SelectPageUp,
13025        window: &mut Window,
13026        cx: &mut Context<Self>,
13027    ) {
13028        let Some(row_count) = self.visible_row_count() else {
13029            return;
13030        };
13031
13032        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13033
13034        let text_layout_details = &self.text_layout_details(window);
13035
13036        self.change_selections(Default::default(), window, cx, |s| {
13037            s.move_heads_with(|map, head, goal| {
13038                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13039            })
13040        })
13041    }
13042
13043    pub fn move_page_up(
13044        &mut self,
13045        action: &MovePageUp,
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
13054            .context_menu
13055            .borrow_mut()
13056            .as_mut()
13057            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13058            .unwrap_or(false)
13059        {
13060            return;
13061        }
13062
13063        if matches!(self.mode, EditorMode::SingleLine) {
13064            cx.propagate();
13065            return;
13066        }
13067
13068        let Some(row_count) = self.visible_row_count() else {
13069            return;
13070        };
13071
13072        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13073
13074        let effects = if action.center_cursor {
13075            SelectionEffects::scroll(Autoscroll::center())
13076        } else {
13077            SelectionEffects::default()
13078        };
13079
13080        let text_layout_details = &self.text_layout_details(window);
13081
13082        self.change_selections(effects, window, cx, |s| {
13083            s.move_with(|map, selection| {
13084                if !selection.is_empty() {
13085                    selection.goal = SelectionGoal::None;
13086                }
13087                let (cursor, goal) = movement::up_by_rows(
13088                    map,
13089                    selection.end,
13090                    row_count,
13091                    selection.goal,
13092                    false,
13093                    text_layout_details,
13094                );
13095                selection.collapse_to(cursor, goal);
13096            });
13097        });
13098    }
13099
13100    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13101        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13102        let text_layout_details = &self.text_layout_details(window);
13103        self.change_selections(Default::default(), window, cx, |s| {
13104            s.move_heads_with(|map, head, goal| {
13105                movement::up(map, head, goal, false, text_layout_details)
13106            })
13107        })
13108    }
13109
13110    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13111        self.take_rename(true, window, cx);
13112
13113        if self.mode.is_single_line() {
13114            cx.propagate();
13115            return;
13116        }
13117
13118        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13119
13120        let text_layout_details = &self.text_layout_details(window);
13121        let selection_count = self.selections.count();
13122        let first_selection = self.selections.first_anchor();
13123
13124        self.change_selections(Default::default(), window, cx, |s| {
13125            s.move_with(|map, selection| {
13126                if !selection.is_empty() {
13127                    selection.goal = SelectionGoal::None;
13128                }
13129                let (cursor, goal) = movement::down(
13130                    map,
13131                    selection.end,
13132                    selection.goal,
13133                    false,
13134                    text_layout_details,
13135                );
13136                selection.collapse_to(cursor, goal);
13137            });
13138        });
13139
13140        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13141        {
13142            cx.propagate();
13143        }
13144    }
13145
13146    pub fn select_page_down(
13147        &mut self,
13148        _: &SelectPageDown,
13149        window: &mut Window,
13150        cx: &mut Context<Self>,
13151    ) {
13152        let Some(row_count) = self.visible_row_count() else {
13153            return;
13154        };
13155
13156        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13157
13158        let text_layout_details = &self.text_layout_details(window);
13159
13160        self.change_selections(Default::default(), window, cx, |s| {
13161            s.move_heads_with(|map, head, goal| {
13162                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13163            })
13164        })
13165    }
13166
13167    pub fn move_page_down(
13168        &mut self,
13169        action: &MovePageDown,
13170        window: &mut Window,
13171        cx: &mut Context<Self>,
13172    ) {
13173        if self.take_rename(true, window, cx).is_some() {
13174            return;
13175        }
13176
13177        if self
13178            .context_menu
13179            .borrow_mut()
13180            .as_mut()
13181            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13182            .unwrap_or(false)
13183        {
13184            return;
13185        }
13186
13187        if matches!(self.mode, EditorMode::SingleLine) {
13188            cx.propagate();
13189            return;
13190        }
13191
13192        let Some(row_count) = self.visible_row_count() else {
13193            return;
13194        };
13195
13196        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13197
13198        let effects = if action.center_cursor {
13199            SelectionEffects::scroll(Autoscroll::center())
13200        } else {
13201            SelectionEffects::default()
13202        };
13203
13204        let text_layout_details = &self.text_layout_details(window);
13205        self.change_selections(effects, window, cx, |s| {
13206            s.move_with(|map, selection| {
13207                if !selection.is_empty() {
13208                    selection.goal = SelectionGoal::None;
13209                }
13210                let (cursor, goal) = movement::down_by_rows(
13211                    map,
13212                    selection.end,
13213                    row_count,
13214                    selection.goal,
13215                    false,
13216                    text_layout_details,
13217                );
13218                selection.collapse_to(cursor, goal);
13219            });
13220        });
13221    }
13222
13223    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13224        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13225        let text_layout_details = &self.text_layout_details(window);
13226        self.change_selections(Default::default(), window, cx, |s| {
13227            s.move_heads_with(|map, head, goal| {
13228                movement::down(map, head, goal, false, text_layout_details)
13229            })
13230        });
13231    }
13232
13233    pub fn context_menu_first(
13234        &mut self,
13235        _: &ContextMenuFirst,
13236        window: &mut Window,
13237        cx: &mut Context<Self>,
13238    ) {
13239        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13240            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13241        }
13242    }
13243
13244    pub fn context_menu_prev(
13245        &mut self,
13246        _: &ContextMenuPrevious,
13247        window: &mut Window,
13248        cx: &mut Context<Self>,
13249    ) {
13250        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13251            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13252        }
13253    }
13254
13255    pub fn context_menu_next(
13256        &mut self,
13257        _: &ContextMenuNext,
13258        window: &mut Window,
13259        cx: &mut Context<Self>,
13260    ) {
13261        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13262            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13263        }
13264    }
13265
13266    pub fn context_menu_last(
13267        &mut self,
13268        _: &ContextMenuLast,
13269        window: &mut Window,
13270        cx: &mut Context<Self>,
13271    ) {
13272        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13273            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13274        }
13275    }
13276
13277    pub fn signature_help_prev(
13278        &mut self,
13279        _: &SignatureHelpPrevious,
13280        _: &mut Window,
13281        cx: &mut Context<Self>,
13282    ) {
13283        if let Some(popover) = self.signature_help_state.popover_mut() {
13284            if popover.current_signature == 0 {
13285                popover.current_signature = popover.signatures.len() - 1;
13286            } else {
13287                popover.current_signature -= 1;
13288            }
13289            cx.notify();
13290        }
13291    }
13292
13293    pub fn signature_help_next(
13294        &mut self,
13295        _: &SignatureHelpNext,
13296        _: &mut Window,
13297        cx: &mut Context<Self>,
13298    ) {
13299        if let Some(popover) = self.signature_help_state.popover_mut() {
13300            if popover.current_signature + 1 == popover.signatures.len() {
13301                popover.current_signature = 0;
13302            } else {
13303                popover.current_signature += 1;
13304            }
13305            cx.notify();
13306        }
13307    }
13308
13309    pub fn move_to_previous_word_start(
13310        &mut self,
13311        _: &MoveToPreviousWordStart,
13312        window: &mut Window,
13313        cx: &mut Context<Self>,
13314    ) {
13315        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13316        self.change_selections(Default::default(), window, cx, |s| {
13317            s.move_cursors_with(|map, head, _| {
13318                (
13319                    movement::previous_word_start(map, head),
13320                    SelectionGoal::None,
13321                )
13322            });
13323        })
13324    }
13325
13326    pub fn move_to_previous_subword_start(
13327        &mut self,
13328        _: &MoveToPreviousSubwordStart,
13329        window: &mut Window,
13330        cx: &mut Context<Self>,
13331    ) {
13332        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13333        self.change_selections(Default::default(), window, cx, |s| {
13334            s.move_cursors_with(|map, head, _| {
13335                (
13336                    movement::previous_subword_start(map, head),
13337                    SelectionGoal::None,
13338                )
13339            });
13340        })
13341    }
13342
13343    pub fn select_to_previous_word_start(
13344        &mut self,
13345        _: &SelectToPreviousWordStart,
13346        window: &mut Window,
13347        cx: &mut Context<Self>,
13348    ) {
13349        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13350        self.change_selections(Default::default(), window, cx, |s| {
13351            s.move_heads_with(|map, head, _| {
13352                (
13353                    movement::previous_word_start(map, head),
13354                    SelectionGoal::None,
13355                )
13356            });
13357        })
13358    }
13359
13360    pub fn select_to_previous_subword_start(
13361        &mut self,
13362        _: &SelectToPreviousSubwordStart,
13363        window: &mut Window,
13364        cx: &mut Context<Self>,
13365    ) {
13366        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13367        self.change_selections(Default::default(), window, cx, |s| {
13368            s.move_heads_with(|map, head, _| {
13369                (
13370                    movement::previous_subword_start(map, head),
13371                    SelectionGoal::None,
13372                )
13373            });
13374        })
13375    }
13376
13377    pub fn delete_to_previous_word_start(
13378        &mut self,
13379        action: &DeleteToPreviousWordStart,
13380        window: &mut Window,
13381        cx: &mut Context<Self>,
13382    ) {
13383        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13384        self.transact(window, cx, |this, window, cx| {
13385            this.select_autoclose_pair(window, cx);
13386            this.change_selections(Default::default(), window, cx, |s| {
13387                s.move_with(|map, selection| {
13388                    if selection.is_empty() {
13389                        let mut cursor = if action.ignore_newlines {
13390                            movement::previous_word_start(map, selection.head())
13391                        } else {
13392                            movement::previous_word_start_or_newline(map, selection.head())
13393                        };
13394                        cursor = movement::adjust_greedy_deletion(
13395                            map,
13396                            selection.head(),
13397                            cursor,
13398                            action.ignore_brackets,
13399                        );
13400                        selection.set_head(cursor, SelectionGoal::None);
13401                    }
13402                });
13403            });
13404            this.insert("", window, cx);
13405        });
13406    }
13407
13408    pub fn delete_to_previous_subword_start(
13409        &mut self,
13410        _: &DeleteToPreviousSubwordStart,
13411        window: &mut Window,
13412        cx: &mut Context<Self>,
13413    ) {
13414        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13415        self.transact(window, cx, |this, window, cx| {
13416            this.select_autoclose_pair(window, cx);
13417            this.change_selections(Default::default(), window, cx, |s| {
13418                s.move_with(|map, selection| {
13419                    if selection.is_empty() {
13420                        let mut cursor = movement::previous_subword_start(map, selection.head());
13421                        cursor =
13422                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13423                        selection.set_head(cursor, SelectionGoal::None);
13424                    }
13425                });
13426            });
13427            this.insert("", window, cx);
13428        });
13429    }
13430
13431    pub fn move_to_next_word_end(
13432        &mut self,
13433        _: &MoveToNextWordEnd,
13434        window: &mut Window,
13435        cx: &mut Context<Self>,
13436    ) {
13437        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13438        self.change_selections(Default::default(), window, cx, |s| {
13439            s.move_cursors_with(|map, head, _| {
13440                (movement::next_word_end(map, head), SelectionGoal::None)
13441            });
13442        })
13443    }
13444
13445    pub fn move_to_next_subword_end(
13446        &mut self,
13447        _: &MoveToNextSubwordEnd,
13448        window: &mut Window,
13449        cx: &mut Context<Self>,
13450    ) {
13451        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13452        self.change_selections(Default::default(), window, cx, |s| {
13453            s.move_cursors_with(|map, head, _| {
13454                (movement::next_subword_end(map, head), SelectionGoal::None)
13455            });
13456        })
13457    }
13458
13459    pub fn select_to_next_word_end(
13460        &mut self,
13461        _: &SelectToNextWordEnd,
13462        window: &mut Window,
13463        cx: &mut Context<Self>,
13464    ) {
13465        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13466        self.change_selections(Default::default(), window, cx, |s| {
13467            s.move_heads_with(|map, head, _| {
13468                (movement::next_word_end(map, head), SelectionGoal::None)
13469            });
13470        })
13471    }
13472
13473    pub fn select_to_next_subword_end(
13474        &mut self,
13475        _: &SelectToNextSubwordEnd,
13476        window: &mut Window,
13477        cx: &mut Context<Self>,
13478    ) {
13479        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13480        self.change_selections(Default::default(), window, cx, |s| {
13481            s.move_heads_with(|map, head, _| {
13482                (movement::next_subword_end(map, head), SelectionGoal::None)
13483            });
13484        })
13485    }
13486
13487    pub fn delete_to_next_word_end(
13488        &mut self,
13489        action: &DeleteToNextWordEnd,
13490        window: &mut Window,
13491        cx: &mut Context<Self>,
13492    ) {
13493        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13494        self.transact(window, cx, |this, window, cx| {
13495            this.change_selections(Default::default(), window, cx, |s| {
13496                s.move_with(|map, selection| {
13497                    if selection.is_empty() {
13498                        let mut cursor = if action.ignore_newlines {
13499                            movement::next_word_end(map, selection.head())
13500                        } else {
13501                            movement::next_word_end_or_newline(map, selection.head())
13502                        };
13503                        cursor = movement::adjust_greedy_deletion(
13504                            map,
13505                            selection.head(),
13506                            cursor,
13507                            action.ignore_brackets,
13508                        );
13509                        selection.set_head(cursor, SelectionGoal::None);
13510                    }
13511                });
13512            });
13513            this.insert("", window, cx);
13514        });
13515    }
13516
13517    pub fn delete_to_next_subword_end(
13518        &mut self,
13519        _: &DeleteToNextSubwordEnd,
13520        window: &mut Window,
13521        cx: &mut Context<Self>,
13522    ) {
13523        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13524        self.transact(window, cx, |this, window, cx| {
13525            this.change_selections(Default::default(), window, cx, |s| {
13526                s.move_with(|map, selection| {
13527                    if selection.is_empty() {
13528                        let mut cursor = movement::next_subword_end(map, selection.head());
13529                        cursor =
13530                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13531                        selection.set_head(cursor, SelectionGoal::None);
13532                    }
13533                });
13534            });
13535            this.insert("", window, cx);
13536        });
13537    }
13538
13539    pub fn move_to_beginning_of_line(
13540        &mut self,
13541        action: &MoveToBeginningOfLine,
13542        window: &mut Window,
13543        cx: &mut Context<Self>,
13544    ) {
13545        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13546        self.change_selections(Default::default(), window, cx, |s| {
13547            s.move_cursors_with(|map, head, _| {
13548                (
13549                    movement::indented_line_beginning(
13550                        map,
13551                        head,
13552                        action.stop_at_soft_wraps,
13553                        action.stop_at_indent,
13554                    ),
13555                    SelectionGoal::None,
13556                )
13557            });
13558        })
13559    }
13560
13561    pub fn select_to_beginning_of_line(
13562        &mut self,
13563        action: &SelectToBeginningOfLine,
13564        window: &mut Window,
13565        cx: &mut Context<Self>,
13566    ) {
13567        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13568        self.change_selections(Default::default(), window, cx, |s| {
13569            s.move_heads_with(|map, head, _| {
13570                (
13571                    movement::indented_line_beginning(
13572                        map,
13573                        head,
13574                        action.stop_at_soft_wraps,
13575                        action.stop_at_indent,
13576                    ),
13577                    SelectionGoal::None,
13578                )
13579            });
13580        });
13581    }
13582
13583    pub fn delete_to_beginning_of_line(
13584        &mut self,
13585        action: &DeleteToBeginningOfLine,
13586        window: &mut Window,
13587        cx: &mut Context<Self>,
13588    ) {
13589        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13590        self.transact(window, cx, |this, window, cx| {
13591            this.change_selections(Default::default(), window, cx, |s| {
13592                s.move_with(|_, selection| {
13593                    selection.reversed = true;
13594                });
13595            });
13596
13597            this.select_to_beginning_of_line(
13598                &SelectToBeginningOfLine {
13599                    stop_at_soft_wraps: false,
13600                    stop_at_indent: action.stop_at_indent,
13601                },
13602                window,
13603                cx,
13604            );
13605            this.backspace(&Backspace, window, cx);
13606        });
13607    }
13608
13609    pub fn move_to_end_of_line(
13610        &mut self,
13611        action: &MoveToEndOfLine,
13612        window: &mut Window,
13613        cx: &mut Context<Self>,
13614    ) {
13615        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13616        self.change_selections(Default::default(), window, cx, |s| {
13617            s.move_cursors_with(|map, head, _| {
13618                (
13619                    movement::line_end(map, head, action.stop_at_soft_wraps),
13620                    SelectionGoal::None,
13621                )
13622            });
13623        })
13624    }
13625
13626    pub fn select_to_end_of_line(
13627        &mut self,
13628        action: &SelectToEndOfLine,
13629        window: &mut Window,
13630        cx: &mut Context<Self>,
13631    ) {
13632        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13633        self.change_selections(Default::default(), window, cx, |s| {
13634            s.move_heads_with(|map, head, _| {
13635                (
13636                    movement::line_end(map, head, action.stop_at_soft_wraps),
13637                    SelectionGoal::None,
13638                )
13639            });
13640        })
13641    }
13642
13643    pub fn delete_to_end_of_line(
13644        &mut self,
13645        _: &DeleteToEndOfLine,
13646        window: &mut Window,
13647        cx: &mut Context<Self>,
13648    ) {
13649        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13650        self.transact(window, cx, |this, window, cx| {
13651            this.select_to_end_of_line(
13652                &SelectToEndOfLine {
13653                    stop_at_soft_wraps: false,
13654                },
13655                window,
13656                cx,
13657            );
13658            this.delete(&Delete, window, cx);
13659        });
13660    }
13661
13662    pub fn cut_to_end_of_line(
13663        &mut self,
13664        action: &CutToEndOfLine,
13665        window: &mut Window,
13666        cx: &mut Context<Self>,
13667    ) {
13668        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13669        self.transact(window, cx, |this, window, cx| {
13670            this.select_to_end_of_line(
13671                &SelectToEndOfLine {
13672                    stop_at_soft_wraps: false,
13673                },
13674                window,
13675                cx,
13676            );
13677            if !action.stop_at_newlines {
13678                this.change_selections(Default::default(), window, cx, |s| {
13679                    s.move_with(|_, sel| {
13680                        if sel.is_empty() {
13681                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13682                        }
13683                    });
13684                });
13685            }
13686            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13687            let item = this.cut_common(false, window, cx);
13688            cx.write_to_clipboard(item);
13689        });
13690    }
13691
13692    pub fn move_to_start_of_paragraph(
13693        &mut self,
13694        _: &MoveToStartOfParagraph,
13695        window: &mut Window,
13696        cx: &mut Context<Self>,
13697    ) {
13698        if matches!(self.mode, EditorMode::SingleLine) {
13699            cx.propagate();
13700            return;
13701        }
13702        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13703        self.change_selections(Default::default(), window, cx, |s| {
13704            s.move_with(|map, selection| {
13705                selection.collapse_to(
13706                    movement::start_of_paragraph(map, selection.head(), 1),
13707                    SelectionGoal::None,
13708                )
13709            });
13710        })
13711    }
13712
13713    pub fn move_to_end_of_paragraph(
13714        &mut self,
13715        _: &MoveToEndOfParagraph,
13716        window: &mut Window,
13717        cx: &mut Context<Self>,
13718    ) {
13719        if matches!(self.mode, EditorMode::SingleLine) {
13720            cx.propagate();
13721            return;
13722        }
13723        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13724        self.change_selections(Default::default(), window, cx, |s| {
13725            s.move_with(|map, selection| {
13726                selection.collapse_to(
13727                    movement::end_of_paragraph(map, selection.head(), 1),
13728                    SelectionGoal::None,
13729                )
13730            });
13731        })
13732    }
13733
13734    pub fn select_to_start_of_paragraph(
13735        &mut self,
13736        _: &SelectToStartOfParagraph,
13737        window: &mut Window,
13738        cx: &mut Context<Self>,
13739    ) {
13740        if matches!(self.mode, EditorMode::SingleLine) {
13741            cx.propagate();
13742            return;
13743        }
13744        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13745        self.change_selections(Default::default(), window, cx, |s| {
13746            s.move_heads_with(|map, head, _| {
13747                (
13748                    movement::start_of_paragraph(map, head, 1),
13749                    SelectionGoal::None,
13750                )
13751            });
13752        })
13753    }
13754
13755    pub fn select_to_end_of_paragraph(
13756        &mut self,
13757        _: &SelectToEndOfParagraph,
13758        window: &mut Window,
13759        cx: &mut Context<Self>,
13760    ) {
13761        if matches!(self.mode, EditorMode::SingleLine) {
13762            cx.propagate();
13763            return;
13764        }
13765        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13766        self.change_selections(Default::default(), window, cx, |s| {
13767            s.move_heads_with(|map, head, _| {
13768                (
13769                    movement::end_of_paragraph(map, head, 1),
13770                    SelectionGoal::None,
13771                )
13772            });
13773        })
13774    }
13775
13776    pub fn move_to_start_of_excerpt(
13777        &mut self,
13778        _: &MoveToStartOfExcerpt,
13779        window: &mut Window,
13780        cx: &mut Context<Self>,
13781    ) {
13782        if matches!(self.mode, EditorMode::SingleLine) {
13783            cx.propagate();
13784            return;
13785        }
13786        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13787        self.change_selections(Default::default(), window, cx, |s| {
13788            s.move_with(|map, selection| {
13789                selection.collapse_to(
13790                    movement::start_of_excerpt(
13791                        map,
13792                        selection.head(),
13793                        workspace::searchable::Direction::Prev,
13794                    ),
13795                    SelectionGoal::None,
13796                )
13797            });
13798        })
13799    }
13800
13801    pub fn move_to_start_of_next_excerpt(
13802        &mut self,
13803        _: &MoveToStartOfNextExcerpt,
13804        window: &mut Window,
13805        cx: &mut Context<Self>,
13806    ) {
13807        if matches!(self.mode, EditorMode::SingleLine) {
13808            cx.propagate();
13809            return;
13810        }
13811
13812        self.change_selections(Default::default(), window, cx, |s| {
13813            s.move_with(|map, selection| {
13814                selection.collapse_to(
13815                    movement::start_of_excerpt(
13816                        map,
13817                        selection.head(),
13818                        workspace::searchable::Direction::Next,
13819                    ),
13820                    SelectionGoal::None,
13821                )
13822            });
13823        })
13824    }
13825
13826    pub fn move_to_end_of_excerpt(
13827        &mut self,
13828        _: &MoveToEndOfExcerpt,
13829        window: &mut Window,
13830        cx: &mut Context<Self>,
13831    ) {
13832        if matches!(self.mode, EditorMode::SingleLine) {
13833            cx.propagate();
13834            return;
13835        }
13836        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13837        self.change_selections(Default::default(), window, cx, |s| {
13838            s.move_with(|map, selection| {
13839                selection.collapse_to(
13840                    movement::end_of_excerpt(
13841                        map,
13842                        selection.head(),
13843                        workspace::searchable::Direction::Next,
13844                    ),
13845                    SelectionGoal::None,
13846                )
13847            });
13848        })
13849    }
13850
13851    pub fn move_to_end_of_previous_excerpt(
13852        &mut self,
13853        _: &MoveToEndOfPreviousExcerpt,
13854        window: &mut Window,
13855        cx: &mut Context<Self>,
13856    ) {
13857        if matches!(self.mode, EditorMode::SingleLine) {
13858            cx.propagate();
13859            return;
13860        }
13861        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13862        self.change_selections(Default::default(), window, cx, |s| {
13863            s.move_with(|map, selection| {
13864                selection.collapse_to(
13865                    movement::end_of_excerpt(
13866                        map,
13867                        selection.head(),
13868                        workspace::searchable::Direction::Prev,
13869                    ),
13870                    SelectionGoal::None,
13871                )
13872            });
13873        })
13874    }
13875
13876    pub fn select_to_start_of_excerpt(
13877        &mut self,
13878        _: &SelectToStartOfExcerpt,
13879        window: &mut Window,
13880        cx: &mut Context<Self>,
13881    ) {
13882        if matches!(self.mode, EditorMode::SingleLine) {
13883            cx.propagate();
13884            return;
13885        }
13886        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13887        self.change_selections(Default::default(), window, cx, |s| {
13888            s.move_heads_with(|map, head, _| {
13889                (
13890                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13891                    SelectionGoal::None,
13892                )
13893            });
13894        })
13895    }
13896
13897    pub fn select_to_start_of_next_excerpt(
13898        &mut self,
13899        _: &SelectToStartOfNextExcerpt,
13900        window: &mut Window,
13901        cx: &mut Context<Self>,
13902    ) {
13903        if matches!(self.mode, EditorMode::SingleLine) {
13904            cx.propagate();
13905            return;
13906        }
13907        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13908        self.change_selections(Default::default(), window, cx, |s| {
13909            s.move_heads_with(|map, head, _| {
13910                (
13911                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13912                    SelectionGoal::None,
13913                )
13914            });
13915        })
13916    }
13917
13918    pub fn select_to_end_of_excerpt(
13919        &mut self,
13920        _: &SelectToEndOfExcerpt,
13921        window: &mut Window,
13922        cx: &mut Context<Self>,
13923    ) {
13924        if matches!(self.mode, EditorMode::SingleLine) {
13925            cx.propagate();
13926            return;
13927        }
13928        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13929        self.change_selections(Default::default(), window, cx, |s| {
13930            s.move_heads_with(|map, head, _| {
13931                (
13932                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13933                    SelectionGoal::None,
13934                )
13935            });
13936        })
13937    }
13938
13939    pub fn select_to_end_of_previous_excerpt(
13940        &mut self,
13941        _: &SelectToEndOfPreviousExcerpt,
13942        window: &mut Window,
13943        cx: &mut Context<Self>,
13944    ) {
13945        if matches!(self.mode, EditorMode::SingleLine) {
13946            cx.propagate();
13947            return;
13948        }
13949        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13950        self.change_selections(Default::default(), window, cx, |s| {
13951            s.move_heads_with(|map, head, _| {
13952                (
13953                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13954                    SelectionGoal::None,
13955                )
13956            });
13957        })
13958    }
13959
13960    pub fn move_to_beginning(
13961        &mut self,
13962        _: &MoveToBeginning,
13963        window: &mut Window,
13964        cx: &mut Context<Self>,
13965    ) {
13966        if matches!(self.mode, EditorMode::SingleLine) {
13967            cx.propagate();
13968            return;
13969        }
13970        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13971        self.change_selections(Default::default(), window, cx, |s| {
13972            s.select_ranges(vec![0..0]);
13973        });
13974    }
13975
13976    pub fn select_to_beginning(
13977        &mut self,
13978        _: &SelectToBeginning,
13979        window: &mut Window,
13980        cx: &mut Context<Self>,
13981    ) {
13982        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
13983        selection.set_head(Point::zero(), SelectionGoal::None);
13984        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13985        self.change_selections(Default::default(), window, cx, |s| {
13986            s.select(vec![selection]);
13987        });
13988    }
13989
13990    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
13991        if matches!(self.mode, EditorMode::SingleLine) {
13992            cx.propagate();
13993            return;
13994        }
13995        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13996        let cursor = self.buffer.read(cx).read(cx).len();
13997        self.change_selections(Default::default(), window, cx, |s| {
13998            s.select_ranges(vec![cursor..cursor])
13999        });
14000    }
14001
14002    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14003        self.nav_history = nav_history;
14004    }
14005
14006    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14007        self.nav_history.as_ref()
14008    }
14009
14010    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14011        self.push_to_nav_history(
14012            self.selections.newest_anchor().head(),
14013            None,
14014            false,
14015            true,
14016            cx,
14017        );
14018    }
14019
14020    fn push_to_nav_history(
14021        &mut self,
14022        cursor_anchor: Anchor,
14023        new_position: Option<Point>,
14024        is_deactivate: bool,
14025        always: bool,
14026        cx: &mut Context<Self>,
14027    ) {
14028        if let Some(nav_history) = self.nav_history.as_mut() {
14029            let buffer = self.buffer.read(cx).read(cx);
14030            let cursor_position = cursor_anchor.to_point(&buffer);
14031            let scroll_state = self.scroll_manager.anchor();
14032            let scroll_top_row = scroll_state.top_row(&buffer);
14033            drop(buffer);
14034
14035            if let Some(new_position) = new_position {
14036                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14037                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14038                    return;
14039                }
14040            }
14041
14042            nav_history.push(
14043                Some(NavigationData {
14044                    cursor_anchor,
14045                    cursor_position,
14046                    scroll_anchor: scroll_state,
14047                    scroll_top_row,
14048                }),
14049                cx,
14050            );
14051            cx.emit(EditorEvent::PushedToNavHistory {
14052                anchor: cursor_anchor,
14053                is_deactivate,
14054            })
14055        }
14056    }
14057
14058    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14059        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14060        let buffer = self.buffer.read(cx).snapshot(cx);
14061        let mut selection = self.selections.first::<usize>(&self.display_snapshot(cx));
14062        selection.set_head(buffer.len(), SelectionGoal::None);
14063        self.change_selections(Default::default(), window, cx, |s| {
14064            s.select(vec![selection]);
14065        });
14066    }
14067
14068    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14069        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14070        let end = self.buffer.read(cx).read(cx).len();
14071        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14072            s.select_ranges(vec![0..end]);
14073        });
14074    }
14075
14076    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14077        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14078        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14079        let mut selections = self.selections.all::<Point>(&display_map);
14080        let max_point = display_map.buffer_snapshot().max_point();
14081        for selection in &mut selections {
14082            let rows = selection.spanned_rows(true, &display_map);
14083            selection.start = Point::new(rows.start.0, 0);
14084            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14085            selection.reversed = false;
14086        }
14087        self.change_selections(Default::default(), window, cx, |s| {
14088            s.select(selections);
14089        });
14090    }
14091
14092    pub fn split_selection_into_lines(
14093        &mut self,
14094        action: &SplitSelectionIntoLines,
14095        window: &mut Window,
14096        cx: &mut Context<Self>,
14097    ) {
14098        let selections = self
14099            .selections
14100            .all::<Point>(&self.display_snapshot(cx))
14101            .into_iter()
14102            .map(|selection| selection.start..selection.end)
14103            .collect::<Vec<_>>();
14104        self.unfold_ranges(&selections, true, true, cx);
14105
14106        let mut new_selection_ranges = Vec::new();
14107        {
14108            let buffer = self.buffer.read(cx).read(cx);
14109            for selection in selections {
14110                for row in selection.start.row..selection.end.row {
14111                    let line_start = Point::new(row, 0);
14112                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14113
14114                    if action.keep_selections {
14115                        // Keep the selection range for each line
14116                        let selection_start = if row == selection.start.row {
14117                            selection.start
14118                        } else {
14119                            line_start
14120                        };
14121                        new_selection_ranges.push(selection_start..line_end);
14122                    } else {
14123                        // Collapse to cursor at end of line
14124                        new_selection_ranges.push(line_end..line_end);
14125                    }
14126                }
14127
14128                let is_multiline_selection = selection.start.row != selection.end.row;
14129                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14130                // so this action feels more ergonomic when paired with other selection operations
14131                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14132                if !should_skip_last {
14133                    if action.keep_selections {
14134                        if is_multiline_selection {
14135                            let line_start = Point::new(selection.end.row, 0);
14136                            new_selection_ranges.push(line_start..selection.end);
14137                        } else {
14138                            new_selection_ranges.push(selection.start..selection.end);
14139                        }
14140                    } else {
14141                        new_selection_ranges.push(selection.end..selection.end);
14142                    }
14143                }
14144            }
14145        }
14146        self.change_selections(Default::default(), window, cx, |s| {
14147            s.select_ranges(new_selection_ranges);
14148        });
14149    }
14150
14151    pub fn add_selection_above(
14152        &mut self,
14153        action: &AddSelectionAbove,
14154        window: &mut Window,
14155        cx: &mut Context<Self>,
14156    ) {
14157        self.add_selection(true, action.skip_soft_wrap, window, cx);
14158    }
14159
14160    pub fn add_selection_below(
14161        &mut self,
14162        action: &AddSelectionBelow,
14163        window: &mut Window,
14164        cx: &mut Context<Self>,
14165    ) {
14166        self.add_selection(false, action.skip_soft_wrap, window, cx);
14167    }
14168
14169    fn add_selection(
14170        &mut self,
14171        above: bool,
14172        skip_soft_wrap: bool,
14173        window: &mut Window,
14174        cx: &mut Context<Self>,
14175    ) {
14176        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14177
14178        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14179        let all_selections = self.selections.all::<Point>(&display_map);
14180        let text_layout_details = self.text_layout_details(window);
14181
14182        let (mut columnar_selections, new_selections_to_columnarize) = {
14183            if let Some(state) = self.add_selections_state.as_ref() {
14184                let columnar_selection_ids: HashSet<_> = state
14185                    .groups
14186                    .iter()
14187                    .flat_map(|group| group.stack.iter())
14188                    .copied()
14189                    .collect();
14190
14191                all_selections
14192                    .into_iter()
14193                    .partition(|s| columnar_selection_ids.contains(&s.id))
14194            } else {
14195                (Vec::new(), all_selections)
14196            }
14197        };
14198
14199        let mut state = self
14200            .add_selections_state
14201            .take()
14202            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14203
14204        for selection in new_selections_to_columnarize {
14205            let range = selection.display_range(&display_map).sorted();
14206            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14207            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14208            let positions = start_x.min(end_x)..start_x.max(end_x);
14209            let mut stack = Vec::new();
14210            for row in range.start.row().0..=range.end.row().0 {
14211                if let Some(selection) = self.selections.build_columnar_selection(
14212                    &display_map,
14213                    DisplayRow(row),
14214                    &positions,
14215                    selection.reversed,
14216                    &text_layout_details,
14217                ) {
14218                    stack.push(selection.id);
14219                    columnar_selections.push(selection);
14220                }
14221            }
14222            if !stack.is_empty() {
14223                if above {
14224                    stack.reverse();
14225                }
14226                state.groups.push(AddSelectionsGroup { above, stack });
14227            }
14228        }
14229
14230        let mut final_selections = Vec::new();
14231        let end_row = if above {
14232            DisplayRow(0)
14233        } else {
14234            display_map.max_point().row()
14235        };
14236
14237        let mut last_added_item_per_group = HashMap::default();
14238        for group in state.groups.iter_mut() {
14239            if let Some(last_id) = group.stack.last() {
14240                last_added_item_per_group.insert(*last_id, group);
14241            }
14242        }
14243
14244        for selection in columnar_selections {
14245            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14246                if above == group.above {
14247                    let range = selection.display_range(&display_map).sorted();
14248                    debug_assert_eq!(range.start.row(), range.end.row());
14249                    let mut row = range.start.row();
14250                    let positions =
14251                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14252                            Pixels::from(start)..Pixels::from(end)
14253                        } else {
14254                            let start_x =
14255                                display_map.x_for_display_point(range.start, &text_layout_details);
14256                            let end_x =
14257                                display_map.x_for_display_point(range.end, &text_layout_details);
14258                            start_x.min(end_x)..start_x.max(end_x)
14259                        };
14260
14261                    let mut maybe_new_selection = None;
14262                    let direction = if above { -1 } else { 1 };
14263
14264                    while row != end_row {
14265                        if skip_soft_wrap {
14266                            row = display_map
14267                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14268                                .row();
14269                        } else if above {
14270                            row.0 -= 1;
14271                        } else {
14272                            row.0 += 1;
14273                        }
14274
14275                        if let Some(new_selection) = self.selections.build_columnar_selection(
14276                            &display_map,
14277                            row,
14278                            &positions,
14279                            selection.reversed,
14280                            &text_layout_details,
14281                        ) {
14282                            maybe_new_selection = Some(new_selection);
14283                            break;
14284                        }
14285                    }
14286
14287                    if let Some(new_selection) = maybe_new_selection {
14288                        group.stack.push(new_selection.id);
14289                        if above {
14290                            final_selections.push(new_selection);
14291                            final_selections.push(selection);
14292                        } else {
14293                            final_selections.push(selection);
14294                            final_selections.push(new_selection);
14295                        }
14296                    } else {
14297                        final_selections.push(selection);
14298                    }
14299                } else {
14300                    group.stack.pop();
14301                }
14302            } else {
14303                final_selections.push(selection);
14304            }
14305        }
14306
14307        self.change_selections(Default::default(), window, cx, |s| {
14308            s.select(final_selections);
14309        });
14310
14311        let final_selection_ids: HashSet<_> = self
14312            .selections
14313            .all::<Point>(&display_map)
14314            .iter()
14315            .map(|s| s.id)
14316            .collect();
14317        state.groups.retain_mut(|group| {
14318            // selections might get merged above so we remove invalid items from stacks
14319            group.stack.retain(|id| final_selection_ids.contains(id));
14320
14321            // single selection in stack can be treated as initial state
14322            group.stack.len() > 1
14323        });
14324
14325        if !state.groups.is_empty() {
14326            self.add_selections_state = Some(state);
14327        }
14328    }
14329
14330    fn select_match_ranges(
14331        &mut self,
14332        range: Range<usize>,
14333        reversed: bool,
14334        replace_newest: bool,
14335        auto_scroll: Option<Autoscroll>,
14336        window: &mut Window,
14337        cx: &mut Context<Editor>,
14338    ) {
14339        self.unfold_ranges(
14340            std::slice::from_ref(&range),
14341            false,
14342            auto_scroll.is_some(),
14343            cx,
14344        );
14345        let effects = if let Some(scroll) = auto_scroll {
14346            SelectionEffects::scroll(scroll)
14347        } else {
14348            SelectionEffects::no_scroll()
14349        };
14350        self.change_selections(effects, window, cx, |s| {
14351            if replace_newest {
14352                s.delete(s.newest_anchor().id);
14353            }
14354            if reversed {
14355                s.insert_range(range.end..range.start);
14356            } else {
14357                s.insert_range(range);
14358            }
14359        });
14360    }
14361
14362    pub fn select_next_match_internal(
14363        &mut self,
14364        display_map: &DisplaySnapshot,
14365        replace_newest: bool,
14366        autoscroll: Option<Autoscroll>,
14367        window: &mut Window,
14368        cx: &mut Context<Self>,
14369    ) -> Result<()> {
14370        let buffer = display_map.buffer_snapshot();
14371        let mut selections = self.selections.all::<usize>(&display_map);
14372        if let Some(mut select_next_state) = self.select_next_state.take() {
14373            let query = &select_next_state.query;
14374            if !select_next_state.done {
14375                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14376                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14377                let mut next_selected_range = None;
14378
14379                let bytes_after_last_selection =
14380                    buffer.bytes_in_range(last_selection.end..buffer.len());
14381                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14382                let query_matches = query
14383                    .stream_find_iter(bytes_after_last_selection)
14384                    .map(|result| (last_selection.end, result))
14385                    .chain(
14386                        query
14387                            .stream_find_iter(bytes_before_first_selection)
14388                            .map(|result| (0, result)),
14389                    );
14390
14391                for (start_offset, query_match) in query_matches {
14392                    let query_match = query_match.unwrap(); // can only fail due to I/O
14393                    let offset_range =
14394                        start_offset + query_match.start()..start_offset + query_match.end();
14395
14396                    if !select_next_state.wordwise
14397                        || (!buffer.is_inside_word(offset_range.start, None)
14398                            && !buffer.is_inside_word(offset_range.end, None))
14399                    {
14400                        let idx = selections
14401                            .partition_point(|selection| selection.end <= offset_range.start);
14402                        let overlaps = selections
14403                            .get(idx)
14404                            .map_or(false, |selection| selection.start < offset_range.end);
14405
14406                        if !overlaps {
14407                            next_selected_range = Some(offset_range);
14408                            break;
14409                        }
14410                    }
14411                }
14412
14413                if let Some(next_selected_range) = next_selected_range {
14414                    self.select_match_ranges(
14415                        next_selected_range,
14416                        last_selection.reversed,
14417                        replace_newest,
14418                        autoscroll,
14419                        window,
14420                        cx,
14421                    );
14422                } else {
14423                    select_next_state.done = true;
14424                }
14425            }
14426
14427            self.select_next_state = Some(select_next_state);
14428        } else {
14429            let mut only_carets = true;
14430            let mut same_text_selected = true;
14431            let mut selected_text = None;
14432
14433            let mut selections_iter = selections.iter().peekable();
14434            while let Some(selection) = selections_iter.next() {
14435                if selection.start != selection.end {
14436                    only_carets = false;
14437                }
14438
14439                if same_text_selected {
14440                    if selected_text.is_none() {
14441                        selected_text =
14442                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14443                    }
14444
14445                    if let Some(next_selection) = selections_iter.peek() {
14446                        if next_selection.range().len() == selection.range().len() {
14447                            let next_selected_text = buffer
14448                                .text_for_range(next_selection.range())
14449                                .collect::<String>();
14450                            if Some(next_selected_text) != selected_text {
14451                                same_text_selected = false;
14452                                selected_text = None;
14453                            }
14454                        } else {
14455                            same_text_selected = false;
14456                            selected_text = None;
14457                        }
14458                    }
14459                }
14460            }
14461
14462            if only_carets {
14463                for selection in &mut selections {
14464                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14465                    selection.start = word_range.start;
14466                    selection.end = word_range.end;
14467                    selection.goal = SelectionGoal::None;
14468                    selection.reversed = false;
14469                    self.select_match_ranges(
14470                        selection.start..selection.end,
14471                        selection.reversed,
14472                        replace_newest,
14473                        autoscroll,
14474                        window,
14475                        cx,
14476                    );
14477                }
14478
14479                if selections.len() == 1 {
14480                    let selection = selections
14481                        .last()
14482                        .expect("ensured that there's only one selection");
14483                    let query = buffer
14484                        .text_for_range(selection.start..selection.end)
14485                        .collect::<String>();
14486                    let is_empty = query.is_empty();
14487                    let select_state = SelectNextState {
14488                        query: AhoCorasick::new(&[query])?,
14489                        wordwise: true,
14490                        done: is_empty,
14491                    };
14492                    self.select_next_state = Some(select_state);
14493                } else {
14494                    self.select_next_state = None;
14495                }
14496            } else if let Some(selected_text) = selected_text {
14497                self.select_next_state = Some(SelectNextState {
14498                    query: AhoCorasick::new(&[selected_text])?,
14499                    wordwise: false,
14500                    done: false,
14501                });
14502                self.select_next_match_internal(
14503                    display_map,
14504                    replace_newest,
14505                    autoscroll,
14506                    window,
14507                    cx,
14508                )?;
14509            }
14510        }
14511        Ok(())
14512    }
14513
14514    pub fn select_all_matches(
14515        &mut self,
14516        _action: &SelectAllMatches,
14517        window: &mut Window,
14518        cx: &mut Context<Self>,
14519    ) -> Result<()> {
14520        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14521
14522        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14523
14524        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14525        let Some(select_next_state) = self.select_next_state.as_mut() else {
14526            return Ok(());
14527        };
14528        if select_next_state.done {
14529            return Ok(());
14530        }
14531
14532        let mut new_selections = Vec::new();
14533
14534        let reversed = self.selections.oldest::<usize>(&display_map).reversed;
14535        let buffer = display_map.buffer_snapshot();
14536        let query_matches = select_next_state
14537            .query
14538            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14539
14540        for query_match in query_matches.into_iter() {
14541            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14542            let offset_range = if reversed {
14543                query_match.end()..query_match.start()
14544            } else {
14545                query_match.start()..query_match.end()
14546            };
14547
14548            if !select_next_state.wordwise
14549                || (!buffer.is_inside_word(offset_range.start, None)
14550                    && !buffer.is_inside_word(offset_range.end, None))
14551            {
14552                new_selections.push(offset_range.start..offset_range.end);
14553            }
14554        }
14555
14556        select_next_state.done = true;
14557
14558        if new_selections.is_empty() {
14559            log::error!("bug: new_selections is empty in select_all_matches");
14560            return Ok(());
14561        }
14562
14563        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14564        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14565            selections.select_ranges(new_selections)
14566        });
14567
14568        Ok(())
14569    }
14570
14571    pub fn select_next(
14572        &mut self,
14573        action: &SelectNext,
14574        window: &mut Window,
14575        cx: &mut Context<Self>,
14576    ) -> Result<()> {
14577        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14578        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14579        self.select_next_match_internal(
14580            &display_map,
14581            action.replace_newest,
14582            Some(Autoscroll::newest()),
14583            window,
14584            cx,
14585        )?;
14586        Ok(())
14587    }
14588
14589    pub fn select_previous(
14590        &mut self,
14591        action: &SelectPrevious,
14592        window: &mut Window,
14593        cx: &mut Context<Self>,
14594    ) -> Result<()> {
14595        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14596        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14597        let buffer = display_map.buffer_snapshot();
14598        let mut selections = self.selections.all::<usize>(&display_map);
14599        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14600            let query = &select_prev_state.query;
14601            if !select_prev_state.done {
14602                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14603                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14604                let mut next_selected_range = None;
14605                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14606                let bytes_before_last_selection =
14607                    buffer.reversed_bytes_in_range(0..last_selection.start);
14608                let bytes_after_first_selection =
14609                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14610                let query_matches = query
14611                    .stream_find_iter(bytes_before_last_selection)
14612                    .map(|result| (last_selection.start, result))
14613                    .chain(
14614                        query
14615                            .stream_find_iter(bytes_after_first_selection)
14616                            .map(|result| (buffer.len(), result)),
14617                    );
14618                for (end_offset, query_match) in query_matches {
14619                    let query_match = query_match.unwrap(); // can only fail due to I/O
14620                    let offset_range =
14621                        end_offset - query_match.end()..end_offset - query_match.start();
14622
14623                    if !select_prev_state.wordwise
14624                        || (!buffer.is_inside_word(offset_range.start, None)
14625                            && !buffer.is_inside_word(offset_range.end, None))
14626                    {
14627                        next_selected_range = Some(offset_range);
14628                        break;
14629                    }
14630                }
14631
14632                if let Some(next_selected_range) = next_selected_range {
14633                    self.select_match_ranges(
14634                        next_selected_range,
14635                        last_selection.reversed,
14636                        action.replace_newest,
14637                        Some(Autoscroll::newest()),
14638                        window,
14639                        cx,
14640                    );
14641                } else {
14642                    select_prev_state.done = true;
14643                }
14644            }
14645
14646            self.select_prev_state = Some(select_prev_state);
14647        } else {
14648            let mut only_carets = true;
14649            let mut same_text_selected = true;
14650            let mut selected_text = None;
14651
14652            let mut selections_iter = selections.iter().peekable();
14653            while let Some(selection) = selections_iter.next() {
14654                if selection.start != selection.end {
14655                    only_carets = false;
14656                }
14657
14658                if same_text_selected {
14659                    if selected_text.is_none() {
14660                        selected_text =
14661                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14662                    }
14663
14664                    if let Some(next_selection) = selections_iter.peek() {
14665                        if next_selection.range().len() == selection.range().len() {
14666                            let next_selected_text = buffer
14667                                .text_for_range(next_selection.range())
14668                                .collect::<String>();
14669                            if Some(next_selected_text) != selected_text {
14670                                same_text_selected = false;
14671                                selected_text = None;
14672                            }
14673                        } else {
14674                            same_text_selected = false;
14675                            selected_text = None;
14676                        }
14677                    }
14678                }
14679            }
14680
14681            if only_carets {
14682                for selection in &mut selections {
14683                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14684                    selection.start = word_range.start;
14685                    selection.end = word_range.end;
14686                    selection.goal = SelectionGoal::None;
14687                    selection.reversed = false;
14688                    self.select_match_ranges(
14689                        selection.start..selection.end,
14690                        selection.reversed,
14691                        action.replace_newest,
14692                        Some(Autoscroll::newest()),
14693                        window,
14694                        cx,
14695                    );
14696                }
14697                if selections.len() == 1 {
14698                    let selection = selections
14699                        .last()
14700                        .expect("ensured that there's only one selection");
14701                    let query = buffer
14702                        .text_for_range(selection.start..selection.end)
14703                        .collect::<String>();
14704                    let is_empty = query.is_empty();
14705                    let select_state = SelectNextState {
14706                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14707                        wordwise: true,
14708                        done: is_empty,
14709                    };
14710                    self.select_prev_state = Some(select_state);
14711                } else {
14712                    self.select_prev_state = None;
14713                }
14714            } else if let Some(selected_text) = selected_text {
14715                self.select_prev_state = Some(SelectNextState {
14716                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14717                    wordwise: false,
14718                    done: false,
14719                });
14720                self.select_previous(action, window, cx)?;
14721            }
14722        }
14723        Ok(())
14724    }
14725
14726    pub fn find_next_match(
14727        &mut self,
14728        _: &FindNextMatch,
14729        window: &mut Window,
14730        cx: &mut Context<Self>,
14731    ) -> Result<()> {
14732        let selections = self.selections.disjoint_anchors_arc();
14733        match selections.first() {
14734            Some(first) if selections.len() >= 2 => {
14735                self.change_selections(Default::default(), window, cx, |s| {
14736                    s.select_ranges([first.range()]);
14737                });
14738            }
14739            _ => self.select_next(
14740                &SelectNext {
14741                    replace_newest: true,
14742                },
14743                window,
14744                cx,
14745            )?,
14746        }
14747        Ok(())
14748    }
14749
14750    pub fn find_previous_match(
14751        &mut self,
14752        _: &FindPreviousMatch,
14753        window: &mut Window,
14754        cx: &mut Context<Self>,
14755    ) -> Result<()> {
14756        let selections = self.selections.disjoint_anchors_arc();
14757        match selections.last() {
14758            Some(last) if selections.len() >= 2 => {
14759                self.change_selections(Default::default(), window, cx, |s| {
14760                    s.select_ranges([last.range()]);
14761                });
14762            }
14763            _ => self.select_previous(
14764                &SelectPrevious {
14765                    replace_newest: true,
14766                },
14767                window,
14768                cx,
14769            )?,
14770        }
14771        Ok(())
14772    }
14773
14774    pub fn toggle_comments(
14775        &mut self,
14776        action: &ToggleComments,
14777        window: &mut Window,
14778        cx: &mut Context<Self>,
14779    ) {
14780        if self.read_only(cx) {
14781            return;
14782        }
14783        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14784        let text_layout_details = &self.text_layout_details(window);
14785        self.transact(window, cx, |this, window, cx| {
14786            let mut selections = this
14787                .selections
14788                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
14789            let mut edits = Vec::new();
14790            let mut selection_edit_ranges = Vec::new();
14791            let mut last_toggled_row = None;
14792            let snapshot = this.buffer.read(cx).read(cx);
14793            let empty_str: Arc<str> = Arc::default();
14794            let mut suffixes_inserted = Vec::new();
14795            let ignore_indent = action.ignore_indent;
14796
14797            fn comment_prefix_range(
14798                snapshot: &MultiBufferSnapshot,
14799                row: MultiBufferRow,
14800                comment_prefix: &str,
14801                comment_prefix_whitespace: &str,
14802                ignore_indent: bool,
14803            ) -> Range<Point> {
14804                let indent_size = if ignore_indent {
14805                    0
14806                } else {
14807                    snapshot.indent_size_for_line(row).len
14808                };
14809
14810                let start = Point::new(row.0, indent_size);
14811
14812                let mut line_bytes = snapshot
14813                    .bytes_in_range(start..snapshot.max_point())
14814                    .flatten()
14815                    .copied();
14816
14817                // If this line currently begins with the line comment prefix, then record
14818                // the range containing the prefix.
14819                if line_bytes
14820                    .by_ref()
14821                    .take(comment_prefix.len())
14822                    .eq(comment_prefix.bytes())
14823                {
14824                    // Include any whitespace that matches the comment prefix.
14825                    let matching_whitespace_len = line_bytes
14826                        .zip(comment_prefix_whitespace.bytes())
14827                        .take_while(|(a, b)| a == b)
14828                        .count() as u32;
14829                    let end = Point::new(
14830                        start.row,
14831                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14832                    );
14833                    start..end
14834                } else {
14835                    start..start
14836                }
14837            }
14838
14839            fn comment_suffix_range(
14840                snapshot: &MultiBufferSnapshot,
14841                row: MultiBufferRow,
14842                comment_suffix: &str,
14843                comment_suffix_has_leading_space: bool,
14844            ) -> Range<Point> {
14845                let end = Point::new(row.0, snapshot.line_len(row));
14846                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14847
14848                let mut line_end_bytes = snapshot
14849                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14850                    .flatten()
14851                    .copied();
14852
14853                let leading_space_len = if suffix_start_column > 0
14854                    && line_end_bytes.next() == Some(b' ')
14855                    && comment_suffix_has_leading_space
14856                {
14857                    1
14858                } else {
14859                    0
14860                };
14861
14862                // If this line currently begins with the line comment prefix, then record
14863                // the range containing the prefix.
14864                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14865                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14866                    start..end
14867                } else {
14868                    end..end
14869                }
14870            }
14871
14872            // TODO: Handle selections that cross excerpts
14873            for selection in &mut selections {
14874                let start_column = snapshot
14875                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14876                    .len;
14877                let language = if let Some(language) =
14878                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14879                {
14880                    language
14881                } else {
14882                    continue;
14883                };
14884
14885                selection_edit_ranges.clear();
14886
14887                // If multiple selections contain a given row, avoid processing that
14888                // row more than once.
14889                let mut start_row = MultiBufferRow(selection.start.row);
14890                if last_toggled_row == Some(start_row) {
14891                    start_row = start_row.next_row();
14892                }
14893                let end_row =
14894                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14895                        MultiBufferRow(selection.end.row - 1)
14896                    } else {
14897                        MultiBufferRow(selection.end.row)
14898                    };
14899                last_toggled_row = Some(end_row);
14900
14901                if start_row > end_row {
14902                    continue;
14903                }
14904
14905                // If the language has line comments, toggle those.
14906                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14907
14908                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14909                if ignore_indent {
14910                    full_comment_prefixes = full_comment_prefixes
14911                        .into_iter()
14912                        .map(|s| Arc::from(s.trim_end()))
14913                        .collect();
14914                }
14915
14916                if !full_comment_prefixes.is_empty() {
14917                    let first_prefix = full_comment_prefixes
14918                        .first()
14919                        .expect("prefixes is non-empty");
14920                    let prefix_trimmed_lengths = full_comment_prefixes
14921                        .iter()
14922                        .map(|p| p.trim_end_matches(' ').len())
14923                        .collect::<SmallVec<[usize; 4]>>();
14924
14925                    let mut all_selection_lines_are_comments = true;
14926
14927                    for row in start_row.0..=end_row.0 {
14928                        let row = MultiBufferRow(row);
14929                        if start_row < end_row && snapshot.is_line_blank(row) {
14930                            continue;
14931                        }
14932
14933                        let prefix_range = full_comment_prefixes
14934                            .iter()
14935                            .zip(prefix_trimmed_lengths.iter().copied())
14936                            .map(|(prefix, trimmed_prefix_len)| {
14937                                comment_prefix_range(
14938                                    snapshot.deref(),
14939                                    row,
14940                                    &prefix[..trimmed_prefix_len],
14941                                    &prefix[trimmed_prefix_len..],
14942                                    ignore_indent,
14943                                )
14944                            })
14945                            .max_by_key(|range| range.end.column - range.start.column)
14946                            .expect("prefixes is non-empty");
14947
14948                        if prefix_range.is_empty() {
14949                            all_selection_lines_are_comments = false;
14950                        }
14951
14952                        selection_edit_ranges.push(prefix_range);
14953                    }
14954
14955                    if all_selection_lines_are_comments {
14956                        edits.extend(
14957                            selection_edit_ranges
14958                                .iter()
14959                                .cloned()
14960                                .map(|range| (range, empty_str.clone())),
14961                        );
14962                    } else {
14963                        let min_column = selection_edit_ranges
14964                            .iter()
14965                            .map(|range| range.start.column)
14966                            .min()
14967                            .unwrap_or(0);
14968                        edits.extend(selection_edit_ranges.iter().map(|range| {
14969                            let position = Point::new(range.start.row, min_column);
14970                            (position..position, first_prefix.clone())
14971                        }));
14972                    }
14973                } else if let Some(BlockCommentConfig {
14974                    start: full_comment_prefix,
14975                    end: comment_suffix,
14976                    ..
14977                }) = language.block_comment()
14978                {
14979                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14980                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14981                    let prefix_range = comment_prefix_range(
14982                        snapshot.deref(),
14983                        start_row,
14984                        comment_prefix,
14985                        comment_prefix_whitespace,
14986                        ignore_indent,
14987                    );
14988                    let suffix_range = comment_suffix_range(
14989                        snapshot.deref(),
14990                        end_row,
14991                        comment_suffix.trim_start_matches(' '),
14992                        comment_suffix.starts_with(' '),
14993                    );
14994
14995                    if prefix_range.is_empty() || suffix_range.is_empty() {
14996                        edits.push((
14997                            prefix_range.start..prefix_range.start,
14998                            full_comment_prefix.clone(),
14999                        ));
15000                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15001                        suffixes_inserted.push((end_row, comment_suffix.len()));
15002                    } else {
15003                        edits.push((prefix_range, empty_str.clone()));
15004                        edits.push((suffix_range, empty_str.clone()));
15005                    }
15006                } else {
15007                    continue;
15008                }
15009            }
15010
15011            drop(snapshot);
15012            this.buffer.update(cx, |buffer, cx| {
15013                buffer.edit(edits, None, cx);
15014            });
15015
15016            // Adjust selections so that they end before any comment suffixes that
15017            // were inserted.
15018            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15019            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15020            let snapshot = this.buffer.read(cx).read(cx);
15021            for selection in &mut selections {
15022                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15023                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15024                        Ordering::Less => {
15025                            suffixes_inserted.next();
15026                            continue;
15027                        }
15028                        Ordering::Greater => break,
15029                        Ordering::Equal => {
15030                            if selection.end.column == snapshot.line_len(row) {
15031                                if selection.is_empty() {
15032                                    selection.start.column -= suffix_len as u32;
15033                                }
15034                                selection.end.column -= suffix_len as u32;
15035                            }
15036                            break;
15037                        }
15038                    }
15039                }
15040            }
15041
15042            drop(snapshot);
15043            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15044
15045            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15046            let selections_on_single_row = selections.windows(2).all(|selections| {
15047                selections[0].start.row == selections[1].start.row
15048                    && selections[0].end.row == selections[1].end.row
15049                    && selections[0].start.row == selections[0].end.row
15050            });
15051            let selections_selecting = selections
15052                .iter()
15053                .any(|selection| selection.start != selection.end);
15054            let advance_downwards = action.advance_downwards
15055                && selections_on_single_row
15056                && !selections_selecting
15057                && !matches!(this.mode, EditorMode::SingleLine);
15058
15059            if advance_downwards {
15060                let snapshot = this.buffer.read(cx).snapshot(cx);
15061
15062                this.change_selections(Default::default(), window, cx, |s| {
15063                    s.move_cursors_with(|display_snapshot, display_point, _| {
15064                        let mut point = display_point.to_point(display_snapshot);
15065                        point.row += 1;
15066                        point = snapshot.clip_point(point, Bias::Left);
15067                        let display_point = point.to_display_point(display_snapshot);
15068                        let goal = SelectionGoal::HorizontalPosition(
15069                            display_snapshot
15070                                .x_for_display_point(display_point, text_layout_details)
15071                                .into(),
15072                        );
15073                        (display_point, goal)
15074                    })
15075                });
15076            }
15077        });
15078    }
15079
15080    pub fn select_enclosing_symbol(
15081        &mut self,
15082        _: &SelectEnclosingSymbol,
15083        window: &mut Window,
15084        cx: &mut Context<Self>,
15085    ) {
15086        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15087
15088        let buffer = self.buffer.read(cx).snapshot(cx);
15089        let old_selections = self
15090            .selections
15091            .all::<usize>(&self.display_snapshot(cx))
15092            .into_boxed_slice();
15093
15094        fn update_selection(
15095            selection: &Selection<usize>,
15096            buffer_snap: &MultiBufferSnapshot,
15097        ) -> Option<Selection<usize>> {
15098            let cursor = selection.head();
15099            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15100            for symbol in symbols.iter().rev() {
15101                let start = symbol.range.start.to_offset(buffer_snap);
15102                let end = symbol.range.end.to_offset(buffer_snap);
15103                let new_range = start..end;
15104                if start < selection.start || end > selection.end {
15105                    return Some(Selection {
15106                        id: selection.id,
15107                        start: new_range.start,
15108                        end: new_range.end,
15109                        goal: SelectionGoal::None,
15110                        reversed: selection.reversed,
15111                    });
15112                }
15113            }
15114            None
15115        }
15116
15117        let mut selected_larger_symbol = false;
15118        let new_selections = old_selections
15119            .iter()
15120            .map(|selection| match update_selection(selection, &buffer) {
15121                Some(new_selection) => {
15122                    if new_selection.range() != selection.range() {
15123                        selected_larger_symbol = true;
15124                    }
15125                    new_selection
15126                }
15127                None => selection.clone(),
15128            })
15129            .collect::<Vec<_>>();
15130
15131        if selected_larger_symbol {
15132            self.change_selections(Default::default(), window, cx, |s| {
15133                s.select(new_selections);
15134            });
15135        }
15136    }
15137
15138    pub fn select_larger_syntax_node(
15139        &mut self,
15140        _: &SelectLargerSyntaxNode,
15141        window: &mut Window,
15142        cx: &mut Context<Self>,
15143    ) {
15144        let Some(visible_row_count) = self.visible_row_count() else {
15145            return;
15146        };
15147        let old_selections: Box<[_]> = self
15148            .selections
15149            .all::<usize>(&self.display_snapshot(cx))
15150            .into();
15151        if old_selections.is_empty() {
15152            return;
15153        }
15154
15155        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15156
15157        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15158        let buffer = self.buffer.read(cx).snapshot(cx);
15159
15160        let mut selected_larger_node = false;
15161        let mut new_selections = old_selections
15162            .iter()
15163            .map(|selection| {
15164                let old_range = selection.start..selection.end;
15165
15166                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15167                    // manually select word at selection
15168                    if ["string_content", "inline"].contains(&node.kind()) {
15169                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15170                        // ignore if word is already selected
15171                        if !word_range.is_empty() && old_range != word_range {
15172                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15173                            // only select word if start and end point belongs to same word
15174                            if word_range == last_word_range {
15175                                selected_larger_node = true;
15176                                return Selection {
15177                                    id: selection.id,
15178                                    start: word_range.start,
15179                                    end: word_range.end,
15180                                    goal: SelectionGoal::None,
15181                                    reversed: selection.reversed,
15182                                };
15183                            }
15184                        }
15185                    }
15186                }
15187
15188                let mut new_range = old_range.clone();
15189                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15190                    new_range = range;
15191                    if !node.is_named() {
15192                        continue;
15193                    }
15194                    if !display_map.intersects_fold(new_range.start)
15195                        && !display_map.intersects_fold(new_range.end)
15196                    {
15197                        break;
15198                    }
15199                }
15200
15201                selected_larger_node |= new_range != old_range;
15202                Selection {
15203                    id: selection.id,
15204                    start: new_range.start,
15205                    end: new_range.end,
15206                    goal: SelectionGoal::None,
15207                    reversed: selection.reversed,
15208                }
15209            })
15210            .collect::<Vec<_>>();
15211
15212        if !selected_larger_node {
15213            return; // don't put this call in the history
15214        }
15215
15216        // scroll based on transformation done to the last selection created by the user
15217        let (last_old, last_new) = old_selections
15218            .last()
15219            .zip(new_selections.last().cloned())
15220            .expect("old_selections isn't empty");
15221
15222        // revert selection
15223        let is_selection_reversed = {
15224            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15225            new_selections.last_mut().expect("checked above").reversed =
15226                should_newest_selection_be_reversed;
15227            should_newest_selection_be_reversed
15228        };
15229
15230        if selected_larger_node {
15231            self.select_syntax_node_history.disable_clearing = true;
15232            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15233                s.select(new_selections.clone());
15234            });
15235            self.select_syntax_node_history.disable_clearing = false;
15236        }
15237
15238        let start_row = last_new.start.to_display_point(&display_map).row().0;
15239        let end_row = last_new.end.to_display_point(&display_map).row().0;
15240        let selection_height = end_row - start_row + 1;
15241        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15242
15243        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15244        let scroll_behavior = if fits_on_the_screen {
15245            self.request_autoscroll(Autoscroll::fit(), cx);
15246            SelectSyntaxNodeScrollBehavior::FitSelection
15247        } else if is_selection_reversed {
15248            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15249            SelectSyntaxNodeScrollBehavior::CursorTop
15250        } else {
15251            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15252            SelectSyntaxNodeScrollBehavior::CursorBottom
15253        };
15254
15255        self.select_syntax_node_history.push((
15256            old_selections,
15257            scroll_behavior,
15258            is_selection_reversed,
15259        ));
15260    }
15261
15262    pub fn select_smaller_syntax_node(
15263        &mut self,
15264        _: &SelectSmallerSyntaxNode,
15265        window: &mut Window,
15266        cx: &mut Context<Self>,
15267    ) {
15268        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15269
15270        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15271            self.select_syntax_node_history.pop()
15272        {
15273            if let Some(selection) = selections.last_mut() {
15274                selection.reversed = is_selection_reversed;
15275            }
15276
15277            self.select_syntax_node_history.disable_clearing = true;
15278            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15279                s.select(selections.to_vec());
15280            });
15281            self.select_syntax_node_history.disable_clearing = false;
15282
15283            match scroll_behavior {
15284                SelectSyntaxNodeScrollBehavior::CursorTop => {
15285                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15286                }
15287                SelectSyntaxNodeScrollBehavior::FitSelection => {
15288                    self.request_autoscroll(Autoscroll::fit(), cx);
15289                }
15290                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15291                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15292                }
15293            }
15294        }
15295    }
15296
15297    pub fn unwrap_syntax_node(
15298        &mut self,
15299        _: &UnwrapSyntaxNode,
15300        window: &mut Window,
15301        cx: &mut Context<Self>,
15302    ) {
15303        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15304
15305        let buffer = self.buffer.read(cx).snapshot(cx);
15306        let selections = self
15307            .selections
15308            .all::<usize>(&self.display_snapshot(cx))
15309            .into_iter()
15310            // subtracting the offset requires sorting
15311            .sorted_by_key(|i| i.start);
15312
15313        let full_edits = selections
15314            .into_iter()
15315            .filter_map(|selection| {
15316                let child = if selection.is_empty()
15317                    && let Some((_, ancestor_range)) =
15318                        buffer.syntax_ancestor(selection.start..selection.end)
15319                {
15320                    ancestor_range
15321                } else {
15322                    selection.range()
15323                };
15324
15325                let mut parent = child.clone();
15326                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15327                    parent = ancestor_range;
15328                    if parent.start < child.start || parent.end > child.end {
15329                        break;
15330                    }
15331                }
15332
15333                if parent == child {
15334                    return None;
15335                }
15336                let text = buffer.text_for_range(child).collect::<String>();
15337                Some((selection.id, parent, text))
15338            })
15339            .collect::<Vec<_>>();
15340        if full_edits.is_empty() {
15341            return;
15342        }
15343
15344        self.transact(window, cx, |this, window, cx| {
15345            this.buffer.update(cx, |buffer, cx| {
15346                buffer.edit(
15347                    full_edits
15348                        .iter()
15349                        .map(|(_, p, t)| (p.clone(), t.clone()))
15350                        .collect::<Vec<_>>(),
15351                    None,
15352                    cx,
15353                );
15354            });
15355            this.change_selections(Default::default(), window, cx, |s| {
15356                let mut offset = 0;
15357                let mut selections = vec![];
15358                for (id, parent, text) in full_edits {
15359                    let start = parent.start - offset;
15360                    offset += parent.len() - text.len();
15361                    selections.push(Selection {
15362                        id,
15363                        start,
15364                        end: start + text.len(),
15365                        reversed: false,
15366                        goal: Default::default(),
15367                    });
15368                }
15369                s.select(selections);
15370            });
15371        });
15372    }
15373
15374    pub fn select_next_syntax_node(
15375        &mut self,
15376        _: &SelectNextSyntaxNode,
15377        window: &mut Window,
15378        cx: &mut Context<Self>,
15379    ) {
15380        let old_selections: Box<[_]> = self
15381            .selections
15382            .all::<usize>(&self.display_snapshot(cx))
15383            .into();
15384        if old_selections.is_empty() {
15385            return;
15386        }
15387
15388        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15389
15390        let buffer = self.buffer.read(cx).snapshot(cx);
15391        let mut selected_sibling = false;
15392
15393        let new_selections = old_selections
15394            .iter()
15395            .map(|selection| {
15396                let old_range = selection.start..selection.end;
15397
15398                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15399                    let new_range = node.byte_range();
15400                    selected_sibling = true;
15401                    Selection {
15402                        id: selection.id,
15403                        start: new_range.start,
15404                        end: new_range.end,
15405                        goal: SelectionGoal::None,
15406                        reversed: selection.reversed,
15407                    }
15408                } else {
15409                    selection.clone()
15410                }
15411            })
15412            .collect::<Vec<_>>();
15413
15414        if selected_sibling {
15415            self.change_selections(
15416                SelectionEffects::scroll(Autoscroll::fit()),
15417                window,
15418                cx,
15419                |s| {
15420                    s.select(new_selections);
15421                },
15422            );
15423        }
15424    }
15425
15426    pub fn select_prev_syntax_node(
15427        &mut self,
15428        _: &SelectPreviousSyntaxNode,
15429        window: &mut Window,
15430        cx: &mut Context<Self>,
15431    ) {
15432        let old_selections: Box<[_]> = self
15433            .selections
15434            .all::<usize>(&self.display_snapshot(cx))
15435            .into();
15436        if old_selections.is_empty() {
15437            return;
15438        }
15439
15440        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15441
15442        let buffer = self.buffer.read(cx).snapshot(cx);
15443        let mut selected_sibling = false;
15444
15445        let new_selections = old_selections
15446            .iter()
15447            .map(|selection| {
15448                let old_range = selection.start..selection.end;
15449
15450                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15451                    let new_range = node.byte_range();
15452                    selected_sibling = true;
15453                    Selection {
15454                        id: selection.id,
15455                        start: new_range.start,
15456                        end: new_range.end,
15457                        goal: SelectionGoal::None,
15458                        reversed: selection.reversed,
15459                    }
15460                } else {
15461                    selection.clone()
15462                }
15463            })
15464            .collect::<Vec<_>>();
15465
15466        if selected_sibling {
15467            self.change_selections(
15468                SelectionEffects::scroll(Autoscroll::fit()),
15469                window,
15470                cx,
15471                |s| {
15472                    s.select(new_selections);
15473                },
15474            );
15475        }
15476    }
15477
15478    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15479        if !EditorSettings::get_global(cx).gutter.runnables {
15480            self.clear_tasks();
15481            return Task::ready(());
15482        }
15483        let project = self.project().map(Entity::downgrade);
15484        let task_sources = self.lsp_task_sources(cx);
15485        let multi_buffer = self.buffer.downgrade();
15486        cx.spawn_in(window, async move |editor, cx| {
15487            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15488            let Some(project) = project.and_then(|p| p.upgrade()) else {
15489                return;
15490            };
15491            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15492                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15493            }) else {
15494                return;
15495            };
15496
15497            let hide_runnables = project
15498                .update(cx, |project, _| project.is_via_collab())
15499                .unwrap_or(true);
15500            if hide_runnables {
15501                return;
15502            }
15503            let new_rows =
15504                cx.background_spawn({
15505                    let snapshot = display_snapshot.clone();
15506                    async move {
15507                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15508                    }
15509                })
15510                    .await;
15511            let Ok(lsp_tasks) =
15512                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15513            else {
15514                return;
15515            };
15516            let lsp_tasks = lsp_tasks.await;
15517
15518            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15519                lsp_tasks
15520                    .into_iter()
15521                    .flat_map(|(kind, tasks)| {
15522                        tasks.into_iter().filter_map(move |(location, task)| {
15523                            Some((kind.clone(), location?, task))
15524                        })
15525                    })
15526                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15527                        let buffer = location.target.buffer;
15528                        let buffer_snapshot = buffer.read(cx).snapshot();
15529                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15530                            |(excerpt_id, snapshot, _)| {
15531                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15532                                    display_snapshot
15533                                        .buffer_snapshot()
15534                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15535                                } else {
15536                                    None
15537                                }
15538                            },
15539                        );
15540                        if let Some(offset) = offset {
15541                            let task_buffer_range =
15542                                location.target.range.to_point(&buffer_snapshot);
15543                            let context_buffer_range =
15544                                task_buffer_range.to_offset(&buffer_snapshot);
15545                            let context_range = BufferOffset(context_buffer_range.start)
15546                                ..BufferOffset(context_buffer_range.end);
15547
15548                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15549                                .or_insert_with(|| RunnableTasks {
15550                                    templates: Vec::new(),
15551                                    offset,
15552                                    column: task_buffer_range.start.column,
15553                                    extra_variables: HashMap::default(),
15554                                    context_range,
15555                                })
15556                                .templates
15557                                .push((kind, task.original_task().clone()));
15558                        }
15559
15560                        acc
15561                    })
15562            }) else {
15563                return;
15564            };
15565
15566            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15567                buffer.language_settings(cx).tasks.prefer_lsp
15568            }) else {
15569                return;
15570            };
15571
15572            let rows = Self::runnable_rows(
15573                project,
15574                display_snapshot,
15575                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15576                new_rows,
15577                cx.clone(),
15578            )
15579            .await;
15580            editor
15581                .update(cx, |editor, _| {
15582                    editor.clear_tasks();
15583                    for (key, mut value) in rows {
15584                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15585                            value.templates.extend(lsp_tasks.templates);
15586                        }
15587
15588                        editor.insert_tasks(key, value);
15589                    }
15590                    for (key, value) in lsp_tasks_by_rows {
15591                        editor.insert_tasks(key, value);
15592                    }
15593                })
15594                .ok();
15595        })
15596    }
15597    fn fetch_runnable_ranges(
15598        snapshot: &DisplaySnapshot,
15599        range: Range<Anchor>,
15600    ) -> Vec<language::RunnableRange> {
15601        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15602    }
15603
15604    fn runnable_rows(
15605        project: Entity<Project>,
15606        snapshot: DisplaySnapshot,
15607        prefer_lsp: bool,
15608        runnable_ranges: Vec<RunnableRange>,
15609        cx: AsyncWindowContext,
15610    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15611        cx.spawn(async move |cx| {
15612            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15613            for mut runnable in runnable_ranges {
15614                let Some(tasks) = cx
15615                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15616                    .ok()
15617                else {
15618                    continue;
15619                };
15620                let mut tasks = tasks.await;
15621
15622                if prefer_lsp {
15623                    tasks.retain(|(task_kind, _)| {
15624                        !matches!(task_kind, TaskSourceKind::Language { .. })
15625                    });
15626                }
15627                if tasks.is_empty() {
15628                    continue;
15629                }
15630
15631                let point = runnable
15632                    .run_range
15633                    .start
15634                    .to_point(&snapshot.buffer_snapshot());
15635                let Some(row) = snapshot
15636                    .buffer_snapshot()
15637                    .buffer_line_for_row(MultiBufferRow(point.row))
15638                    .map(|(_, range)| range.start.row)
15639                else {
15640                    continue;
15641                };
15642
15643                let context_range =
15644                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15645                runnable_rows.push((
15646                    (runnable.buffer_id, row),
15647                    RunnableTasks {
15648                        templates: tasks,
15649                        offset: snapshot
15650                            .buffer_snapshot()
15651                            .anchor_before(runnable.run_range.start),
15652                        context_range,
15653                        column: point.column,
15654                        extra_variables: runnable.extra_captures,
15655                    },
15656                ));
15657            }
15658            runnable_rows
15659        })
15660    }
15661
15662    fn templates_with_tags(
15663        project: &Entity<Project>,
15664        runnable: &mut Runnable,
15665        cx: &mut App,
15666    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15667        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15668            let (worktree_id, file) = project
15669                .buffer_for_id(runnable.buffer, cx)
15670                .and_then(|buffer| buffer.read(cx).file())
15671                .map(|file| (file.worktree_id(cx), file.clone()))
15672                .unzip();
15673
15674            (
15675                project.task_store().read(cx).task_inventory().cloned(),
15676                worktree_id,
15677                file,
15678            )
15679        });
15680
15681        let tags = mem::take(&mut runnable.tags);
15682        let language = runnable.language.clone();
15683        cx.spawn(async move |cx| {
15684            let mut templates_with_tags = Vec::new();
15685            if let Some(inventory) = inventory {
15686                for RunnableTag(tag) in tags {
15687                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15688                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15689                    }) else {
15690                        return templates_with_tags;
15691                    };
15692                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15693                        move |(_, template)| {
15694                            template.tags.iter().any(|source_tag| source_tag == &tag)
15695                        },
15696                    ));
15697                }
15698            }
15699            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15700
15701            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15702                // Strongest source wins; if we have worktree tag binding, prefer that to
15703                // global and language bindings;
15704                // if we have a global binding, prefer that to language binding.
15705                let first_mismatch = templates_with_tags
15706                    .iter()
15707                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15708                if let Some(index) = first_mismatch {
15709                    templates_with_tags.truncate(index);
15710                }
15711            }
15712
15713            templates_with_tags
15714        })
15715    }
15716
15717    pub fn move_to_enclosing_bracket(
15718        &mut self,
15719        _: &MoveToEnclosingBracket,
15720        window: &mut Window,
15721        cx: &mut Context<Self>,
15722    ) {
15723        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15724        self.change_selections(Default::default(), window, cx, |s| {
15725            s.move_offsets_with(|snapshot, selection| {
15726                let Some(enclosing_bracket_ranges) =
15727                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15728                else {
15729                    return;
15730                };
15731
15732                let mut best_length = usize::MAX;
15733                let mut best_inside = false;
15734                let mut best_in_bracket_range = false;
15735                let mut best_destination = None;
15736                for (open, close) in enclosing_bracket_ranges {
15737                    let close = close.to_inclusive();
15738                    let length = close.end() - open.start;
15739                    let inside = selection.start >= open.end && selection.end <= *close.start();
15740                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15741                        || close.contains(&selection.head());
15742
15743                    // If best is next to a bracket and current isn't, skip
15744                    if !in_bracket_range && best_in_bracket_range {
15745                        continue;
15746                    }
15747
15748                    // Prefer smaller lengths unless best is inside and current isn't
15749                    if length > best_length && (best_inside || !inside) {
15750                        continue;
15751                    }
15752
15753                    best_length = length;
15754                    best_inside = inside;
15755                    best_in_bracket_range = in_bracket_range;
15756                    best_destination = Some(
15757                        if close.contains(&selection.start) && close.contains(&selection.end) {
15758                            if inside { open.end } else { open.start }
15759                        } else if inside {
15760                            *close.start()
15761                        } else {
15762                            *close.end()
15763                        },
15764                    );
15765                }
15766
15767                if let Some(destination) = best_destination {
15768                    selection.collapse_to(destination, SelectionGoal::None);
15769                }
15770            })
15771        });
15772    }
15773
15774    pub fn undo_selection(
15775        &mut self,
15776        _: &UndoSelection,
15777        window: &mut Window,
15778        cx: &mut Context<Self>,
15779    ) {
15780        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15781        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15782            self.selection_history.mode = SelectionHistoryMode::Undoing;
15783            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15784                this.end_selection(window, cx);
15785                this.change_selections(
15786                    SelectionEffects::scroll(Autoscroll::newest()),
15787                    window,
15788                    cx,
15789                    |s| s.select_anchors(entry.selections.to_vec()),
15790                );
15791            });
15792            self.selection_history.mode = SelectionHistoryMode::Normal;
15793
15794            self.select_next_state = entry.select_next_state;
15795            self.select_prev_state = entry.select_prev_state;
15796            self.add_selections_state = entry.add_selections_state;
15797        }
15798    }
15799
15800    pub fn redo_selection(
15801        &mut self,
15802        _: &RedoSelection,
15803        window: &mut Window,
15804        cx: &mut Context<Self>,
15805    ) {
15806        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15807        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15808            self.selection_history.mode = SelectionHistoryMode::Redoing;
15809            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15810                this.end_selection(window, cx);
15811                this.change_selections(
15812                    SelectionEffects::scroll(Autoscroll::newest()),
15813                    window,
15814                    cx,
15815                    |s| s.select_anchors(entry.selections.to_vec()),
15816                );
15817            });
15818            self.selection_history.mode = SelectionHistoryMode::Normal;
15819
15820            self.select_next_state = entry.select_next_state;
15821            self.select_prev_state = entry.select_prev_state;
15822            self.add_selections_state = entry.add_selections_state;
15823        }
15824    }
15825
15826    pub fn expand_excerpts(
15827        &mut self,
15828        action: &ExpandExcerpts,
15829        _: &mut Window,
15830        cx: &mut Context<Self>,
15831    ) {
15832        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15833    }
15834
15835    pub fn expand_excerpts_down(
15836        &mut self,
15837        action: &ExpandExcerptsDown,
15838        _: &mut Window,
15839        cx: &mut Context<Self>,
15840    ) {
15841        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15842    }
15843
15844    pub fn expand_excerpts_up(
15845        &mut self,
15846        action: &ExpandExcerptsUp,
15847        _: &mut Window,
15848        cx: &mut Context<Self>,
15849    ) {
15850        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15851    }
15852
15853    pub fn expand_excerpts_for_direction(
15854        &mut self,
15855        lines: u32,
15856        direction: ExpandExcerptDirection,
15857
15858        cx: &mut Context<Self>,
15859    ) {
15860        let selections = self.selections.disjoint_anchors_arc();
15861
15862        let lines = if lines == 0 {
15863            EditorSettings::get_global(cx).expand_excerpt_lines
15864        } else {
15865            lines
15866        };
15867
15868        self.buffer.update(cx, |buffer, cx| {
15869            let snapshot = buffer.snapshot(cx);
15870            let mut excerpt_ids = selections
15871                .iter()
15872                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15873                .collect::<Vec<_>>();
15874            excerpt_ids.sort();
15875            excerpt_ids.dedup();
15876            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15877        })
15878    }
15879
15880    pub fn expand_excerpt(
15881        &mut self,
15882        excerpt: ExcerptId,
15883        direction: ExpandExcerptDirection,
15884        window: &mut Window,
15885        cx: &mut Context<Self>,
15886    ) {
15887        let current_scroll_position = self.scroll_position(cx);
15888        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15889        let mut scroll = None;
15890
15891        if direction == ExpandExcerptDirection::Down {
15892            let multi_buffer = self.buffer.read(cx);
15893            let snapshot = multi_buffer.snapshot(cx);
15894            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15895                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15896                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
15897            {
15898                let buffer_snapshot = buffer.read(cx).snapshot();
15899                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15900                let last_row = buffer_snapshot.max_point().row;
15901                let lines_below = last_row.saturating_sub(excerpt_end_row);
15902                if lines_below >= lines_to_expand {
15903                    scroll = Some(
15904                        current_scroll_position
15905                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
15906                    );
15907                }
15908            }
15909        }
15910        if direction == ExpandExcerptDirection::Up
15911            && self
15912                .buffer
15913                .read(cx)
15914                .snapshot(cx)
15915                .excerpt_before(excerpt)
15916                .is_none()
15917        {
15918            scroll = Some(current_scroll_position);
15919        }
15920
15921        self.buffer.update(cx, |buffer, cx| {
15922            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15923        });
15924
15925        if let Some(new_scroll_position) = scroll {
15926            self.set_scroll_position(new_scroll_position, window, cx);
15927        }
15928    }
15929
15930    pub fn go_to_singleton_buffer_point(
15931        &mut self,
15932        point: Point,
15933        window: &mut Window,
15934        cx: &mut Context<Self>,
15935    ) {
15936        self.go_to_singleton_buffer_range(point..point, window, cx);
15937    }
15938
15939    pub fn go_to_singleton_buffer_range(
15940        &mut self,
15941        range: Range<Point>,
15942        window: &mut Window,
15943        cx: &mut Context<Self>,
15944    ) {
15945        let multibuffer = self.buffer().read(cx);
15946        let Some(buffer) = multibuffer.as_singleton() else {
15947            return;
15948        };
15949        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15950            return;
15951        };
15952        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15953            return;
15954        };
15955        self.change_selections(
15956            SelectionEffects::default().nav_history(true),
15957            window,
15958            cx,
15959            |s| s.select_anchor_ranges([start..end]),
15960        );
15961    }
15962
15963    pub fn go_to_diagnostic(
15964        &mut self,
15965        action: &GoToDiagnostic,
15966        window: &mut Window,
15967        cx: &mut Context<Self>,
15968    ) {
15969        if !self.diagnostics_enabled() {
15970            return;
15971        }
15972        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15973        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15974    }
15975
15976    pub fn go_to_prev_diagnostic(
15977        &mut self,
15978        action: &GoToPreviousDiagnostic,
15979        window: &mut Window,
15980        cx: &mut Context<Self>,
15981    ) {
15982        if !self.diagnostics_enabled() {
15983            return;
15984        }
15985        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15986        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15987    }
15988
15989    pub fn go_to_diagnostic_impl(
15990        &mut self,
15991        direction: Direction,
15992        severity: GoToDiagnosticSeverityFilter,
15993        window: &mut Window,
15994        cx: &mut Context<Self>,
15995    ) {
15996        let buffer = self.buffer.read(cx).snapshot(cx);
15997        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
15998
15999        let mut active_group_id = None;
16000        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16001            && active_group.active_range.start.to_offset(&buffer) == selection.start
16002        {
16003            active_group_id = Some(active_group.group_id);
16004        }
16005
16006        fn filtered<'a>(
16007            severity: GoToDiagnosticSeverityFilter,
16008            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
16009        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
16010            diagnostics
16011                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16012                .filter(|entry| entry.range.start != entry.range.end)
16013                .filter(|entry| !entry.diagnostic.is_unnecessary)
16014        }
16015
16016        let before = filtered(
16017            severity,
16018            buffer
16019                .diagnostics_in_range(0..selection.start)
16020                .filter(|entry| entry.range.start <= selection.start),
16021        );
16022        let after = filtered(
16023            severity,
16024            buffer
16025                .diagnostics_in_range(selection.start..buffer.len())
16026                .filter(|entry| entry.range.start >= selection.start),
16027        );
16028
16029        let mut found: Option<DiagnosticEntryRef<usize>> = None;
16030        if direction == Direction::Prev {
16031            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16032            {
16033                for diagnostic in prev_diagnostics.into_iter().rev() {
16034                    if diagnostic.range.start != selection.start
16035                        || active_group_id
16036                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16037                    {
16038                        found = Some(diagnostic);
16039                        break 'outer;
16040                    }
16041                }
16042            }
16043        } else {
16044            for diagnostic in after.chain(before) {
16045                if diagnostic.range.start != selection.start
16046                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16047                {
16048                    found = Some(diagnostic);
16049                    break;
16050                }
16051            }
16052        }
16053        let Some(next_diagnostic) = found else {
16054            return;
16055        };
16056
16057        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16058        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16059            return;
16060        };
16061        let snapshot = self.snapshot(window, cx);
16062        if snapshot.intersects_fold(next_diagnostic.range.start) {
16063            self.unfold_ranges(
16064                std::slice::from_ref(&next_diagnostic.range),
16065                true,
16066                false,
16067                cx,
16068            );
16069        }
16070        self.change_selections(Default::default(), window, cx, |s| {
16071            s.select_ranges(vec![
16072                next_diagnostic.range.start..next_diagnostic.range.start,
16073            ])
16074        });
16075        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16076        self.refresh_edit_prediction(false, true, window, cx);
16077    }
16078
16079    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16080        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16081        let snapshot = self.snapshot(window, cx);
16082        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16083        self.go_to_hunk_before_or_after_position(
16084            &snapshot,
16085            selection.head(),
16086            Direction::Next,
16087            window,
16088            cx,
16089        );
16090    }
16091
16092    pub fn go_to_hunk_before_or_after_position(
16093        &mut self,
16094        snapshot: &EditorSnapshot,
16095        position: Point,
16096        direction: Direction,
16097        window: &mut Window,
16098        cx: &mut Context<Editor>,
16099    ) {
16100        let row = if direction == Direction::Next {
16101            self.hunk_after_position(snapshot, position)
16102                .map(|hunk| hunk.row_range.start)
16103        } else {
16104            self.hunk_before_position(snapshot, position)
16105        };
16106
16107        if let Some(row) = row {
16108            let destination = Point::new(row.0, 0);
16109            let autoscroll = Autoscroll::center();
16110
16111            self.unfold_ranges(&[destination..destination], false, false, cx);
16112            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16113                s.select_ranges([destination..destination]);
16114            });
16115        }
16116    }
16117
16118    fn hunk_after_position(
16119        &mut self,
16120        snapshot: &EditorSnapshot,
16121        position: Point,
16122    ) -> Option<MultiBufferDiffHunk> {
16123        snapshot
16124            .buffer_snapshot()
16125            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16126            .find(|hunk| hunk.row_range.start.0 > position.row)
16127            .or_else(|| {
16128                snapshot
16129                    .buffer_snapshot()
16130                    .diff_hunks_in_range(Point::zero()..position)
16131                    .find(|hunk| hunk.row_range.end.0 < position.row)
16132            })
16133    }
16134
16135    fn go_to_prev_hunk(
16136        &mut self,
16137        _: &GoToPreviousHunk,
16138        window: &mut Window,
16139        cx: &mut Context<Self>,
16140    ) {
16141        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16142        let snapshot = self.snapshot(window, cx);
16143        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16144        self.go_to_hunk_before_or_after_position(
16145            &snapshot,
16146            selection.head(),
16147            Direction::Prev,
16148            window,
16149            cx,
16150        );
16151    }
16152
16153    fn hunk_before_position(
16154        &mut self,
16155        snapshot: &EditorSnapshot,
16156        position: Point,
16157    ) -> Option<MultiBufferRow> {
16158        snapshot
16159            .buffer_snapshot()
16160            .diff_hunk_before(position)
16161            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16162    }
16163
16164    fn go_to_next_change(
16165        &mut self,
16166        _: &GoToNextChange,
16167        window: &mut Window,
16168        cx: &mut Context<Self>,
16169    ) {
16170        if let Some(selections) = self
16171            .change_list
16172            .next_change(1, Direction::Next)
16173            .map(|s| s.to_vec())
16174        {
16175            self.change_selections(Default::default(), window, cx, |s| {
16176                let map = s.display_map();
16177                s.select_display_ranges(selections.iter().map(|a| {
16178                    let point = a.to_display_point(&map);
16179                    point..point
16180                }))
16181            })
16182        }
16183    }
16184
16185    fn go_to_previous_change(
16186        &mut self,
16187        _: &GoToPreviousChange,
16188        window: &mut Window,
16189        cx: &mut Context<Self>,
16190    ) {
16191        if let Some(selections) = self
16192            .change_list
16193            .next_change(1, Direction::Prev)
16194            .map(|s| s.to_vec())
16195        {
16196            self.change_selections(Default::default(), window, cx, |s| {
16197                let map = s.display_map();
16198                s.select_display_ranges(selections.iter().map(|a| {
16199                    let point = a.to_display_point(&map);
16200                    point..point
16201                }))
16202            })
16203        }
16204    }
16205
16206    pub fn go_to_next_document_highlight(
16207        &mut self,
16208        _: &GoToNextDocumentHighlight,
16209        window: &mut Window,
16210        cx: &mut Context<Self>,
16211    ) {
16212        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16213    }
16214
16215    pub fn go_to_prev_document_highlight(
16216        &mut self,
16217        _: &GoToPreviousDocumentHighlight,
16218        window: &mut Window,
16219        cx: &mut Context<Self>,
16220    ) {
16221        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16222    }
16223
16224    pub fn go_to_document_highlight_before_or_after_position(
16225        &mut self,
16226        direction: Direction,
16227        window: &mut Window,
16228        cx: &mut Context<Editor>,
16229    ) {
16230        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16231        let snapshot = self.snapshot(window, cx);
16232        let buffer = &snapshot.buffer_snapshot();
16233        let position = self
16234            .selections
16235            .newest::<Point>(&snapshot.display_snapshot)
16236            .head();
16237        let anchor_position = buffer.anchor_after(position);
16238
16239        // Get all document highlights (both read and write)
16240        let mut all_highlights = Vec::new();
16241
16242        if let Some((_, read_highlights)) = self
16243            .background_highlights
16244            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16245        {
16246            all_highlights.extend(read_highlights.iter());
16247        }
16248
16249        if let Some((_, write_highlights)) = self
16250            .background_highlights
16251            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16252        {
16253            all_highlights.extend(write_highlights.iter());
16254        }
16255
16256        if all_highlights.is_empty() {
16257            return;
16258        }
16259
16260        // Sort highlights by position
16261        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16262
16263        let target_highlight = match direction {
16264            Direction::Next => {
16265                // Find the first highlight after the current position
16266                all_highlights
16267                    .iter()
16268                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16269            }
16270            Direction::Prev => {
16271                // Find the last highlight before the current position
16272                all_highlights
16273                    .iter()
16274                    .rev()
16275                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16276            }
16277        };
16278
16279        if let Some(highlight) = target_highlight {
16280            let destination = highlight.start.to_point(buffer);
16281            let autoscroll = Autoscroll::center();
16282
16283            self.unfold_ranges(&[destination..destination], false, false, cx);
16284            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16285                s.select_ranges([destination..destination]);
16286            });
16287        }
16288    }
16289
16290    fn go_to_line<T: 'static>(
16291        &mut self,
16292        position: Anchor,
16293        highlight_color: Option<Hsla>,
16294        window: &mut Window,
16295        cx: &mut Context<Self>,
16296    ) {
16297        let snapshot = self.snapshot(window, cx).display_snapshot;
16298        let position = position.to_point(&snapshot.buffer_snapshot());
16299        let start = snapshot
16300            .buffer_snapshot()
16301            .clip_point(Point::new(position.row, 0), Bias::Left);
16302        let end = start + Point::new(1, 0);
16303        let start = snapshot.buffer_snapshot().anchor_before(start);
16304        let end = snapshot.buffer_snapshot().anchor_before(end);
16305
16306        self.highlight_rows::<T>(
16307            start..end,
16308            highlight_color
16309                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16310            Default::default(),
16311            cx,
16312        );
16313
16314        if self.buffer.read(cx).is_singleton() {
16315            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16316        }
16317    }
16318
16319    pub fn go_to_definition(
16320        &mut self,
16321        _: &GoToDefinition,
16322        window: &mut Window,
16323        cx: &mut Context<Self>,
16324    ) -> Task<Result<Navigated>> {
16325        let definition =
16326            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16327        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16328        cx.spawn_in(window, async move |editor, cx| {
16329            if definition.await? == Navigated::Yes {
16330                return Ok(Navigated::Yes);
16331            }
16332            match fallback_strategy {
16333                GoToDefinitionFallback::None => Ok(Navigated::No),
16334                GoToDefinitionFallback::FindAllReferences => {
16335                    match editor.update_in(cx, |editor, window, cx| {
16336                        editor.find_all_references(&FindAllReferences, window, cx)
16337                    })? {
16338                        Some(references) => references.await,
16339                        None => Ok(Navigated::No),
16340                    }
16341                }
16342            }
16343        })
16344    }
16345
16346    pub fn go_to_declaration(
16347        &mut self,
16348        _: &GoToDeclaration,
16349        window: &mut Window,
16350        cx: &mut Context<Self>,
16351    ) -> Task<Result<Navigated>> {
16352        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16353    }
16354
16355    pub fn go_to_declaration_split(
16356        &mut self,
16357        _: &GoToDeclaration,
16358        window: &mut Window,
16359        cx: &mut Context<Self>,
16360    ) -> Task<Result<Navigated>> {
16361        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16362    }
16363
16364    pub fn go_to_implementation(
16365        &mut self,
16366        _: &GoToImplementation,
16367        window: &mut Window,
16368        cx: &mut Context<Self>,
16369    ) -> Task<Result<Navigated>> {
16370        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16371    }
16372
16373    pub fn go_to_implementation_split(
16374        &mut self,
16375        _: &GoToImplementationSplit,
16376        window: &mut Window,
16377        cx: &mut Context<Self>,
16378    ) -> Task<Result<Navigated>> {
16379        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16380    }
16381
16382    pub fn go_to_type_definition(
16383        &mut self,
16384        _: &GoToTypeDefinition,
16385        window: &mut Window,
16386        cx: &mut Context<Self>,
16387    ) -> Task<Result<Navigated>> {
16388        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16389    }
16390
16391    pub fn go_to_definition_split(
16392        &mut self,
16393        _: &GoToDefinitionSplit,
16394        window: &mut Window,
16395        cx: &mut Context<Self>,
16396    ) -> Task<Result<Navigated>> {
16397        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16398    }
16399
16400    pub fn go_to_type_definition_split(
16401        &mut self,
16402        _: &GoToTypeDefinitionSplit,
16403        window: &mut Window,
16404        cx: &mut Context<Self>,
16405    ) -> Task<Result<Navigated>> {
16406        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16407    }
16408
16409    fn go_to_definition_of_kind(
16410        &mut self,
16411        kind: GotoDefinitionKind,
16412        split: bool,
16413        window: &mut Window,
16414        cx: &mut Context<Self>,
16415    ) -> Task<Result<Navigated>> {
16416        let Some(provider) = self.semantics_provider.clone() else {
16417            return Task::ready(Ok(Navigated::No));
16418        };
16419        let head = self
16420            .selections
16421            .newest::<usize>(&self.display_snapshot(cx))
16422            .head();
16423        let buffer = self.buffer.read(cx);
16424        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16425            return Task::ready(Ok(Navigated::No));
16426        };
16427        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16428            return Task::ready(Ok(Navigated::No));
16429        };
16430
16431        cx.spawn_in(window, async move |editor, cx| {
16432            let Some(definitions) = definitions.await? else {
16433                return Ok(Navigated::No);
16434            };
16435            let navigated = editor
16436                .update_in(cx, |editor, window, cx| {
16437                    editor.navigate_to_hover_links(
16438                        Some(kind),
16439                        definitions
16440                            .into_iter()
16441                            .filter(|location| {
16442                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16443                            })
16444                            .map(HoverLink::Text)
16445                            .collect::<Vec<_>>(),
16446                        split,
16447                        window,
16448                        cx,
16449                    )
16450                })?
16451                .await?;
16452            anyhow::Ok(navigated)
16453        })
16454    }
16455
16456    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16457        let selection = self.selections.newest_anchor();
16458        let head = selection.head();
16459        let tail = selection.tail();
16460
16461        let Some((buffer, start_position)) =
16462            self.buffer.read(cx).text_anchor_for_position(head, cx)
16463        else {
16464            return;
16465        };
16466
16467        let end_position = if head != tail {
16468            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16469                return;
16470            };
16471            Some(pos)
16472        } else {
16473            None
16474        };
16475
16476        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16477            let url = if let Some(end_pos) = end_position {
16478                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16479            } else {
16480                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16481            };
16482
16483            if let Some(url) = url {
16484                cx.update(|window, cx| {
16485                    if parse_zed_link(&url, cx).is_some() {
16486                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16487                    } else {
16488                        cx.open_url(&url);
16489                    }
16490                })?;
16491            }
16492
16493            anyhow::Ok(())
16494        });
16495
16496        url_finder.detach();
16497    }
16498
16499    pub fn open_selected_filename(
16500        &mut self,
16501        _: &OpenSelectedFilename,
16502        window: &mut Window,
16503        cx: &mut Context<Self>,
16504    ) {
16505        let Some(workspace) = self.workspace() else {
16506            return;
16507        };
16508
16509        let position = self.selections.newest_anchor().head();
16510
16511        let Some((buffer, buffer_position)) =
16512            self.buffer.read(cx).text_anchor_for_position(position, cx)
16513        else {
16514            return;
16515        };
16516
16517        let project = self.project.clone();
16518
16519        cx.spawn_in(window, async move |_, cx| {
16520            let result = find_file(&buffer, project, buffer_position, cx).await;
16521
16522            if let Some((_, path)) = result {
16523                workspace
16524                    .update_in(cx, |workspace, window, cx| {
16525                        workspace.open_resolved_path(path, window, cx)
16526                    })?
16527                    .await?;
16528            }
16529            anyhow::Ok(())
16530        })
16531        .detach();
16532    }
16533
16534    pub(crate) fn navigate_to_hover_links(
16535        &mut self,
16536        kind: Option<GotoDefinitionKind>,
16537        definitions: Vec<HoverLink>,
16538        split: bool,
16539        window: &mut Window,
16540        cx: &mut Context<Editor>,
16541    ) -> Task<Result<Navigated>> {
16542        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16543        let mut first_url_or_file = None;
16544        let definitions: Vec<_> = definitions
16545            .into_iter()
16546            .filter_map(|def| match def {
16547                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16548                HoverLink::InlayHint(lsp_location, server_id) => {
16549                    let computation =
16550                        self.compute_target_location(lsp_location, server_id, window, cx);
16551                    Some(cx.background_spawn(computation))
16552                }
16553                HoverLink::Url(url) => {
16554                    first_url_or_file = Some(Either::Left(url));
16555                    None
16556                }
16557                HoverLink::File(path) => {
16558                    first_url_or_file = Some(Either::Right(path));
16559                    None
16560                }
16561            })
16562            .collect();
16563
16564        let workspace = self.workspace();
16565
16566        cx.spawn_in(window, async move |editor, cx| {
16567            let locations: Vec<Location> = future::join_all(definitions)
16568                .await
16569                .into_iter()
16570                .filter_map(|location| location.transpose())
16571                .collect::<Result<_>>()
16572                .context("location tasks")?;
16573            let mut locations = cx.update(|_, cx| {
16574                locations
16575                    .into_iter()
16576                    .map(|location| {
16577                        let buffer = location.buffer.read(cx);
16578                        (location.buffer, location.range.to_point(buffer))
16579                    })
16580                    .into_group_map()
16581            })?;
16582            let mut num_locations = 0;
16583            for ranges in locations.values_mut() {
16584                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16585                ranges.dedup();
16586                num_locations += ranges.len();
16587            }
16588
16589            if num_locations > 1 {
16590                let Some(workspace) = workspace else {
16591                    return Ok(Navigated::No);
16592                };
16593
16594                let tab_kind = match kind {
16595                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16596                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16597                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16598                    Some(GotoDefinitionKind::Type) => "Types",
16599                };
16600                let title = editor
16601                    .update_in(cx, |_, _, cx| {
16602                        let target = locations
16603                            .iter()
16604                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16605                            .map(|(buffer, location)| {
16606                                buffer
16607                                    .read(cx)
16608                                    .text_for_range(location.clone())
16609                                    .collect::<String>()
16610                            })
16611                            .filter(|text| !text.contains('\n'))
16612                            .unique()
16613                            .take(3)
16614                            .join(", ");
16615                        if target.is_empty() {
16616                            tab_kind.to_owned()
16617                        } else {
16618                            format!("{tab_kind} for {target}")
16619                        }
16620                    })
16621                    .context("buffer title")?;
16622
16623                let opened = workspace
16624                    .update_in(cx, |workspace, window, cx| {
16625                        Self::open_locations_in_multibuffer(
16626                            workspace,
16627                            locations,
16628                            title,
16629                            split,
16630                            MultibufferSelectionMode::First,
16631                            window,
16632                            cx,
16633                        )
16634                    })
16635                    .is_ok();
16636
16637                anyhow::Ok(Navigated::from_bool(opened))
16638            } else if num_locations == 0 {
16639                // If there is one url or file, open it directly
16640                match first_url_or_file {
16641                    Some(Either::Left(url)) => {
16642                        cx.update(|_, cx| cx.open_url(&url))?;
16643                        Ok(Navigated::Yes)
16644                    }
16645                    Some(Either::Right(path)) => {
16646                        let Some(workspace) = workspace else {
16647                            return Ok(Navigated::No);
16648                        };
16649
16650                        workspace
16651                            .update_in(cx, |workspace, window, cx| {
16652                                workspace.open_resolved_path(path, window, cx)
16653                            })?
16654                            .await?;
16655                        Ok(Navigated::Yes)
16656                    }
16657                    None => Ok(Navigated::No),
16658                }
16659            } else {
16660                let Some(workspace) = workspace else {
16661                    return Ok(Navigated::No);
16662                };
16663
16664                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16665                let target_range = target_ranges.first().unwrap().clone();
16666
16667                editor.update_in(cx, |editor, window, cx| {
16668                    let range = target_range.to_point(target_buffer.read(cx));
16669                    let range = editor.range_for_match(&range, false);
16670                    let range = collapse_multiline_range(range);
16671
16672                    if !split
16673                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16674                    {
16675                        editor.go_to_singleton_buffer_range(range, window, cx);
16676                    } else {
16677                        let pane = workspace.read(cx).active_pane().clone();
16678                        window.defer(cx, move |window, cx| {
16679                            let target_editor: Entity<Self> =
16680                                workspace.update(cx, |workspace, cx| {
16681                                    let pane = if split {
16682                                        workspace.adjacent_pane(window, cx)
16683                                    } else {
16684                                        workspace.active_pane().clone()
16685                                    };
16686
16687                                    workspace.open_project_item(
16688                                        pane,
16689                                        target_buffer.clone(),
16690                                        true,
16691                                        true,
16692                                        window,
16693                                        cx,
16694                                    )
16695                                });
16696                            target_editor.update(cx, |target_editor, cx| {
16697                                // When selecting a definition in a different buffer, disable the nav history
16698                                // to avoid creating a history entry at the previous cursor location.
16699                                pane.update(cx, |pane, _| pane.disable_history());
16700                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16701                                pane.update(cx, |pane, _| pane.enable_history());
16702                            });
16703                        });
16704                    }
16705                    Navigated::Yes
16706                })
16707            }
16708        })
16709    }
16710
16711    fn compute_target_location(
16712        &self,
16713        lsp_location: lsp::Location,
16714        server_id: LanguageServerId,
16715        window: &mut Window,
16716        cx: &mut Context<Self>,
16717    ) -> Task<anyhow::Result<Option<Location>>> {
16718        let Some(project) = self.project.clone() else {
16719            return Task::ready(Ok(None));
16720        };
16721
16722        cx.spawn_in(window, async move |editor, cx| {
16723            let location_task = editor.update(cx, |_, cx| {
16724                project.update(cx, |project, cx| {
16725                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16726                })
16727            })?;
16728            let location = Some({
16729                let target_buffer_handle = location_task.await.context("open local buffer")?;
16730                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16731                    let target_start = target_buffer
16732                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16733                    let target_end = target_buffer
16734                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16735                    target_buffer.anchor_after(target_start)
16736                        ..target_buffer.anchor_before(target_end)
16737                })?;
16738                Location {
16739                    buffer: target_buffer_handle,
16740                    range,
16741                }
16742            });
16743            Ok(location)
16744        })
16745    }
16746
16747    fn go_to_next_reference(
16748        &mut self,
16749        _: &GoToNextReference,
16750        window: &mut Window,
16751        cx: &mut Context<Self>,
16752    ) {
16753        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
16754        if let Some(task) = task {
16755            task.detach();
16756        };
16757    }
16758
16759    fn go_to_prev_reference(
16760        &mut self,
16761        _: &GoToPreviousReference,
16762        window: &mut Window,
16763        cx: &mut Context<Self>,
16764    ) {
16765        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
16766        if let Some(task) = task {
16767            task.detach();
16768        };
16769    }
16770
16771    pub fn go_to_reference_before_or_after_position(
16772        &mut self,
16773        direction: Direction,
16774        count: usize,
16775        window: &mut Window,
16776        cx: &mut Context<Self>,
16777    ) -> Option<Task<Result<()>>> {
16778        let selection = self.selections.newest_anchor();
16779        let head = selection.head();
16780
16781        let multi_buffer = self.buffer.read(cx);
16782
16783        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
16784        let workspace = self.workspace()?;
16785        let project = workspace.read(cx).project().clone();
16786        let references =
16787            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
16788        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
16789            let Some(locations) = references.await? else {
16790                return Ok(());
16791            };
16792
16793            if locations.is_empty() {
16794                // totally normal - the cursor may be on something which is not
16795                // a symbol (e.g. a keyword)
16796                log::info!("no references found under cursor");
16797                return Ok(());
16798            }
16799
16800            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
16801
16802            let multi_buffer_snapshot =
16803                multi_buffer.read_with(cx, |multi_buffer, cx| multi_buffer.snapshot(cx))?;
16804
16805            let (locations, current_location_index) =
16806                multi_buffer.update(cx, |multi_buffer, cx| {
16807                    let mut locations = locations
16808                        .into_iter()
16809                        .filter_map(|loc| {
16810                            let start = multi_buffer.buffer_anchor_to_anchor(
16811                                &loc.buffer,
16812                                loc.range.start,
16813                                cx,
16814                            )?;
16815                            let end = multi_buffer.buffer_anchor_to_anchor(
16816                                &loc.buffer,
16817                                loc.range.end,
16818                                cx,
16819                            )?;
16820                            Some(start..end)
16821                        })
16822                        .collect::<Vec<_>>();
16823
16824                    // There is an O(n) implementation, but given this list will be
16825                    // small (usually <100 items), the extra O(log(n)) factor isn't
16826                    // worth the (surprisingly large amount of) extra complexity.
16827                    locations
16828                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
16829
16830                    let head_offset = head.to_offset(&multi_buffer_snapshot);
16831
16832                    let current_location_index = locations.iter().position(|loc| {
16833                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
16834                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
16835                    });
16836
16837                    (locations, current_location_index)
16838                })?;
16839
16840            let Some(current_location_index) = current_location_index else {
16841                // This indicates something has gone wrong, because we already
16842                // handle the "no references" case above
16843                log::error!(
16844                    "failed to find current reference under cursor. Total references: {}",
16845                    locations.len()
16846                );
16847                return Ok(());
16848            };
16849
16850            let destination_location_index = match direction {
16851                Direction::Next => (current_location_index + count) % locations.len(),
16852                Direction::Prev => {
16853                    (current_location_index + locations.len() - count % locations.len())
16854                        % locations.len()
16855                }
16856            };
16857
16858            // TODO(cameron): is this needed?
16859            // the thinking is to avoid "jumping to the current location" (avoid
16860            // polluting "jumplist" in vim terms)
16861            if current_location_index == destination_location_index {
16862                return Ok(());
16863            }
16864
16865            let Range { start, end } = locations[destination_location_index];
16866
16867            editor.update_in(cx, |editor, window, cx| {
16868                let effects = SelectionEffects::default();
16869
16870                editor.unfold_ranges(&[start..end], false, false, cx);
16871                editor.change_selections(effects, window, cx, |s| {
16872                    s.select_ranges([start..start]);
16873                });
16874            })?;
16875
16876            Ok(())
16877        }))
16878    }
16879
16880    pub fn find_all_references(
16881        &mut self,
16882        _: &FindAllReferences,
16883        window: &mut Window,
16884        cx: &mut Context<Self>,
16885    ) -> Option<Task<Result<Navigated>>> {
16886        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
16887        let multi_buffer = self.buffer.read(cx);
16888        let head = selection.head();
16889
16890        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16891        let head_anchor = multi_buffer_snapshot.anchor_at(
16892            head,
16893            if head < selection.tail() {
16894                Bias::Right
16895            } else {
16896                Bias::Left
16897            },
16898        );
16899
16900        match self
16901            .find_all_references_task_sources
16902            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16903        {
16904            Ok(_) => {
16905                log::info!(
16906                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16907                );
16908                return None;
16909            }
16910            Err(i) => {
16911                self.find_all_references_task_sources.insert(i, head_anchor);
16912            }
16913        }
16914
16915        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16916        let workspace = self.workspace()?;
16917        let project = workspace.read(cx).project().clone();
16918        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16919        Some(cx.spawn_in(window, async move |editor, cx| {
16920            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16921                if let Ok(i) = editor
16922                    .find_all_references_task_sources
16923                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16924                {
16925                    editor.find_all_references_task_sources.remove(i);
16926                }
16927            });
16928
16929            let Some(locations) = references.await? else {
16930                return anyhow::Ok(Navigated::No);
16931            };
16932            let mut locations = cx.update(|_, cx| {
16933                locations
16934                    .into_iter()
16935                    .map(|location| {
16936                        let buffer = location.buffer.read(cx);
16937                        (location.buffer, location.range.to_point(buffer))
16938                    })
16939                    .into_group_map()
16940            })?;
16941            if locations.is_empty() {
16942                return anyhow::Ok(Navigated::No);
16943            }
16944            for ranges in locations.values_mut() {
16945                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16946                ranges.dedup();
16947            }
16948
16949            workspace.update_in(cx, |workspace, window, cx| {
16950                let target = locations
16951                    .iter()
16952                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16953                    .map(|(buffer, location)| {
16954                        buffer
16955                            .read(cx)
16956                            .text_for_range(location.clone())
16957                            .collect::<String>()
16958                    })
16959                    .filter(|text| !text.contains('\n'))
16960                    .unique()
16961                    .take(3)
16962                    .join(", ");
16963                let title = if target.is_empty() {
16964                    "References".to_owned()
16965                } else {
16966                    format!("References to {target}")
16967                };
16968                Self::open_locations_in_multibuffer(
16969                    workspace,
16970                    locations,
16971                    title,
16972                    false,
16973                    MultibufferSelectionMode::First,
16974                    window,
16975                    cx,
16976                );
16977                Navigated::Yes
16978            })
16979        }))
16980    }
16981
16982    /// Opens a multibuffer with the given project locations in it
16983    pub fn open_locations_in_multibuffer(
16984        workspace: &mut Workspace,
16985        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
16986        title: String,
16987        split: bool,
16988        multibuffer_selection_mode: MultibufferSelectionMode,
16989        window: &mut Window,
16990        cx: &mut Context<Workspace>,
16991    ) {
16992        if locations.is_empty() {
16993            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
16994            return;
16995        }
16996
16997        let capability = workspace.project().read(cx).capability();
16998        let mut ranges = <Vec<Range<Anchor>>>::new();
16999
17000        // a key to find existing multibuffer editors with the same set of locations
17001        // to prevent us from opening more and more multibuffer tabs for searches and the like
17002        let mut key = (title.clone(), vec![]);
17003        let excerpt_buffer = cx.new(|cx| {
17004            let key = &mut key.1;
17005            let mut multibuffer = MultiBuffer::new(capability);
17006            for (buffer, mut ranges_for_buffer) in locations {
17007                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17008                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17009                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17010                    PathKey::for_buffer(&buffer, cx),
17011                    buffer.clone(),
17012                    ranges_for_buffer,
17013                    multibuffer_context_lines(cx),
17014                    cx,
17015                );
17016                ranges.extend(new_ranges)
17017            }
17018
17019            multibuffer.with_title(title)
17020        });
17021        let existing = workspace.active_pane().update(cx, |pane, cx| {
17022            pane.items()
17023                .filter_map(|item| item.downcast::<Editor>())
17024                .find(|editor| {
17025                    editor
17026                        .read(cx)
17027                        .lookup_key
17028                        .as_ref()
17029                        .and_then(|it| {
17030                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17031                        })
17032                        .is_some_and(|it| *it == key)
17033                })
17034        });
17035        let editor = existing.unwrap_or_else(|| {
17036            cx.new(|cx| {
17037                let mut editor = Editor::for_multibuffer(
17038                    excerpt_buffer,
17039                    Some(workspace.project().clone()),
17040                    window,
17041                    cx,
17042                );
17043                editor.lookup_key = Some(Box::new(key));
17044                editor
17045            })
17046        });
17047        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17048            MultibufferSelectionMode::First => {
17049                if let Some(first_range) = ranges.first() {
17050                    editor.change_selections(
17051                        SelectionEffects::no_scroll(),
17052                        window,
17053                        cx,
17054                        |selections| {
17055                            selections.clear_disjoint();
17056                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17057                        },
17058                    );
17059                }
17060                editor.highlight_background::<Self>(
17061                    &ranges,
17062                    |theme| theme.colors().editor_highlighted_line_background,
17063                    cx,
17064                );
17065            }
17066            MultibufferSelectionMode::All => {
17067                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17068                    selections.clear_disjoint();
17069                    selections.select_anchor_ranges(ranges);
17070                });
17071            }
17072        });
17073
17074        let item = Box::new(editor);
17075        let item_id = item.item_id();
17076
17077        if split {
17078            let pane = workspace.adjacent_pane(window, cx);
17079            workspace.add_item(pane, item, None, true, true, window, cx);
17080        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
17081            let (preview_item_id, preview_item_idx) =
17082                workspace.active_pane().read_with(cx, |pane, _| {
17083                    (pane.preview_item_id(), pane.preview_item_idx())
17084                });
17085
17086            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
17087
17088            if let Some(preview_item_id) = preview_item_id {
17089                workspace.active_pane().update(cx, |pane, cx| {
17090                    pane.remove_item(preview_item_id, false, false, window, cx);
17091                });
17092            }
17093        } else {
17094            workspace.add_item_to_active_pane(item, None, true, window, cx);
17095        }
17096        workspace.active_pane().update(cx, |pane, cx| {
17097            pane.set_preview_item_id(Some(item_id), cx);
17098        });
17099    }
17100
17101    pub fn rename(
17102        &mut self,
17103        _: &Rename,
17104        window: &mut Window,
17105        cx: &mut Context<Self>,
17106    ) -> Option<Task<Result<()>>> {
17107        use language::ToOffset as _;
17108
17109        let provider = self.semantics_provider.clone()?;
17110        let selection = self.selections.newest_anchor().clone();
17111        let (cursor_buffer, cursor_buffer_position) = self
17112            .buffer
17113            .read(cx)
17114            .text_anchor_for_position(selection.head(), cx)?;
17115        let (tail_buffer, cursor_buffer_position_end) = self
17116            .buffer
17117            .read(cx)
17118            .text_anchor_for_position(selection.tail(), cx)?;
17119        if tail_buffer != cursor_buffer {
17120            return None;
17121        }
17122
17123        let snapshot = cursor_buffer.read(cx).snapshot();
17124        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17125        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17126        let prepare_rename = provider
17127            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17128            .unwrap_or_else(|| Task::ready(Ok(None)));
17129        drop(snapshot);
17130
17131        Some(cx.spawn_in(window, async move |this, cx| {
17132            let rename_range = if let Some(range) = prepare_rename.await? {
17133                Some(range)
17134            } else {
17135                this.update(cx, |this, cx| {
17136                    let buffer = this.buffer.read(cx).snapshot(cx);
17137                    let mut buffer_highlights = this
17138                        .document_highlights_for_position(selection.head(), &buffer)
17139                        .filter(|highlight| {
17140                            highlight.start.excerpt_id == selection.head().excerpt_id
17141                                && highlight.end.excerpt_id == selection.head().excerpt_id
17142                        });
17143                    buffer_highlights
17144                        .next()
17145                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17146                })?
17147            };
17148            if let Some(rename_range) = rename_range {
17149                this.update_in(cx, |this, window, cx| {
17150                    let snapshot = cursor_buffer.read(cx).snapshot();
17151                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17152                    let cursor_offset_in_rename_range =
17153                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17154                    let cursor_offset_in_rename_range_end =
17155                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17156
17157                    this.take_rename(false, window, cx);
17158                    let buffer = this.buffer.read(cx).read(cx);
17159                    let cursor_offset = selection.head().to_offset(&buffer);
17160                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
17161                    let rename_end = rename_start + rename_buffer_range.len();
17162                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17163                    let mut old_highlight_id = None;
17164                    let old_name: Arc<str> = buffer
17165                        .chunks(rename_start..rename_end, true)
17166                        .map(|chunk| {
17167                            if old_highlight_id.is_none() {
17168                                old_highlight_id = chunk.syntax_highlight_id;
17169                            }
17170                            chunk.text
17171                        })
17172                        .collect::<String>()
17173                        .into();
17174
17175                    drop(buffer);
17176
17177                    // Position the selection in the rename editor so that it matches the current selection.
17178                    this.show_local_selections = false;
17179                    let rename_editor = cx.new(|cx| {
17180                        let mut editor = Editor::single_line(window, cx);
17181                        editor.buffer.update(cx, |buffer, cx| {
17182                            buffer.edit([(0..0, old_name.clone())], None, cx)
17183                        });
17184                        let rename_selection_range = match cursor_offset_in_rename_range
17185                            .cmp(&cursor_offset_in_rename_range_end)
17186                        {
17187                            Ordering::Equal => {
17188                                editor.select_all(&SelectAll, window, cx);
17189                                return editor;
17190                            }
17191                            Ordering::Less => {
17192                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17193                            }
17194                            Ordering::Greater => {
17195                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17196                            }
17197                        };
17198                        if rename_selection_range.end > old_name.len() {
17199                            editor.select_all(&SelectAll, window, cx);
17200                        } else {
17201                            editor.change_selections(Default::default(), window, cx, |s| {
17202                                s.select_ranges([rename_selection_range]);
17203                            });
17204                        }
17205                        editor
17206                    });
17207                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17208                        if e == &EditorEvent::Focused {
17209                            cx.emit(EditorEvent::FocusedIn)
17210                        }
17211                    })
17212                    .detach();
17213
17214                    let write_highlights =
17215                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17216                    let read_highlights =
17217                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17218                    let ranges = write_highlights
17219                        .iter()
17220                        .flat_map(|(_, ranges)| ranges.iter())
17221                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17222                        .cloned()
17223                        .collect();
17224
17225                    this.highlight_text::<Rename>(
17226                        ranges,
17227                        HighlightStyle {
17228                            fade_out: Some(0.6),
17229                            ..Default::default()
17230                        },
17231                        cx,
17232                    );
17233                    let rename_focus_handle = rename_editor.focus_handle(cx);
17234                    window.focus(&rename_focus_handle);
17235                    let block_id = this.insert_blocks(
17236                        [BlockProperties {
17237                            style: BlockStyle::Flex,
17238                            placement: BlockPlacement::Below(range.start),
17239                            height: Some(1),
17240                            render: Arc::new({
17241                                let rename_editor = rename_editor.clone();
17242                                move |cx: &mut BlockContext| {
17243                                    let mut text_style = cx.editor_style.text.clone();
17244                                    if let Some(highlight_style) = old_highlight_id
17245                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17246                                    {
17247                                        text_style = text_style.highlight(highlight_style);
17248                                    }
17249                                    div()
17250                                        .block_mouse_except_scroll()
17251                                        .pl(cx.anchor_x)
17252                                        .child(EditorElement::new(
17253                                            &rename_editor,
17254                                            EditorStyle {
17255                                                background: cx.theme().system().transparent,
17256                                                local_player: cx.editor_style.local_player,
17257                                                text: text_style,
17258                                                scrollbar_width: cx.editor_style.scrollbar_width,
17259                                                syntax: cx.editor_style.syntax.clone(),
17260                                                status: cx.editor_style.status.clone(),
17261                                                inlay_hints_style: HighlightStyle {
17262                                                    font_weight: Some(FontWeight::BOLD),
17263                                                    ..make_inlay_hints_style(cx.app)
17264                                                },
17265                                                edit_prediction_styles: make_suggestion_styles(
17266                                                    cx.app,
17267                                                ),
17268                                                ..EditorStyle::default()
17269                                            },
17270                                        ))
17271                                        .into_any_element()
17272                                }
17273                            }),
17274                            priority: 0,
17275                        }],
17276                        Some(Autoscroll::fit()),
17277                        cx,
17278                    )[0];
17279                    this.pending_rename = Some(RenameState {
17280                        range,
17281                        old_name,
17282                        editor: rename_editor,
17283                        block_id,
17284                    });
17285                })?;
17286            }
17287
17288            Ok(())
17289        }))
17290    }
17291
17292    pub fn confirm_rename(
17293        &mut self,
17294        _: &ConfirmRename,
17295        window: &mut Window,
17296        cx: &mut Context<Self>,
17297    ) -> Option<Task<Result<()>>> {
17298        let rename = self.take_rename(false, window, cx)?;
17299        let workspace = self.workspace()?.downgrade();
17300        let (buffer, start) = self
17301            .buffer
17302            .read(cx)
17303            .text_anchor_for_position(rename.range.start, cx)?;
17304        let (end_buffer, _) = self
17305            .buffer
17306            .read(cx)
17307            .text_anchor_for_position(rename.range.end, cx)?;
17308        if buffer != end_buffer {
17309            return None;
17310        }
17311
17312        let old_name = rename.old_name;
17313        let new_name = rename.editor.read(cx).text(cx);
17314
17315        let rename = self.semantics_provider.as_ref()?.perform_rename(
17316            &buffer,
17317            start,
17318            new_name.clone(),
17319            cx,
17320        )?;
17321
17322        Some(cx.spawn_in(window, async move |editor, cx| {
17323            let project_transaction = rename.await?;
17324            Self::open_project_transaction(
17325                &editor,
17326                workspace,
17327                project_transaction,
17328                format!("Rename: {}{}", old_name, new_name),
17329                cx,
17330            )
17331            .await?;
17332
17333            editor.update(cx, |editor, cx| {
17334                editor.refresh_document_highlights(cx);
17335            })?;
17336            Ok(())
17337        }))
17338    }
17339
17340    fn take_rename(
17341        &mut self,
17342        moving_cursor: bool,
17343        window: &mut Window,
17344        cx: &mut Context<Self>,
17345    ) -> Option<RenameState> {
17346        let rename = self.pending_rename.take()?;
17347        if rename.editor.focus_handle(cx).is_focused(window) {
17348            window.focus(&self.focus_handle);
17349        }
17350
17351        self.remove_blocks(
17352            [rename.block_id].into_iter().collect(),
17353            Some(Autoscroll::fit()),
17354            cx,
17355        );
17356        self.clear_highlights::<Rename>(cx);
17357        self.show_local_selections = true;
17358
17359        if moving_cursor {
17360            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17361                editor
17362                    .selections
17363                    .newest::<usize>(&editor.display_snapshot(cx))
17364                    .head()
17365            });
17366
17367            // Update the selection to match the position of the selection inside
17368            // the rename editor.
17369            let snapshot = self.buffer.read(cx).read(cx);
17370            let rename_range = rename.range.to_offset(&snapshot);
17371            let cursor_in_editor = snapshot
17372                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17373                .min(rename_range.end);
17374            drop(snapshot);
17375
17376            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17377                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17378            });
17379        } else {
17380            self.refresh_document_highlights(cx);
17381        }
17382
17383        Some(rename)
17384    }
17385
17386    pub fn pending_rename(&self) -> Option<&RenameState> {
17387        self.pending_rename.as_ref()
17388    }
17389
17390    fn format(
17391        &mut self,
17392        _: &Format,
17393        window: &mut Window,
17394        cx: &mut Context<Self>,
17395    ) -> Option<Task<Result<()>>> {
17396        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17397
17398        let project = match &self.project {
17399            Some(project) => project.clone(),
17400            None => return None,
17401        };
17402
17403        Some(self.perform_format(
17404            project,
17405            FormatTrigger::Manual,
17406            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17407            window,
17408            cx,
17409        ))
17410    }
17411
17412    fn format_selections(
17413        &mut self,
17414        _: &FormatSelections,
17415        window: &mut Window,
17416        cx: &mut Context<Self>,
17417    ) -> Option<Task<Result<()>>> {
17418        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17419
17420        let project = match &self.project {
17421            Some(project) => project.clone(),
17422            None => return None,
17423        };
17424
17425        let ranges = self
17426            .selections
17427            .all_adjusted(&self.display_snapshot(cx))
17428            .into_iter()
17429            .map(|selection| selection.range())
17430            .collect_vec();
17431
17432        Some(self.perform_format(
17433            project,
17434            FormatTrigger::Manual,
17435            FormatTarget::Ranges(ranges),
17436            window,
17437            cx,
17438        ))
17439    }
17440
17441    fn perform_format(
17442        &mut self,
17443        project: Entity<Project>,
17444        trigger: FormatTrigger,
17445        target: FormatTarget,
17446        window: &mut Window,
17447        cx: &mut Context<Self>,
17448    ) -> Task<Result<()>> {
17449        let buffer = self.buffer.clone();
17450        let (buffers, target) = match target {
17451            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17452            FormatTarget::Ranges(selection_ranges) => {
17453                let multi_buffer = buffer.read(cx);
17454                let snapshot = multi_buffer.read(cx);
17455                let mut buffers = HashSet::default();
17456                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17457                    BTreeMap::new();
17458                for selection_range in selection_ranges {
17459                    for (buffer, buffer_range, _) in
17460                        snapshot.range_to_buffer_ranges(selection_range)
17461                    {
17462                        let buffer_id = buffer.remote_id();
17463                        let start = buffer.anchor_before(buffer_range.start);
17464                        let end = buffer.anchor_after(buffer_range.end);
17465                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17466                        buffer_id_to_ranges
17467                            .entry(buffer_id)
17468                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17469                            .or_insert_with(|| vec![start..end]);
17470                    }
17471                }
17472                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17473            }
17474        };
17475
17476        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17477        let selections_prev = transaction_id_prev
17478            .and_then(|transaction_id_prev| {
17479                // default to selections as they were after the last edit, if we have them,
17480                // instead of how they are now.
17481                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17482                // will take you back to where you made the last edit, instead of staying where you scrolled
17483                self.selection_history
17484                    .transaction(transaction_id_prev)
17485                    .map(|t| t.0.clone())
17486            })
17487            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17488
17489        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17490        let format = project.update(cx, |project, cx| {
17491            project.format(buffers, target, true, trigger, cx)
17492        });
17493
17494        cx.spawn_in(window, async move |editor, cx| {
17495            let transaction = futures::select_biased! {
17496                transaction = format.log_err().fuse() => transaction,
17497                () = timeout => {
17498                    log::warn!("timed out waiting for formatting");
17499                    None
17500                }
17501            };
17502
17503            buffer
17504                .update(cx, |buffer, cx| {
17505                    if let Some(transaction) = transaction
17506                        && !buffer.is_singleton()
17507                    {
17508                        buffer.push_transaction(&transaction.0, cx);
17509                    }
17510                    cx.notify();
17511                })
17512                .ok();
17513
17514            if let Some(transaction_id_now) =
17515                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17516            {
17517                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17518                if has_new_transaction {
17519                    _ = editor.update(cx, |editor, _| {
17520                        editor
17521                            .selection_history
17522                            .insert_transaction(transaction_id_now, selections_prev);
17523                    });
17524                }
17525            }
17526
17527            Ok(())
17528        })
17529    }
17530
17531    fn organize_imports(
17532        &mut self,
17533        _: &OrganizeImports,
17534        window: &mut Window,
17535        cx: &mut Context<Self>,
17536    ) -> Option<Task<Result<()>>> {
17537        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17538        let project = match &self.project {
17539            Some(project) => project.clone(),
17540            None => return None,
17541        };
17542        Some(self.perform_code_action_kind(
17543            project,
17544            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17545            window,
17546            cx,
17547        ))
17548    }
17549
17550    fn perform_code_action_kind(
17551        &mut self,
17552        project: Entity<Project>,
17553        kind: CodeActionKind,
17554        window: &mut Window,
17555        cx: &mut Context<Self>,
17556    ) -> Task<Result<()>> {
17557        let buffer = self.buffer.clone();
17558        let buffers = buffer.read(cx).all_buffers();
17559        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17560        let apply_action = project.update(cx, |project, cx| {
17561            project.apply_code_action_kind(buffers, kind, true, cx)
17562        });
17563        cx.spawn_in(window, async move |_, cx| {
17564            let transaction = futures::select_biased! {
17565                () = timeout => {
17566                    log::warn!("timed out waiting for executing code action");
17567                    None
17568                }
17569                transaction = apply_action.log_err().fuse() => transaction,
17570            };
17571            buffer
17572                .update(cx, |buffer, cx| {
17573                    // check if we need this
17574                    if let Some(transaction) = transaction
17575                        && !buffer.is_singleton()
17576                    {
17577                        buffer.push_transaction(&transaction.0, cx);
17578                    }
17579                    cx.notify();
17580                })
17581                .ok();
17582            Ok(())
17583        })
17584    }
17585
17586    pub fn restart_language_server(
17587        &mut self,
17588        _: &RestartLanguageServer,
17589        _: &mut Window,
17590        cx: &mut Context<Self>,
17591    ) {
17592        if let Some(project) = self.project.clone() {
17593            self.buffer.update(cx, |multi_buffer, cx| {
17594                project.update(cx, |project, cx| {
17595                    project.restart_language_servers_for_buffers(
17596                        multi_buffer.all_buffers().into_iter().collect(),
17597                        HashSet::default(),
17598                        cx,
17599                    );
17600                });
17601            })
17602        }
17603    }
17604
17605    pub fn stop_language_server(
17606        &mut self,
17607        _: &StopLanguageServer,
17608        _: &mut Window,
17609        cx: &mut Context<Self>,
17610    ) {
17611        if let Some(project) = self.project.clone() {
17612            self.buffer.update(cx, |multi_buffer, cx| {
17613                project.update(cx, |project, cx| {
17614                    project.stop_language_servers_for_buffers(
17615                        multi_buffer.all_buffers().into_iter().collect(),
17616                        HashSet::default(),
17617                        cx,
17618                    );
17619                });
17620            });
17621            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
17622        }
17623    }
17624
17625    fn cancel_language_server_work(
17626        workspace: &mut Workspace,
17627        _: &actions::CancelLanguageServerWork,
17628        _: &mut Window,
17629        cx: &mut Context<Workspace>,
17630    ) {
17631        let project = workspace.project();
17632        let buffers = workspace
17633            .active_item(cx)
17634            .and_then(|item| item.act_as::<Editor>(cx))
17635            .map_or(HashSet::default(), |editor| {
17636                editor.read(cx).buffer.read(cx).all_buffers()
17637            });
17638        project.update(cx, |project, cx| {
17639            project.cancel_language_server_work_for_buffers(buffers, cx);
17640        });
17641    }
17642
17643    fn show_character_palette(
17644        &mut self,
17645        _: &ShowCharacterPalette,
17646        window: &mut Window,
17647        _: &mut Context<Self>,
17648    ) {
17649        window.show_character_palette();
17650    }
17651
17652    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17653        if !self.diagnostics_enabled() {
17654            return;
17655        }
17656
17657        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17658            let buffer = self.buffer.read(cx).snapshot(cx);
17659            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17660            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17661            let is_valid = buffer
17662                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17663                .any(|entry| {
17664                    entry.diagnostic.is_primary
17665                        && !entry.range.is_empty()
17666                        && entry.range.start == primary_range_start
17667                        && entry.diagnostic.message == active_diagnostics.active_message
17668                });
17669
17670            if !is_valid {
17671                self.dismiss_diagnostics(cx);
17672            }
17673        }
17674    }
17675
17676    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17677        match &self.active_diagnostics {
17678            ActiveDiagnostic::Group(group) => Some(group),
17679            _ => None,
17680        }
17681    }
17682
17683    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17684        if !self.diagnostics_enabled() {
17685            return;
17686        }
17687        self.dismiss_diagnostics(cx);
17688        self.active_diagnostics = ActiveDiagnostic::All;
17689    }
17690
17691    fn activate_diagnostics(
17692        &mut self,
17693        buffer_id: BufferId,
17694        diagnostic: DiagnosticEntryRef<'_, usize>,
17695        window: &mut Window,
17696        cx: &mut Context<Self>,
17697    ) {
17698        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17699            return;
17700        }
17701        self.dismiss_diagnostics(cx);
17702        let snapshot = self.snapshot(window, cx);
17703        let buffer = self.buffer.read(cx).snapshot(cx);
17704        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17705            return;
17706        };
17707
17708        let diagnostic_group = buffer
17709            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17710            .collect::<Vec<_>>();
17711
17712        let blocks =
17713            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17714
17715        let blocks = self.display_map.update(cx, |display_map, cx| {
17716            display_map.insert_blocks(blocks, cx).into_iter().collect()
17717        });
17718        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17719            active_range: buffer.anchor_before(diagnostic.range.start)
17720                ..buffer.anchor_after(diagnostic.range.end),
17721            active_message: diagnostic.diagnostic.message.clone(),
17722            group_id: diagnostic.diagnostic.group_id,
17723            blocks,
17724        });
17725        cx.notify();
17726    }
17727
17728    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17729        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17730            return;
17731        };
17732
17733        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17734        if let ActiveDiagnostic::Group(group) = prev {
17735            self.display_map.update(cx, |display_map, cx| {
17736                display_map.remove_blocks(group.blocks, cx);
17737            });
17738            cx.notify();
17739        }
17740    }
17741
17742    /// Disable inline diagnostics rendering for this editor.
17743    pub fn disable_inline_diagnostics(&mut self) {
17744        self.inline_diagnostics_enabled = false;
17745        self.inline_diagnostics_update = Task::ready(());
17746        self.inline_diagnostics.clear();
17747    }
17748
17749    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17750        self.diagnostics_enabled = false;
17751        self.dismiss_diagnostics(cx);
17752        self.inline_diagnostics_update = Task::ready(());
17753        self.inline_diagnostics.clear();
17754    }
17755
17756    pub fn disable_word_completions(&mut self) {
17757        self.word_completions_enabled = false;
17758    }
17759
17760    pub fn diagnostics_enabled(&self) -> bool {
17761        self.diagnostics_enabled && self.mode.is_full()
17762    }
17763
17764    pub fn inline_diagnostics_enabled(&self) -> bool {
17765        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17766    }
17767
17768    pub fn show_inline_diagnostics(&self) -> bool {
17769        self.show_inline_diagnostics
17770    }
17771
17772    pub fn toggle_inline_diagnostics(
17773        &mut self,
17774        _: &ToggleInlineDiagnostics,
17775        window: &mut Window,
17776        cx: &mut Context<Editor>,
17777    ) {
17778        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17779        self.refresh_inline_diagnostics(false, window, cx);
17780    }
17781
17782    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17783        self.diagnostics_max_severity = severity;
17784        self.display_map.update(cx, |display_map, _| {
17785            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17786        });
17787    }
17788
17789    pub fn toggle_diagnostics(
17790        &mut self,
17791        _: &ToggleDiagnostics,
17792        window: &mut Window,
17793        cx: &mut Context<Editor>,
17794    ) {
17795        if !self.diagnostics_enabled() {
17796            return;
17797        }
17798
17799        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17800            EditorSettings::get_global(cx)
17801                .diagnostics_max_severity
17802                .filter(|severity| severity != &DiagnosticSeverity::Off)
17803                .unwrap_or(DiagnosticSeverity::Hint)
17804        } else {
17805            DiagnosticSeverity::Off
17806        };
17807        self.set_max_diagnostics_severity(new_severity, cx);
17808        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17809            self.active_diagnostics = ActiveDiagnostic::None;
17810            self.inline_diagnostics_update = Task::ready(());
17811            self.inline_diagnostics.clear();
17812        } else {
17813            self.refresh_inline_diagnostics(false, window, cx);
17814        }
17815
17816        cx.notify();
17817    }
17818
17819    pub fn toggle_minimap(
17820        &mut self,
17821        _: &ToggleMinimap,
17822        window: &mut Window,
17823        cx: &mut Context<Editor>,
17824    ) {
17825        if self.supports_minimap(cx) {
17826            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17827        }
17828    }
17829
17830    fn refresh_inline_diagnostics(
17831        &mut self,
17832        debounce: bool,
17833        window: &mut Window,
17834        cx: &mut Context<Self>,
17835    ) {
17836        let max_severity = ProjectSettings::get_global(cx)
17837            .diagnostics
17838            .inline
17839            .max_severity
17840            .unwrap_or(self.diagnostics_max_severity);
17841
17842        if !self.inline_diagnostics_enabled()
17843            || !self.diagnostics_enabled()
17844            || !self.show_inline_diagnostics
17845            || max_severity == DiagnosticSeverity::Off
17846        {
17847            self.inline_diagnostics_update = Task::ready(());
17848            self.inline_diagnostics.clear();
17849            return;
17850        }
17851
17852        let debounce_ms = ProjectSettings::get_global(cx)
17853            .diagnostics
17854            .inline
17855            .update_debounce_ms;
17856        let debounce = if debounce && debounce_ms > 0 {
17857            Some(Duration::from_millis(debounce_ms))
17858        } else {
17859            None
17860        };
17861        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17862            if let Some(debounce) = debounce {
17863                cx.background_executor().timer(debounce).await;
17864            }
17865            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17866                editor
17867                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17868                    .ok()
17869            }) else {
17870                return;
17871            };
17872
17873            let new_inline_diagnostics = cx
17874                .background_spawn(async move {
17875                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17876                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17877                        let message = diagnostic_entry
17878                            .diagnostic
17879                            .message
17880                            .split_once('\n')
17881                            .map(|(line, _)| line)
17882                            .map(SharedString::new)
17883                            .unwrap_or_else(|| {
17884                                SharedString::new(&*diagnostic_entry.diagnostic.message)
17885                            });
17886                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17887                        let (Ok(i) | Err(i)) = inline_diagnostics
17888                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17889                        inline_diagnostics.insert(
17890                            i,
17891                            (
17892                                start_anchor,
17893                                InlineDiagnostic {
17894                                    message,
17895                                    group_id: diagnostic_entry.diagnostic.group_id,
17896                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17897                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17898                                    severity: diagnostic_entry.diagnostic.severity,
17899                                },
17900                            ),
17901                        );
17902                    }
17903                    inline_diagnostics
17904                })
17905                .await;
17906
17907            editor
17908                .update(cx, |editor, cx| {
17909                    editor.inline_diagnostics = new_inline_diagnostics;
17910                    cx.notify();
17911                })
17912                .ok();
17913        });
17914    }
17915
17916    fn pull_diagnostics(
17917        &mut self,
17918        buffer_id: Option<BufferId>,
17919        window: &Window,
17920        cx: &mut Context<Self>,
17921    ) -> Option<()> {
17922        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
17923            return None;
17924        }
17925        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17926            .diagnostics
17927            .lsp_pull_diagnostics;
17928        if !pull_diagnostics_settings.enabled {
17929            return None;
17930        }
17931        let project = self.project()?.downgrade();
17932        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17933        let mut buffers = self.buffer.read(cx).all_buffers();
17934        buffers.retain(|buffer| {
17935            let buffer_id_to_retain = buffer.read(cx).remote_id();
17936            buffer_id.is_none_or(|buffer_id| buffer_id == buffer_id_to_retain)
17937                && self.registered_buffers.contains_key(&buffer_id_to_retain)
17938        });
17939        if buffers.is_empty() {
17940            self.pull_diagnostics_task = Task::ready(());
17941            return None;
17942        }
17943
17944        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17945            cx.background_executor().timer(debounce).await;
17946
17947            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17948                buffers
17949                    .into_iter()
17950                    .filter_map(|buffer| {
17951                        project
17952                            .update(cx, |project, cx| {
17953                                project.lsp_store().update(cx, |lsp_store, cx| {
17954                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17955                                })
17956                            })
17957                            .ok()
17958                    })
17959                    .collect::<FuturesUnordered<_>>()
17960            }) else {
17961                return;
17962            };
17963
17964            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17965                match pull_task {
17966                    Ok(()) => {
17967                        if editor
17968                            .update_in(cx, |editor, window, cx| {
17969                                editor.update_diagnostics_state(window, cx);
17970                            })
17971                            .is_err()
17972                        {
17973                            return;
17974                        }
17975                    }
17976                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17977                }
17978            }
17979        });
17980
17981        Some(())
17982    }
17983
17984    pub fn set_selections_from_remote(
17985        &mut self,
17986        selections: Vec<Selection<Anchor>>,
17987        pending_selection: Option<Selection<Anchor>>,
17988        window: &mut Window,
17989        cx: &mut Context<Self>,
17990    ) {
17991        let old_cursor_position = self.selections.newest_anchor().head();
17992        self.selections.change_with(cx, |s| {
17993            s.select_anchors(selections);
17994            if let Some(pending_selection) = pending_selection {
17995                s.set_pending(pending_selection, SelectMode::Character);
17996            } else {
17997                s.clear_pending();
17998            }
17999        });
18000        self.selections_did_change(
18001            false,
18002            &old_cursor_position,
18003            SelectionEffects::default(),
18004            window,
18005            cx,
18006        );
18007    }
18008
18009    pub fn transact(
18010        &mut self,
18011        window: &mut Window,
18012        cx: &mut Context<Self>,
18013        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
18014    ) -> Option<TransactionId> {
18015        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18016            this.start_transaction_at(Instant::now(), window, cx);
18017            update(this, window, cx);
18018            this.end_transaction_at(Instant::now(), cx)
18019        })
18020    }
18021
18022    pub fn start_transaction_at(
18023        &mut self,
18024        now: Instant,
18025        window: &mut Window,
18026        cx: &mut Context<Self>,
18027    ) -> Option<TransactionId> {
18028        self.end_selection(window, cx);
18029        if let Some(tx_id) = self
18030            .buffer
18031            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18032        {
18033            self.selection_history
18034                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18035            cx.emit(EditorEvent::TransactionBegun {
18036                transaction_id: tx_id,
18037            });
18038            Some(tx_id)
18039        } else {
18040            None
18041        }
18042    }
18043
18044    pub fn end_transaction_at(
18045        &mut self,
18046        now: Instant,
18047        cx: &mut Context<Self>,
18048    ) -> Option<TransactionId> {
18049        if let Some(transaction_id) = self
18050            .buffer
18051            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18052        {
18053            if let Some((_, end_selections)) =
18054                self.selection_history.transaction_mut(transaction_id)
18055            {
18056                *end_selections = Some(self.selections.disjoint_anchors_arc());
18057            } else {
18058                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18059            }
18060
18061            cx.emit(EditorEvent::Edited { transaction_id });
18062            Some(transaction_id)
18063        } else {
18064            None
18065        }
18066    }
18067
18068    pub fn modify_transaction_selection_history(
18069        &mut self,
18070        transaction_id: TransactionId,
18071        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18072    ) -> bool {
18073        self.selection_history
18074            .transaction_mut(transaction_id)
18075            .map(modify)
18076            .is_some()
18077    }
18078
18079    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18080        if self.selection_mark_mode {
18081            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18082                s.move_with(|_, sel| {
18083                    sel.collapse_to(sel.head(), SelectionGoal::None);
18084                });
18085            })
18086        }
18087        self.selection_mark_mode = true;
18088        cx.notify();
18089    }
18090
18091    pub fn swap_selection_ends(
18092        &mut self,
18093        _: &actions::SwapSelectionEnds,
18094        window: &mut Window,
18095        cx: &mut Context<Self>,
18096    ) {
18097        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18098            s.move_with(|_, sel| {
18099                if sel.start != sel.end {
18100                    sel.reversed = !sel.reversed
18101                }
18102            });
18103        });
18104        self.request_autoscroll(Autoscroll::newest(), cx);
18105        cx.notify();
18106    }
18107
18108    pub fn toggle_focus(
18109        workspace: &mut Workspace,
18110        _: &actions::ToggleFocus,
18111        window: &mut Window,
18112        cx: &mut Context<Workspace>,
18113    ) {
18114        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18115            return;
18116        };
18117        workspace.activate_item(&item, true, true, window, cx);
18118    }
18119
18120    pub fn toggle_fold(
18121        &mut self,
18122        _: &actions::ToggleFold,
18123        window: &mut Window,
18124        cx: &mut Context<Self>,
18125    ) {
18126        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18127            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18128            let selection = self.selections.newest::<Point>(&display_map);
18129
18130            let range = if selection.is_empty() {
18131                let point = selection.head().to_display_point(&display_map);
18132                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18133                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18134                    .to_point(&display_map);
18135                start..end
18136            } else {
18137                selection.range()
18138            };
18139            if display_map.folds_in_range(range).next().is_some() {
18140                self.unfold_lines(&Default::default(), window, cx)
18141            } else {
18142                self.fold(&Default::default(), window, cx)
18143            }
18144        } else {
18145            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18146            let buffer_ids: HashSet<_> = self
18147                .selections
18148                .disjoint_anchor_ranges()
18149                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18150                .collect();
18151
18152            let should_unfold = buffer_ids
18153                .iter()
18154                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18155
18156            for buffer_id in buffer_ids {
18157                if should_unfold {
18158                    self.unfold_buffer(buffer_id, cx);
18159                } else {
18160                    self.fold_buffer(buffer_id, cx);
18161                }
18162            }
18163        }
18164    }
18165
18166    pub fn toggle_fold_recursive(
18167        &mut self,
18168        _: &actions::ToggleFoldRecursive,
18169        window: &mut Window,
18170        cx: &mut Context<Self>,
18171    ) {
18172        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
18173
18174        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18175        let range = if selection.is_empty() {
18176            let point = selection.head().to_display_point(&display_map);
18177            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18178            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18179                .to_point(&display_map);
18180            start..end
18181        } else {
18182            selection.range()
18183        };
18184        if display_map.folds_in_range(range).next().is_some() {
18185            self.unfold_recursive(&Default::default(), window, cx)
18186        } else {
18187            self.fold_recursive(&Default::default(), window, cx)
18188        }
18189    }
18190
18191    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18192        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18193            let mut to_fold = Vec::new();
18194            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18195            let selections = self.selections.all_adjusted(&display_map);
18196
18197            for selection in selections {
18198                let range = selection.range().sorted();
18199                let buffer_start_row = range.start.row;
18200
18201                if range.start.row != range.end.row {
18202                    let mut found = false;
18203                    let mut row = range.start.row;
18204                    while row <= range.end.row {
18205                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18206                        {
18207                            found = true;
18208                            row = crease.range().end.row + 1;
18209                            to_fold.push(crease);
18210                        } else {
18211                            row += 1
18212                        }
18213                    }
18214                    if found {
18215                        continue;
18216                    }
18217                }
18218
18219                for row in (0..=range.start.row).rev() {
18220                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18221                        && crease.range().end.row >= buffer_start_row
18222                    {
18223                        to_fold.push(crease);
18224                        if row <= range.start.row {
18225                            break;
18226                        }
18227                    }
18228                }
18229            }
18230
18231            self.fold_creases(to_fold, true, window, cx);
18232        } else {
18233            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18234            let buffer_ids = self
18235                .selections
18236                .disjoint_anchor_ranges()
18237                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18238                .collect::<HashSet<_>>();
18239            for buffer_id in buffer_ids {
18240                self.fold_buffer(buffer_id, cx);
18241            }
18242        }
18243    }
18244
18245    pub fn toggle_fold_all(
18246        &mut self,
18247        _: &actions::ToggleFoldAll,
18248        window: &mut Window,
18249        cx: &mut Context<Self>,
18250    ) {
18251        if self.buffer.read(cx).is_singleton() {
18252            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18253            let has_folds = display_map
18254                .folds_in_range(0..display_map.buffer_snapshot().len())
18255                .next()
18256                .is_some();
18257
18258            if has_folds {
18259                self.unfold_all(&actions::UnfoldAll, window, cx);
18260            } else {
18261                self.fold_all(&actions::FoldAll, window, cx);
18262            }
18263        } else {
18264            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18265            let should_unfold = buffer_ids
18266                .iter()
18267                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18268
18269            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18270                editor
18271                    .update_in(cx, |editor, _, cx| {
18272                        for buffer_id in buffer_ids {
18273                            if should_unfold {
18274                                editor.unfold_buffer(buffer_id, cx);
18275                            } else {
18276                                editor.fold_buffer(buffer_id, cx);
18277                            }
18278                        }
18279                    })
18280                    .ok();
18281            });
18282        }
18283    }
18284
18285    fn fold_at_level(
18286        &mut self,
18287        fold_at: &FoldAtLevel,
18288        window: &mut Window,
18289        cx: &mut Context<Self>,
18290    ) {
18291        if !self.buffer.read(cx).is_singleton() {
18292            return;
18293        }
18294
18295        let fold_at_level = fold_at.0;
18296        let snapshot = self.buffer.read(cx).snapshot(cx);
18297        let mut to_fold = Vec::new();
18298        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18299
18300        let row_ranges_to_keep: Vec<Range<u32>> = self
18301            .selections
18302            .all::<Point>(&self.display_snapshot(cx))
18303            .into_iter()
18304            .map(|sel| sel.start.row..sel.end.row)
18305            .collect();
18306
18307        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18308            while start_row < end_row {
18309                match self
18310                    .snapshot(window, cx)
18311                    .crease_for_buffer_row(MultiBufferRow(start_row))
18312                {
18313                    Some(crease) => {
18314                        let nested_start_row = crease.range().start.row + 1;
18315                        let nested_end_row = crease.range().end.row;
18316
18317                        if current_level < fold_at_level {
18318                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18319                        } else if current_level == fold_at_level {
18320                            // Fold iff there is no selection completely contained within the fold region
18321                            if !row_ranges_to_keep.iter().any(|selection| {
18322                                selection.end >= nested_start_row
18323                                    && selection.start <= nested_end_row
18324                            }) {
18325                                to_fold.push(crease);
18326                            }
18327                        }
18328
18329                        start_row = nested_end_row + 1;
18330                    }
18331                    None => start_row += 1,
18332                }
18333            }
18334        }
18335
18336        self.fold_creases(to_fold, true, window, cx);
18337    }
18338
18339    pub fn fold_at_level_1(
18340        &mut self,
18341        _: &actions::FoldAtLevel1,
18342        window: &mut Window,
18343        cx: &mut Context<Self>,
18344    ) {
18345        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18346    }
18347
18348    pub fn fold_at_level_2(
18349        &mut self,
18350        _: &actions::FoldAtLevel2,
18351        window: &mut Window,
18352        cx: &mut Context<Self>,
18353    ) {
18354        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18355    }
18356
18357    pub fn fold_at_level_3(
18358        &mut self,
18359        _: &actions::FoldAtLevel3,
18360        window: &mut Window,
18361        cx: &mut Context<Self>,
18362    ) {
18363        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18364    }
18365
18366    pub fn fold_at_level_4(
18367        &mut self,
18368        _: &actions::FoldAtLevel4,
18369        window: &mut Window,
18370        cx: &mut Context<Self>,
18371    ) {
18372        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18373    }
18374
18375    pub fn fold_at_level_5(
18376        &mut self,
18377        _: &actions::FoldAtLevel5,
18378        window: &mut Window,
18379        cx: &mut Context<Self>,
18380    ) {
18381        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18382    }
18383
18384    pub fn fold_at_level_6(
18385        &mut self,
18386        _: &actions::FoldAtLevel6,
18387        window: &mut Window,
18388        cx: &mut Context<Self>,
18389    ) {
18390        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18391    }
18392
18393    pub fn fold_at_level_7(
18394        &mut self,
18395        _: &actions::FoldAtLevel7,
18396        window: &mut Window,
18397        cx: &mut Context<Self>,
18398    ) {
18399        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18400    }
18401
18402    pub fn fold_at_level_8(
18403        &mut self,
18404        _: &actions::FoldAtLevel8,
18405        window: &mut Window,
18406        cx: &mut Context<Self>,
18407    ) {
18408        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18409    }
18410
18411    pub fn fold_at_level_9(
18412        &mut self,
18413        _: &actions::FoldAtLevel9,
18414        window: &mut Window,
18415        cx: &mut Context<Self>,
18416    ) {
18417        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18418    }
18419
18420    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18421        if self.buffer.read(cx).is_singleton() {
18422            let mut fold_ranges = Vec::new();
18423            let snapshot = self.buffer.read(cx).snapshot(cx);
18424
18425            for row in 0..snapshot.max_row().0 {
18426                if let Some(foldable_range) = self
18427                    .snapshot(window, cx)
18428                    .crease_for_buffer_row(MultiBufferRow(row))
18429                {
18430                    fold_ranges.push(foldable_range);
18431                }
18432            }
18433
18434            self.fold_creases(fold_ranges, true, window, cx);
18435        } else {
18436            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18437                editor
18438                    .update_in(cx, |editor, _, cx| {
18439                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18440                            editor.fold_buffer(buffer_id, cx);
18441                        }
18442                    })
18443                    .ok();
18444            });
18445        }
18446    }
18447
18448    pub fn fold_function_bodies(
18449        &mut self,
18450        _: &actions::FoldFunctionBodies,
18451        window: &mut Window,
18452        cx: &mut Context<Self>,
18453    ) {
18454        let snapshot = self.buffer.read(cx).snapshot(cx);
18455
18456        let ranges = snapshot
18457            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18458            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18459            .collect::<Vec<_>>();
18460
18461        let creases = ranges
18462            .into_iter()
18463            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18464            .collect();
18465
18466        self.fold_creases(creases, true, window, cx);
18467    }
18468
18469    pub fn fold_recursive(
18470        &mut self,
18471        _: &actions::FoldRecursive,
18472        window: &mut Window,
18473        cx: &mut Context<Self>,
18474    ) {
18475        let mut to_fold = Vec::new();
18476        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18477        let selections = self.selections.all_adjusted(&display_map);
18478
18479        for selection in selections {
18480            let range = selection.range().sorted();
18481            let buffer_start_row = range.start.row;
18482
18483            if range.start.row != range.end.row {
18484                let mut found = false;
18485                for row in range.start.row..=range.end.row {
18486                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18487                        found = true;
18488                        to_fold.push(crease);
18489                    }
18490                }
18491                if found {
18492                    continue;
18493                }
18494            }
18495
18496            for row in (0..=range.start.row).rev() {
18497                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18498                    if crease.range().end.row >= buffer_start_row {
18499                        to_fold.push(crease);
18500                    } else {
18501                        break;
18502                    }
18503                }
18504            }
18505        }
18506
18507        self.fold_creases(to_fold, true, window, cx);
18508    }
18509
18510    pub fn fold_at(
18511        &mut self,
18512        buffer_row: MultiBufferRow,
18513        window: &mut Window,
18514        cx: &mut Context<Self>,
18515    ) {
18516        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18517
18518        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18519            let autoscroll = self
18520                .selections
18521                .all::<Point>(&display_map)
18522                .iter()
18523                .any(|selection| crease.range().overlaps(&selection.range()));
18524
18525            self.fold_creases(vec![crease], autoscroll, window, cx);
18526        }
18527    }
18528
18529    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18530        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18531            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18532            let buffer = display_map.buffer_snapshot();
18533            let selections = self.selections.all::<Point>(&display_map);
18534            let ranges = selections
18535                .iter()
18536                .map(|s| {
18537                    let range = s.display_range(&display_map).sorted();
18538                    let mut start = range.start.to_point(&display_map);
18539                    let mut end = range.end.to_point(&display_map);
18540                    start.column = 0;
18541                    end.column = buffer.line_len(MultiBufferRow(end.row));
18542                    start..end
18543                })
18544                .collect::<Vec<_>>();
18545
18546            self.unfold_ranges(&ranges, true, true, cx);
18547        } else {
18548            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18549            let buffer_ids = self
18550                .selections
18551                .disjoint_anchor_ranges()
18552                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18553                .collect::<HashSet<_>>();
18554            for buffer_id in buffer_ids {
18555                self.unfold_buffer(buffer_id, cx);
18556            }
18557        }
18558    }
18559
18560    pub fn unfold_recursive(
18561        &mut self,
18562        _: &UnfoldRecursive,
18563        _window: &mut Window,
18564        cx: &mut Context<Self>,
18565    ) {
18566        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18567        let selections = self.selections.all::<Point>(&display_map);
18568        let ranges = selections
18569            .iter()
18570            .map(|s| {
18571                let mut range = s.display_range(&display_map).sorted();
18572                *range.start.column_mut() = 0;
18573                *range.end.column_mut() = display_map.line_len(range.end.row());
18574                let start = range.start.to_point(&display_map);
18575                let end = range.end.to_point(&display_map);
18576                start..end
18577            })
18578            .collect::<Vec<_>>();
18579
18580        self.unfold_ranges(&ranges, true, true, cx);
18581    }
18582
18583    pub fn unfold_at(
18584        &mut self,
18585        buffer_row: MultiBufferRow,
18586        _window: &mut Window,
18587        cx: &mut Context<Self>,
18588    ) {
18589        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18590
18591        let intersection_range = Point::new(buffer_row.0, 0)
18592            ..Point::new(
18593                buffer_row.0,
18594                display_map.buffer_snapshot().line_len(buffer_row),
18595            );
18596
18597        let autoscroll = self
18598            .selections
18599            .all::<Point>(&display_map)
18600            .iter()
18601            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18602
18603        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18604    }
18605
18606    pub fn unfold_all(
18607        &mut self,
18608        _: &actions::UnfoldAll,
18609        _window: &mut Window,
18610        cx: &mut Context<Self>,
18611    ) {
18612        if self.buffer.read(cx).is_singleton() {
18613            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18614            self.unfold_ranges(&[0..display_map.buffer_snapshot().len()], true, true, cx);
18615        } else {
18616            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18617                editor
18618                    .update(cx, |editor, cx| {
18619                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18620                            editor.unfold_buffer(buffer_id, cx);
18621                        }
18622                    })
18623                    .ok();
18624            });
18625        }
18626    }
18627
18628    pub fn fold_selected_ranges(
18629        &mut self,
18630        _: &FoldSelectedRanges,
18631        window: &mut Window,
18632        cx: &mut Context<Self>,
18633    ) {
18634        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18635        let selections = self.selections.all_adjusted(&display_map);
18636        let ranges = selections
18637            .into_iter()
18638            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18639            .collect::<Vec<_>>();
18640        self.fold_creases(ranges, true, window, cx);
18641    }
18642
18643    pub fn fold_ranges<T: ToOffset + Clone>(
18644        &mut self,
18645        ranges: Vec<Range<T>>,
18646        auto_scroll: bool,
18647        window: &mut Window,
18648        cx: &mut Context<Self>,
18649    ) {
18650        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18651        let ranges = ranges
18652            .into_iter()
18653            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18654            .collect::<Vec<_>>();
18655        self.fold_creases(ranges, auto_scroll, window, cx);
18656    }
18657
18658    pub fn fold_creases<T: ToOffset + Clone>(
18659        &mut self,
18660        creases: Vec<Crease<T>>,
18661        auto_scroll: bool,
18662        _window: &mut Window,
18663        cx: &mut Context<Self>,
18664    ) {
18665        if creases.is_empty() {
18666            return;
18667        }
18668
18669        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18670
18671        if auto_scroll {
18672            self.request_autoscroll(Autoscroll::fit(), cx);
18673        }
18674
18675        cx.notify();
18676
18677        self.scrollbar_marker_state.dirty = true;
18678        self.folds_did_change(cx);
18679    }
18680
18681    /// Removes any folds whose ranges intersect any of the given ranges.
18682    pub fn unfold_ranges<T: ToOffset + Clone>(
18683        &mut self,
18684        ranges: &[Range<T>],
18685        inclusive: bool,
18686        auto_scroll: bool,
18687        cx: &mut Context<Self>,
18688    ) {
18689        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18690            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18691        });
18692        self.folds_did_change(cx);
18693    }
18694
18695    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18696        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18697            return;
18698        }
18699        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18700        self.display_map.update(cx, |display_map, cx| {
18701            display_map.fold_buffers([buffer_id], cx)
18702        });
18703        cx.emit(EditorEvent::BufferFoldToggled {
18704            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18705            folded: true,
18706        });
18707        cx.notify();
18708    }
18709
18710    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18711        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18712            return;
18713        }
18714        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18715        self.display_map.update(cx, |display_map, cx| {
18716            display_map.unfold_buffers([buffer_id], cx);
18717        });
18718        cx.emit(EditorEvent::BufferFoldToggled {
18719            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18720            folded: false,
18721        });
18722        cx.notify();
18723    }
18724
18725    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18726        self.display_map.read(cx).is_buffer_folded(buffer)
18727    }
18728
18729    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18730        self.display_map.read(cx).folded_buffers()
18731    }
18732
18733    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18734        self.display_map.update(cx, |display_map, cx| {
18735            display_map.disable_header_for_buffer(buffer_id, cx);
18736        });
18737        cx.notify();
18738    }
18739
18740    /// Removes any folds with the given ranges.
18741    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18742        &mut self,
18743        ranges: &[Range<T>],
18744        type_id: TypeId,
18745        auto_scroll: bool,
18746        cx: &mut Context<Self>,
18747    ) {
18748        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18749            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18750        });
18751        self.folds_did_change(cx);
18752    }
18753
18754    fn remove_folds_with<T: ToOffset + Clone>(
18755        &mut self,
18756        ranges: &[Range<T>],
18757        auto_scroll: bool,
18758        cx: &mut Context<Self>,
18759        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18760    ) {
18761        if ranges.is_empty() {
18762            return;
18763        }
18764
18765        let mut buffers_affected = HashSet::default();
18766        let multi_buffer = self.buffer().read(cx);
18767        for range in ranges {
18768            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18769                buffers_affected.insert(buffer.read(cx).remote_id());
18770            };
18771        }
18772
18773        self.display_map.update(cx, update);
18774
18775        if auto_scroll {
18776            self.request_autoscroll(Autoscroll::fit(), cx);
18777        }
18778
18779        cx.notify();
18780        self.scrollbar_marker_state.dirty = true;
18781        self.active_indent_guides_state.dirty = true;
18782    }
18783
18784    pub fn update_renderer_widths(
18785        &mut self,
18786        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18787        cx: &mut Context<Self>,
18788    ) -> bool {
18789        self.display_map
18790            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18791    }
18792
18793    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18794        self.display_map.read(cx).fold_placeholder.clone()
18795    }
18796
18797    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18798        self.buffer.update(cx, |buffer, cx| {
18799            buffer.set_all_diff_hunks_expanded(cx);
18800        });
18801    }
18802
18803    pub fn expand_all_diff_hunks(
18804        &mut self,
18805        _: &ExpandAllDiffHunks,
18806        _window: &mut Window,
18807        cx: &mut Context<Self>,
18808    ) {
18809        self.buffer.update(cx, |buffer, cx| {
18810            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18811        });
18812    }
18813
18814    pub fn collapse_all_diff_hunks(
18815        &mut self,
18816        _: &CollapseAllDiffHunks,
18817        _window: &mut Window,
18818        cx: &mut Context<Self>,
18819    ) {
18820        self.buffer.update(cx, |buffer, cx| {
18821            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18822        });
18823    }
18824
18825    pub fn toggle_selected_diff_hunks(
18826        &mut self,
18827        _: &ToggleSelectedDiffHunks,
18828        _window: &mut Window,
18829        cx: &mut Context<Self>,
18830    ) {
18831        let ranges: Vec<_> = self
18832            .selections
18833            .disjoint_anchors()
18834            .iter()
18835            .map(|s| s.range())
18836            .collect();
18837        self.toggle_diff_hunks_in_ranges(ranges, cx);
18838    }
18839
18840    pub fn diff_hunks_in_ranges<'a>(
18841        &'a self,
18842        ranges: &'a [Range<Anchor>],
18843        buffer: &'a MultiBufferSnapshot,
18844    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18845        ranges.iter().flat_map(move |range| {
18846            let end_excerpt_id = range.end.excerpt_id;
18847            let range = range.to_point(buffer);
18848            let mut peek_end = range.end;
18849            if range.end.row < buffer.max_row().0 {
18850                peek_end = Point::new(range.end.row + 1, 0);
18851            }
18852            buffer
18853                .diff_hunks_in_range(range.start..peek_end)
18854                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18855        })
18856    }
18857
18858    pub fn has_stageable_diff_hunks_in_ranges(
18859        &self,
18860        ranges: &[Range<Anchor>],
18861        snapshot: &MultiBufferSnapshot,
18862    ) -> bool {
18863        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18864        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18865    }
18866
18867    pub fn toggle_staged_selected_diff_hunks(
18868        &mut self,
18869        _: &::git::ToggleStaged,
18870        _: &mut Window,
18871        cx: &mut Context<Self>,
18872    ) {
18873        let snapshot = self.buffer.read(cx).snapshot(cx);
18874        let ranges: Vec<_> = self
18875            .selections
18876            .disjoint_anchors()
18877            .iter()
18878            .map(|s| s.range())
18879            .collect();
18880        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18881        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18882    }
18883
18884    pub fn set_render_diff_hunk_controls(
18885        &mut self,
18886        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18887        cx: &mut Context<Self>,
18888    ) {
18889        self.render_diff_hunk_controls = render_diff_hunk_controls;
18890        cx.notify();
18891    }
18892
18893    pub fn stage_and_next(
18894        &mut self,
18895        _: &::git::StageAndNext,
18896        window: &mut Window,
18897        cx: &mut Context<Self>,
18898    ) {
18899        self.do_stage_or_unstage_and_next(true, window, cx);
18900    }
18901
18902    pub fn unstage_and_next(
18903        &mut self,
18904        _: &::git::UnstageAndNext,
18905        window: &mut Window,
18906        cx: &mut Context<Self>,
18907    ) {
18908        self.do_stage_or_unstage_and_next(false, window, cx);
18909    }
18910
18911    pub fn stage_or_unstage_diff_hunks(
18912        &mut self,
18913        stage: bool,
18914        ranges: Vec<Range<Anchor>>,
18915        cx: &mut Context<Self>,
18916    ) {
18917        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18918        cx.spawn(async move |this, cx| {
18919            task.await?;
18920            this.update(cx, |this, cx| {
18921                let snapshot = this.buffer.read(cx).snapshot(cx);
18922                let chunk_by = this
18923                    .diff_hunks_in_ranges(&ranges, &snapshot)
18924                    .chunk_by(|hunk| hunk.buffer_id);
18925                for (buffer_id, hunks) in &chunk_by {
18926                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18927                }
18928            })
18929        })
18930        .detach_and_log_err(cx);
18931    }
18932
18933    fn save_buffers_for_ranges_if_needed(
18934        &mut self,
18935        ranges: &[Range<Anchor>],
18936        cx: &mut Context<Editor>,
18937    ) -> Task<Result<()>> {
18938        let multibuffer = self.buffer.read(cx);
18939        let snapshot = multibuffer.read(cx);
18940        let buffer_ids: HashSet<_> = ranges
18941            .iter()
18942            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18943            .collect();
18944        drop(snapshot);
18945
18946        let mut buffers = HashSet::default();
18947        for buffer_id in buffer_ids {
18948            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18949                let buffer = buffer_entity.read(cx);
18950                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18951                {
18952                    buffers.insert(buffer_entity);
18953                }
18954            }
18955        }
18956
18957        if let Some(project) = &self.project {
18958            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18959        } else {
18960            Task::ready(Ok(()))
18961        }
18962    }
18963
18964    fn do_stage_or_unstage_and_next(
18965        &mut self,
18966        stage: bool,
18967        window: &mut Window,
18968        cx: &mut Context<Self>,
18969    ) {
18970        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18971
18972        if ranges.iter().any(|range| range.start != range.end) {
18973            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18974            return;
18975        }
18976
18977        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18978        let snapshot = self.snapshot(window, cx);
18979        let position = self
18980            .selections
18981            .newest::<Point>(&snapshot.display_snapshot)
18982            .head();
18983        let mut row = snapshot
18984            .buffer_snapshot()
18985            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
18986            .find(|hunk| hunk.row_range.start.0 > position.row)
18987            .map(|hunk| hunk.row_range.start);
18988
18989        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18990        // Outside of the project diff editor, wrap around to the beginning.
18991        if !all_diff_hunks_expanded {
18992            row = row.or_else(|| {
18993                snapshot
18994                    .buffer_snapshot()
18995                    .diff_hunks_in_range(Point::zero()..position)
18996                    .find(|hunk| hunk.row_range.end.0 < position.row)
18997                    .map(|hunk| hunk.row_range.start)
18998            });
18999        }
19000
19001        if let Some(row) = row {
19002            let destination = Point::new(row.0, 0);
19003            let autoscroll = Autoscroll::center();
19004
19005            self.unfold_ranges(&[destination..destination], false, false, cx);
19006            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
19007                s.select_ranges([destination..destination]);
19008            });
19009        }
19010    }
19011
19012    fn do_stage_or_unstage(
19013        &self,
19014        stage: bool,
19015        buffer_id: BufferId,
19016        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
19017        cx: &mut App,
19018    ) -> Option<()> {
19019        let project = self.project()?;
19020        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19021        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19022        let buffer_snapshot = buffer.read(cx).snapshot();
19023        let file_exists = buffer_snapshot
19024            .file()
19025            .is_some_and(|file| file.disk_state().exists());
19026        diff.update(cx, |diff, cx| {
19027            diff.stage_or_unstage_hunks(
19028                stage,
19029                &hunks
19030                    .map(|hunk| buffer_diff::DiffHunk {
19031                        buffer_range: hunk.buffer_range,
19032                        diff_base_byte_range: hunk.diff_base_byte_range,
19033                        secondary_status: hunk.secondary_status,
19034                        range: Point::zero()..Point::zero(), // unused
19035                    })
19036                    .collect::<Vec<_>>(),
19037                &buffer_snapshot,
19038                file_exists,
19039                cx,
19040            )
19041        });
19042        None
19043    }
19044
19045    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19046        let ranges: Vec<_> = self
19047            .selections
19048            .disjoint_anchors()
19049            .iter()
19050            .map(|s| s.range())
19051            .collect();
19052        self.buffer
19053            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19054    }
19055
19056    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19057        self.buffer.update(cx, |buffer, cx| {
19058            let ranges = vec![Anchor::min()..Anchor::max()];
19059            if !buffer.all_diff_hunks_expanded()
19060                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19061            {
19062                buffer.collapse_diff_hunks(ranges, cx);
19063                true
19064            } else {
19065                false
19066            }
19067        })
19068    }
19069
19070    fn toggle_diff_hunks_in_ranges(
19071        &mut self,
19072        ranges: Vec<Range<Anchor>>,
19073        cx: &mut Context<Editor>,
19074    ) {
19075        self.buffer.update(cx, |buffer, cx| {
19076            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
19077            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
19078        })
19079    }
19080
19081    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
19082        self.buffer.update(cx, |buffer, cx| {
19083            let snapshot = buffer.snapshot(cx);
19084            let excerpt_id = range.end.excerpt_id;
19085            let point_range = range.to_point(&snapshot);
19086            let expand = !buffer.single_hunk_is_expanded(range, cx);
19087            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
19088        })
19089    }
19090
19091    pub(crate) fn apply_all_diff_hunks(
19092        &mut self,
19093        _: &ApplyAllDiffHunks,
19094        window: &mut Window,
19095        cx: &mut Context<Self>,
19096    ) {
19097        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19098
19099        let buffers = self.buffer.read(cx).all_buffers();
19100        for branch_buffer in buffers {
19101            branch_buffer.update(cx, |branch_buffer, cx| {
19102                branch_buffer.merge_into_base(Vec::new(), cx);
19103            });
19104        }
19105
19106        if let Some(project) = self.project.clone() {
19107            self.save(
19108                SaveOptions {
19109                    format: true,
19110                    autosave: false,
19111                },
19112                project,
19113                window,
19114                cx,
19115            )
19116            .detach_and_log_err(cx);
19117        }
19118    }
19119
19120    pub(crate) fn apply_selected_diff_hunks(
19121        &mut self,
19122        _: &ApplyDiffHunk,
19123        window: &mut Window,
19124        cx: &mut Context<Self>,
19125    ) {
19126        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19127        let snapshot = self.snapshot(window, cx);
19128        let hunks = snapshot.hunks_for_ranges(
19129            self.selections
19130                .all(&snapshot.display_snapshot)
19131                .into_iter()
19132                .map(|selection| selection.range()),
19133        );
19134        let mut ranges_by_buffer = HashMap::default();
19135        self.transact(window, cx, |editor, _window, cx| {
19136            for hunk in hunks {
19137                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19138                    ranges_by_buffer
19139                        .entry(buffer.clone())
19140                        .or_insert_with(Vec::new)
19141                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19142                }
19143            }
19144
19145            for (buffer, ranges) in ranges_by_buffer {
19146                buffer.update(cx, |buffer, cx| {
19147                    buffer.merge_into_base(ranges, cx);
19148                });
19149            }
19150        });
19151
19152        if let Some(project) = self.project.clone() {
19153            self.save(
19154                SaveOptions {
19155                    format: true,
19156                    autosave: false,
19157                },
19158                project,
19159                window,
19160                cx,
19161            )
19162            .detach_and_log_err(cx);
19163        }
19164    }
19165
19166    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19167        if hovered != self.gutter_hovered {
19168            self.gutter_hovered = hovered;
19169            cx.notify();
19170        }
19171    }
19172
19173    pub fn insert_blocks(
19174        &mut self,
19175        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19176        autoscroll: Option<Autoscroll>,
19177        cx: &mut Context<Self>,
19178    ) -> Vec<CustomBlockId> {
19179        let blocks = self
19180            .display_map
19181            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19182        if let Some(autoscroll) = autoscroll {
19183            self.request_autoscroll(autoscroll, cx);
19184        }
19185        cx.notify();
19186        blocks
19187    }
19188
19189    pub fn resize_blocks(
19190        &mut self,
19191        heights: HashMap<CustomBlockId, u32>,
19192        autoscroll: Option<Autoscroll>,
19193        cx: &mut Context<Self>,
19194    ) {
19195        self.display_map
19196            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19197        if let Some(autoscroll) = autoscroll {
19198            self.request_autoscroll(autoscroll, cx);
19199        }
19200        cx.notify();
19201    }
19202
19203    pub fn replace_blocks(
19204        &mut self,
19205        renderers: HashMap<CustomBlockId, RenderBlock>,
19206        autoscroll: Option<Autoscroll>,
19207        cx: &mut Context<Self>,
19208    ) {
19209        self.display_map
19210            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19211        if let Some(autoscroll) = autoscroll {
19212            self.request_autoscroll(autoscroll, cx);
19213        }
19214        cx.notify();
19215    }
19216
19217    pub fn remove_blocks(
19218        &mut self,
19219        block_ids: HashSet<CustomBlockId>,
19220        autoscroll: Option<Autoscroll>,
19221        cx: &mut Context<Self>,
19222    ) {
19223        self.display_map.update(cx, |display_map, cx| {
19224            display_map.remove_blocks(block_ids, cx)
19225        });
19226        if let Some(autoscroll) = autoscroll {
19227            self.request_autoscroll(autoscroll, cx);
19228        }
19229        cx.notify();
19230    }
19231
19232    pub fn row_for_block(
19233        &self,
19234        block_id: CustomBlockId,
19235        cx: &mut Context<Self>,
19236    ) -> Option<DisplayRow> {
19237        self.display_map
19238            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19239    }
19240
19241    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19242        self.focused_block = Some(focused_block);
19243    }
19244
19245    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19246        self.focused_block.take()
19247    }
19248
19249    pub fn insert_creases(
19250        &mut self,
19251        creases: impl IntoIterator<Item = Crease<Anchor>>,
19252        cx: &mut Context<Self>,
19253    ) -> Vec<CreaseId> {
19254        self.display_map
19255            .update(cx, |map, cx| map.insert_creases(creases, cx))
19256    }
19257
19258    pub fn remove_creases(
19259        &mut self,
19260        ids: impl IntoIterator<Item = CreaseId>,
19261        cx: &mut Context<Self>,
19262    ) -> Vec<(CreaseId, Range<Anchor>)> {
19263        self.display_map
19264            .update(cx, |map, cx| map.remove_creases(ids, cx))
19265    }
19266
19267    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19268        self.display_map
19269            .update(cx, |map, cx| map.snapshot(cx))
19270            .longest_row()
19271    }
19272
19273    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19274        self.display_map
19275            .update(cx, |map, cx| map.snapshot(cx))
19276            .max_point()
19277    }
19278
19279    pub fn text(&self, cx: &App) -> String {
19280        self.buffer.read(cx).read(cx).text()
19281    }
19282
19283    pub fn is_empty(&self, cx: &App) -> bool {
19284        self.buffer.read(cx).read(cx).is_empty()
19285    }
19286
19287    pub fn text_option(&self, cx: &App) -> Option<String> {
19288        let text = self.text(cx);
19289        let text = text.trim();
19290
19291        if text.is_empty() {
19292            return None;
19293        }
19294
19295        Some(text.to_string())
19296    }
19297
19298    pub fn set_text(
19299        &mut self,
19300        text: impl Into<Arc<str>>,
19301        window: &mut Window,
19302        cx: &mut Context<Self>,
19303    ) {
19304        self.transact(window, cx, |this, _, cx| {
19305            this.buffer
19306                .read(cx)
19307                .as_singleton()
19308                .expect("you can only call set_text on editors for singleton buffers")
19309                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19310        });
19311    }
19312
19313    pub fn display_text(&self, cx: &mut App) -> String {
19314        self.display_map
19315            .update(cx, |map, cx| map.snapshot(cx))
19316            .text()
19317    }
19318
19319    fn create_minimap(
19320        &self,
19321        minimap_settings: MinimapSettings,
19322        window: &mut Window,
19323        cx: &mut Context<Self>,
19324    ) -> Option<Entity<Self>> {
19325        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19326            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19327    }
19328
19329    fn initialize_new_minimap(
19330        &self,
19331        minimap_settings: MinimapSettings,
19332        window: &mut Window,
19333        cx: &mut Context<Self>,
19334    ) -> Entity<Self> {
19335        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19336
19337        let mut minimap = Editor::new_internal(
19338            EditorMode::Minimap {
19339                parent: cx.weak_entity(),
19340            },
19341            self.buffer.clone(),
19342            None,
19343            Some(self.display_map.clone()),
19344            window,
19345            cx,
19346        );
19347        minimap.scroll_manager.clone_state(&self.scroll_manager);
19348        minimap.set_text_style_refinement(TextStyleRefinement {
19349            font_size: Some(MINIMAP_FONT_SIZE),
19350            font_weight: Some(MINIMAP_FONT_WEIGHT),
19351            ..Default::default()
19352        });
19353        minimap.update_minimap_configuration(minimap_settings, cx);
19354        cx.new(|_| minimap)
19355    }
19356
19357    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19358        let current_line_highlight = minimap_settings
19359            .current_line_highlight
19360            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19361        self.set_current_line_highlight(Some(current_line_highlight));
19362    }
19363
19364    pub fn minimap(&self) -> Option<&Entity<Self>> {
19365        self.minimap
19366            .as_ref()
19367            .filter(|_| self.minimap_visibility.visible())
19368    }
19369
19370    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19371        let mut wrap_guides = smallvec![];
19372
19373        if self.show_wrap_guides == Some(false) {
19374            return wrap_guides;
19375        }
19376
19377        let settings = self.buffer.read(cx).language_settings(cx);
19378        if settings.show_wrap_guides {
19379            match self.soft_wrap_mode(cx) {
19380                SoftWrap::Column(soft_wrap) => {
19381                    wrap_guides.push((soft_wrap as usize, true));
19382                }
19383                SoftWrap::Bounded(soft_wrap) => {
19384                    wrap_guides.push((soft_wrap as usize, true));
19385                }
19386                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19387            }
19388            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19389        }
19390
19391        wrap_guides
19392    }
19393
19394    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19395        let settings = self.buffer.read(cx).language_settings(cx);
19396        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19397        match mode {
19398            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19399                SoftWrap::None
19400            }
19401            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19402            language_settings::SoftWrap::PreferredLineLength => {
19403                SoftWrap::Column(settings.preferred_line_length)
19404            }
19405            language_settings::SoftWrap::Bounded => {
19406                SoftWrap::Bounded(settings.preferred_line_length)
19407            }
19408        }
19409    }
19410
19411    pub fn set_soft_wrap_mode(
19412        &mut self,
19413        mode: language_settings::SoftWrap,
19414
19415        cx: &mut Context<Self>,
19416    ) {
19417        self.soft_wrap_mode_override = Some(mode);
19418        cx.notify();
19419    }
19420
19421    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19422        self.hard_wrap = hard_wrap;
19423        cx.notify();
19424    }
19425
19426    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19427        self.text_style_refinement = Some(style);
19428    }
19429
19430    /// called by the Element so we know what style we were most recently rendered with.
19431    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19432        // We intentionally do not inform the display map about the minimap style
19433        // so that wrapping is not recalculated and stays consistent for the editor
19434        // and its linked minimap.
19435        if !self.mode.is_minimap() {
19436            let font = style.text.font();
19437            let font_size = style.text.font_size.to_pixels(window.rem_size());
19438            let display_map = self
19439                .placeholder_display_map
19440                .as_ref()
19441                .filter(|_| self.is_empty(cx))
19442                .unwrap_or(&self.display_map);
19443
19444            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19445        }
19446        self.style = Some(style);
19447    }
19448
19449    pub fn style(&self) -> Option<&EditorStyle> {
19450        self.style.as_ref()
19451    }
19452
19453    // Called by the element. This method is not designed to be called outside of the editor
19454    // element's layout code because it does not notify when rewrapping is computed synchronously.
19455    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19456        if self.is_empty(cx) {
19457            self.placeholder_display_map
19458                .as_ref()
19459                .map_or(false, |display_map| {
19460                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19461                })
19462        } else {
19463            self.display_map
19464                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19465        }
19466    }
19467
19468    pub fn set_soft_wrap(&mut self) {
19469        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19470    }
19471
19472    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19473        if self.soft_wrap_mode_override.is_some() {
19474            self.soft_wrap_mode_override.take();
19475        } else {
19476            let soft_wrap = match self.soft_wrap_mode(cx) {
19477                SoftWrap::GitDiff => return,
19478                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19479                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19480                    language_settings::SoftWrap::None
19481                }
19482            };
19483            self.soft_wrap_mode_override = Some(soft_wrap);
19484        }
19485        cx.notify();
19486    }
19487
19488    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19489        let Some(workspace) = self.workspace() else {
19490            return;
19491        };
19492        let fs = workspace.read(cx).app_state().fs.clone();
19493        let current_show = TabBarSettings::get_global(cx).show;
19494        update_settings_file(fs, cx, move |setting, _| {
19495            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19496        });
19497    }
19498
19499    pub fn toggle_indent_guides(
19500        &mut self,
19501        _: &ToggleIndentGuides,
19502        _: &mut Window,
19503        cx: &mut Context<Self>,
19504    ) {
19505        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19506            self.buffer
19507                .read(cx)
19508                .language_settings(cx)
19509                .indent_guides
19510                .enabled
19511        });
19512        self.show_indent_guides = Some(!currently_enabled);
19513        cx.notify();
19514    }
19515
19516    fn should_show_indent_guides(&self) -> Option<bool> {
19517        self.show_indent_guides
19518    }
19519
19520    pub fn toggle_line_numbers(
19521        &mut self,
19522        _: &ToggleLineNumbers,
19523        _: &mut Window,
19524        cx: &mut Context<Self>,
19525    ) {
19526        let mut editor_settings = EditorSettings::get_global(cx).clone();
19527        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19528        EditorSettings::override_global(editor_settings, cx);
19529    }
19530
19531    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19532        if let Some(show_line_numbers) = self.show_line_numbers {
19533            return show_line_numbers;
19534        }
19535        EditorSettings::get_global(cx).gutter.line_numbers
19536    }
19537
19538    pub fn relative_line_numbers(&self, cx: &mut App) -> RelativeLineNumbers {
19539        match (
19540            self.use_relative_line_numbers,
19541            EditorSettings::get_global(cx).relative_line_numbers,
19542        ) {
19543            (None, setting) => setting,
19544            (Some(false), _) => RelativeLineNumbers::Disabled,
19545            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
19546            (Some(true), _) => RelativeLineNumbers::Enabled,
19547        }
19548    }
19549
19550    pub fn toggle_relative_line_numbers(
19551        &mut self,
19552        _: &ToggleRelativeLineNumbers,
19553        _: &mut Window,
19554        cx: &mut Context<Self>,
19555    ) {
19556        let is_relative = self.relative_line_numbers(cx);
19557        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
19558    }
19559
19560    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19561        self.use_relative_line_numbers = is_relative;
19562        cx.notify();
19563    }
19564
19565    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19566        self.show_gutter = show_gutter;
19567        cx.notify();
19568    }
19569
19570    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19571        self.show_scrollbars = ScrollbarAxes {
19572            horizontal: show,
19573            vertical: show,
19574        };
19575        cx.notify();
19576    }
19577
19578    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19579        self.show_scrollbars.vertical = show;
19580        cx.notify();
19581    }
19582
19583    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19584        self.show_scrollbars.horizontal = show;
19585        cx.notify();
19586    }
19587
19588    pub fn set_minimap_visibility(
19589        &mut self,
19590        minimap_visibility: MinimapVisibility,
19591        window: &mut Window,
19592        cx: &mut Context<Self>,
19593    ) {
19594        if self.minimap_visibility != minimap_visibility {
19595            if minimap_visibility.visible() && self.minimap.is_none() {
19596                let minimap_settings = EditorSettings::get_global(cx).minimap;
19597                self.minimap =
19598                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19599            }
19600            self.minimap_visibility = minimap_visibility;
19601            cx.notify();
19602        }
19603    }
19604
19605    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19606        self.set_show_scrollbars(false, cx);
19607        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19608    }
19609
19610    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19611        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19612    }
19613
19614    /// Normally the text in full mode and auto height editors is padded on the
19615    /// left side by roughly half a character width for improved hit testing.
19616    ///
19617    /// Use this method to disable this for cases where this is not wanted (e.g.
19618    /// if you want to align the editor text with some other text above or below)
19619    /// or if you want to add this padding to single-line editors.
19620    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19621        self.offset_content = offset_content;
19622        cx.notify();
19623    }
19624
19625    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19626        self.show_line_numbers = Some(show_line_numbers);
19627        cx.notify();
19628    }
19629
19630    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19631        self.disable_expand_excerpt_buttons = true;
19632        cx.notify();
19633    }
19634
19635    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19636        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19637        cx.notify();
19638    }
19639
19640    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19641        self.show_code_actions = Some(show_code_actions);
19642        cx.notify();
19643    }
19644
19645    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19646        self.show_runnables = Some(show_runnables);
19647        cx.notify();
19648    }
19649
19650    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19651        self.show_breakpoints = Some(show_breakpoints);
19652        cx.notify();
19653    }
19654
19655    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19656        if self.display_map.read(cx).masked != masked {
19657            self.display_map.update(cx, |map, _| map.masked = masked);
19658        }
19659        cx.notify()
19660    }
19661
19662    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19663        self.show_wrap_guides = Some(show_wrap_guides);
19664        cx.notify();
19665    }
19666
19667    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19668        self.show_indent_guides = Some(show_indent_guides);
19669        cx.notify();
19670    }
19671
19672    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19673        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19674            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19675                && let Some(dir) = file.abs_path(cx).parent()
19676            {
19677                return Some(dir.to_owned());
19678            }
19679        }
19680
19681        None
19682    }
19683
19684    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19685        self.active_excerpt(cx)?
19686            .1
19687            .read(cx)
19688            .file()
19689            .and_then(|f| f.as_local())
19690    }
19691
19692    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19693        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19694            let buffer = buffer.read(cx);
19695            if let Some(project_path) = buffer.project_path(cx) {
19696                let project = self.project()?.read(cx);
19697                project.absolute_path(&project_path, cx)
19698            } else {
19699                buffer
19700                    .file()
19701                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19702            }
19703        })
19704    }
19705
19706    pub fn reveal_in_finder(
19707        &mut self,
19708        _: &RevealInFileManager,
19709        _window: &mut Window,
19710        cx: &mut Context<Self>,
19711    ) {
19712        if let Some(target) = self.target_file(cx) {
19713            cx.reveal_path(&target.abs_path(cx));
19714        }
19715    }
19716
19717    pub fn copy_path(
19718        &mut self,
19719        _: &zed_actions::workspace::CopyPath,
19720        _window: &mut Window,
19721        cx: &mut Context<Self>,
19722    ) {
19723        if let Some(path) = self.target_file_abs_path(cx)
19724            && let Some(path) = path.to_str()
19725        {
19726            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19727        } else {
19728            cx.propagate();
19729        }
19730    }
19731
19732    pub fn copy_relative_path(
19733        &mut self,
19734        _: &zed_actions::workspace::CopyRelativePath,
19735        _window: &mut Window,
19736        cx: &mut Context<Self>,
19737    ) {
19738        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19739            let project = self.project()?.read(cx);
19740            let path = buffer.read(cx).file()?.path();
19741            let path = path.display(project.path_style(cx));
19742            Some(path)
19743        }) {
19744            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19745        } else {
19746            cx.propagate();
19747        }
19748    }
19749
19750    /// Returns the project path for the editor's buffer, if any buffer is
19751    /// opened in the editor.
19752    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19753        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19754            buffer.read(cx).project_path(cx)
19755        } else {
19756            None
19757        }
19758    }
19759
19760    // Returns true if the editor handled a go-to-line request
19761    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19762        maybe!({
19763            let breakpoint_store = self.breakpoint_store.as_ref()?;
19764
19765            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19766            else {
19767                self.clear_row_highlights::<ActiveDebugLine>();
19768                return None;
19769            };
19770
19771            let position = active_stack_frame.position;
19772            let buffer_id = position.buffer_id?;
19773            let snapshot = self
19774                .project
19775                .as_ref()?
19776                .read(cx)
19777                .buffer_for_id(buffer_id, cx)?
19778                .read(cx)
19779                .snapshot();
19780
19781            let mut handled = false;
19782            for (id, ExcerptRange { context, .. }) in
19783                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19784            {
19785                if context.start.cmp(&position, &snapshot).is_ge()
19786                    || context.end.cmp(&position, &snapshot).is_lt()
19787                {
19788                    continue;
19789                }
19790                let snapshot = self.buffer.read(cx).snapshot(cx);
19791                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19792
19793                handled = true;
19794                self.clear_row_highlights::<ActiveDebugLine>();
19795
19796                self.go_to_line::<ActiveDebugLine>(
19797                    multibuffer_anchor,
19798                    Some(cx.theme().colors().editor_debugger_active_line_background),
19799                    window,
19800                    cx,
19801                );
19802
19803                cx.notify();
19804            }
19805
19806            handled.then_some(())
19807        })
19808        .is_some()
19809    }
19810
19811    pub fn copy_file_name_without_extension(
19812        &mut self,
19813        _: &CopyFileNameWithoutExtension,
19814        _: &mut Window,
19815        cx: &mut Context<Self>,
19816    ) {
19817        if let Some(file) = self.target_file(cx)
19818            && let Some(file_stem) = file.path().file_stem()
19819        {
19820            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
19821        }
19822    }
19823
19824    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19825        if let Some(file) = self.target_file(cx)
19826            && let Some(name) = file.path().file_name()
19827        {
19828            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19829        }
19830    }
19831
19832    pub fn toggle_git_blame(
19833        &mut self,
19834        _: &::git::Blame,
19835        window: &mut Window,
19836        cx: &mut Context<Self>,
19837    ) {
19838        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19839
19840        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19841            self.start_git_blame(true, window, cx);
19842        }
19843
19844        cx.notify();
19845    }
19846
19847    pub fn toggle_git_blame_inline(
19848        &mut self,
19849        _: &ToggleGitBlameInline,
19850        window: &mut Window,
19851        cx: &mut Context<Self>,
19852    ) {
19853        self.toggle_git_blame_inline_internal(true, window, cx);
19854        cx.notify();
19855    }
19856
19857    pub fn open_git_blame_commit(
19858        &mut self,
19859        _: &OpenGitBlameCommit,
19860        window: &mut Window,
19861        cx: &mut Context<Self>,
19862    ) {
19863        self.open_git_blame_commit_internal(window, cx);
19864    }
19865
19866    fn open_git_blame_commit_internal(
19867        &mut self,
19868        window: &mut Window,
19869        cx: &mut Context<Self>,
19870    ) -> Option<()> {
19871        let blame = self.blame.as_ref()?;
19872        let snapshot = self.snapshot(window, cx);
19873        let cursor = self
19874            .selections
19875            .newest::<Point>(&snapshot.display_snapshot)
19876            .head();
19877        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
19878        let (_, blame_entry) = blame
19879            .update(cx, |blame, cx| {
19880                blame
19881                    .blame_for_rows(
19882                        &[RowInfo {
19883                            buffer_id: Some(buffer.remote_id()),
19884                            buffer_row: Some(point.row),
19885                            ..Default::default()
19886                        }],
19887                        cx,
19888                    )
19889                    .next()
19890            })
19891            .flatten()?;
19892        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19893        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19894        let workspace = self.workspace()?.downgrade();
19895        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19896        None
19897    }
19898
19899    pub fn git_blame_inline_enabled(&self) -> bool {
19900        self.git_blame_inline_enabled
19901    }
19902
19903    pub fn toggle_selection_menu(
19904        &mut self,
19905        _: &ToggleSelectionMenu,
19906        _: &mut Window,
19907        cx: &mut Context<Self>,
19908    ) {
19909        self.show_selection_menu = self
19910            .show_selection_menu
19911            .map(|show_selections_menu| !show_selections_menu)
19912            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19913
19914        cx.notify();
19915    }
19916
19917    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19918        self.show_selection_menu
19919            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19920    }
19921
19922    fn start_git_blame(
19923        &mut self,
19924        user_triggered: bool,
19925        window: &mut Window,
19926        cx: &mut Context<Self>,
19927    ) {
19928        if let Some(project) = self.project() {
19929            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19930                && buffer.read(cx).file().is_none()
19931            {
19932                return;
19933            }
19934
19935            let focused = self.focus_handle(cx).contains_focused(window, cx);
19936
19937            let project = project.clone();
19938            let blame = cx
19939                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19940            self.blame_subscription =
19941                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19942            self.blame = Some(blame);
19943        }
19944    }
19945
19946    fn toggle_git_blame_inline_internal(
19947        &mut self,
19948        user_triggered: bool,
19949        window: &mut Window,
19950        cx: &mut Context<Self>,
19951    ) {
19952        if self.git_blame_inline_enabled {
19953            self.git_blame_inline_enabled = false;
19954            self.show_git_blame_inline = false;
19955            self.show_git_blame_inline_delay_task.take();
19956        } else {
19957            self.git_blame_inline_enabled = true;
19958            self.start_git_blame_inline(user_triggered, window, cx);
19959        }
19960
19961        cx.notify();
19962    }
19963
19964    fn start_git_blame_inline(
19965        &mut self,
19966        user_triggered: bool,
19967        window: &mut Window,
19968        cx: &mut Context<Self>,
19969    ) {
19970        self.start_git_blame(user_triggered, window, cx);
19971
19972        if ProjectSettings::get_global(cx)
19973            .git
19974            .inline_blame_delay()
19975            .is_some()
19976        {
19977            self.start_inline_blame_timer(window, cx);
19978        } else {
19979            self.show_git_blame_inline = true
19980        }
19981    }
19982
19983    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19984        self.blame.as_ref()
19985    }
19986
19987    pub fn show_git_blame_gutter(&self) -> bool {
19988        self.show_git_blame_gutter
19989    }
19990
19991    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19992        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19993    }
19994
19995    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19996        self.show_git_blame_inline
19997            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19998            && !self.newest_selection_head_on_empty_line(cx)
19999            && self.has_blame_entries(cx)
20000    }
20001
20002    fn has_blame_entries(&self, cx: &App) -> bool {
20003        self.blame()
20004            .is_some_and(|blame| blame.read(cx).has_generated_entries())
20005    }
20006
20007    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
20008        let cursor_anchor = self.selections.newest_anchor().head();
20009
20010        let snapshot = self.buffer.read(cx).snapshot(cx);
20011        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
20012
20013        snapshot.line_len(buffer_row) == 0
20014    }
20015
20016    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
20017        let buffer_and_selection = maybe!({
20018            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20019            let selection_range = selection.range();
20020
20021            let multi_buffer = self.buffer().read(cx);
20022            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20023            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
20024
20025            let (buffer, range, _) = if selection.reversed {
20026                buffer_ranges.first()
20027            } else {
20028                buffer_ranges.last()
20029            }?;
20030
20031            let selection = text::ToPoint::to_point(&range.start, buffer).row
20032                ..text::ToPoint::to_point(&range.end, buffer).row;
20033            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
20034        });
20035
20036        let Some((buffer, selection)) = buffer_and_selection else {
20037            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
20038        };
20039
20040        let Some(project) = self.project() else {
20041            return Task::ready(Err(anyhow!("editor does not have project")));
20042        };
20043
20044        project.update(cx, |project, cx| {
20045            project.get_permalink_to_line(&buffer, selection, cx)
20046        })
20047    }
20048
20049    pub fn copy_permalink_to_line(
20050        &mut self,
20051        _: &CopyPermalinkToLine,
20052        window: &mut Window,
20053        cx: &mut Context<Self>,
20054    ) {
20055        let permalink_task = self.get_permalink_to_line(cx);
20056        let workspace = self.workspace();
20057
20058        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20059            Ok(permalink) => {
20060                cx.update(|_, cx| {
20061                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
20062                })
20063                .ok();
20064            }
20065            Err(err) => {
20066                let message = format!("Failed to copy permalink: {err}");
20067
20068                anyhow::Result::<()>::Err(err).log_err();
20069
20070                if let Some(workspace) = workspace {
20071                    workspace
20072                        .update_in(cx, |workspace, _, cx| {
20073                            struct CopyPermalinkToLine;
20074
20075                            workspace.show_toast(
20076                                Toast::new(
20077                                    NotificationId::unique::<CopyPermalinkToLine>(),
20078                                    message,
20079                                ),
20080                                cx,
20081                            )
20082                        })
20083                        .ok();
20084                }
20085            }
20086        })
20087        .detach();
20088    }
20089
20090    pub fn copy_file_location(
20091        &mut self,
20092        _: &CopyFileLocation,
20093        _: &mut Window,
20094        cx: &mut Context<Self>,
20095    ) {
20096        let selection = self
20097            .selections
20098            .newest::<Point>(&self.display_snapshot(cx))
20099            .start
20100            .row
20101            + 1;
20102        if let Some(file) = self.target_file(cx) {
20103            let path = file.path().display(file.path_style(cx));
20104            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
20105        }
20106    }
20107
20108    pub fn open_permalink_to_line(
20109        &mut self,
20110        _: &OpenPermalinkToLine,
20111        window: &mut Window,
20112        cx: &mut Context<Self>,
20113    ) {
20114        let permalink_task = self.get_permalink_to_line(cx);
20115        let workspace = self.workspace();
20116
20117        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20118            Ok(permalink) => {
20119                cx.update(|_, cx| {
20120                    cx.open_url(permalink.as_ref());
20121                })
20122                .ok();
20123            }
20124            Err(err) => {
20125                let message = format!("Failed to open permalink: {err}");
20126
20127                anyhow::Result::<()>::Err(err).log_err();
20128
20129                if let Some(workspace) = workspace {
20130                    workspace
20131                        .update(cx, |workspace, cx| {
20132                            struct OpenPermalinkToLine;
20133
20134                            workspace.show_toast(
20135                                Toast::new(
20136                                    NotificationId::unique::<OpenPermalinkToLine>(),
20137                                    message,
20138                                ),
20139                                cx,
20140                            )
20141                        })
20142                        .ok();
20143                }
20144            }
20145        })
20146        .detach();
20147    }
20148
20149    pub fn insert_uuid_v4(
20150        &mut self,
20151        _: &InsertUuidV4,
20152        window: &mut Window,
20153        cx: &mut Context<Self>,
20154    ) {
20155        self.insert_uuid(UuidVersion::V4, window, cx);
20156    }
20157
20158    pub fn insert_uuid_v7(
20159        &mut self,
20160        _: &InsertUuidV7,
20161        window: &mut Window,
20162        cx: &mut Context<Self>,
20163    ) {
20164        self.insert_uuid(UuidVersion::V7, window, cx);
20165    }
20166
20167    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20168        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20169        self.transact(window, cx, |this, window, cx| {
20170            let edits = this
20171                .selections
20172                .all::<Point>(&this.display_snapshot(cx))
20173                .into_iter()
20174                .map(|selection| {
20175                    let uuid = match version {
20176                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20177                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20178                    };
20179
20180                    (selection.range(), uuid.to_string())
20181                });
20182            this.edit(edits, cx);
20183            this.refresh_edit_prediction(true, false, window, cx);
20184        });
20185    }
20186
20187    pub fn open_selections_in_multibuffer(
20188        &mut self,
20189        _: &OpenSelectionsInMultibuffer,
20190        window: &mut Window,
20191        cx: &mut Context<Self>,
20192    ) {
20193        let multibuffer = self.buffer.read(cx);
20194
20195        let Some(buffer) = multibuffer.as_singleton() else {
20196            return;
20197        };
20198
20199        let Some(workspace) = self.workspace() else {
20200            return;
20201        };
20202
20203        let title = multibuffer.title(cx).to_string();
20204
20205        let locations = self
20206            .selections
20207            .all_anchors(cx)
20208            .iter()
20209            .map(|selection| {
20210                (
20211                    buffer.clone(),
20212                    (selection.start.text_anchor..selection.end.text_anchor)
20213                        .to_point(buffer.read(cx)),
20214                )
20215            })
20216            .into_group_map();
20217
20218        cx.spawn_in(window, async move |_, cx| {
20219            workspace.update_in(cx, |workspace, window, cx| {
20220                Self::open_locations_in_multibuffer(
20221                    workspace,
20222                    locations,
20223                    format!("Selections for '{title}'"),
20224                    false,
20225                    MultibufferSelectionMode::All,
20226                    window,
20227                    cx,
20228                );
20229            })
20230        })
20231        .detach();
20232    }
20233
20234    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20235    /// last highlight added will be used.
20236    ///
20237    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20238    pub fn highlight_rows<T: 'static>(
20239        &mut self,
20240        range: Range<Anchor>,
20241        color: Hsla,
20242        options: RowHighlightOptions,
20243        cx: &mut Context<Self>,
20244    ) {
20245        let snapshot = self.buffer().read(cx).snapshot(cx);
20246        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20247        let ix = row_highlights.binary_search_by(|highlight| {
20248            Ordering::Equal
20249                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20250                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20251        });
20252
20253        if let Err(mut ix) = ix {
20254            let index = post_inc(&mut self.highlight_order);
20255
20256            // If this range intersects with the preceding highlight, then merge it with
20257            // the preceding highlight. Otherwise insert a new highlight.
20258            let mut merged = false;
20259            if ix > 0 {
20260                let prev_highlight = &mut row_highlights[ix - 1];
20261                if prev_highlight
20262                    .range
20263                    .end
20264                    .cmp(&range.start, &snapshot)
20265                    .is_ge()
20266                {
20267                    ix -= 1;
20268                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20269                        prev_highlight.range.end = range.end;
20270                    }
20271                    merged = true;
20272                    prev_highlight.index = index;
20273                    prev_highlight.color = color;
20274                    prev_highlight.options = options;
20275                }
20276            }
20277
20278            if !merged {
20279                row_highlights.insert(
20280                    ix,
20281                    RowHighlight {
20282                        range,
20283                        index,
20284                        color,
20285                        options,
20286                        type_id: TypeId::of::<T>(),
20287                    },
20288                );
20289            }
20290
20291            // If any of the following highlights intersect with this one, merge them.
20292            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20293                let highlight = &row_highlights[ix];
20294                if next_highlight
20295                    .range
20296                    .start
20297                    .cmp(&highlight.range.end, &snapshot)
20298                    .is_le()
20299                {
20300                    if next_highlight
20301                        .range
20302                        .end
20303                        .cmp(&highlight.range.end, &snapshot)
20304                        .is_gt()
20305                    {
20306                        row_highlights[ix].range.end = next_highlight.range.end;
20307                    }
20308                    row_highlights.remove(ix + 1);
20309                } else {
20310                    break;
20311                }
20312            }
20313        }
20314    }
20315
20316    /// Remove any highlighted row ranges of the given type that intersect the
20317    /// given ranges.
20318    pub fn remove_highlighted_rows<T: 'static>(
20319        &mut self,
20320        ranges_to_remove: Vec<Range<Anchor>>,
20321        cx: &mut Context<Self>,
20322    ) {
20323        let snapshot = self.buffer().read(cx).snapshot(cx);
20324        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20325        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20326        row_highlights.retain(|highlight| {
20327            while let Some(range_to_remove) = ranges_to_remove.peek() {
20328                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20329                    Ordering::Less | Ordering::Equal => {
20330                        ranges_to_remove.next();
20331                    }
20332                    Ordering::Greater => {
20333                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20334                            Ordering::Less | Ordering::Equal => {
20335                                return false;
20336                            }
20337                            Ordering::Greater => break,
20338                        }
20339                    }
20340                }
20341            }
20342
20343            true
20344        })
20345    }
20346
20347    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20348    pub fn clear_row_highlights<T: 'static>(&mut self) {
20349        self.highlighted_rows.remove(&TypeId::of::<T>());
20350    }
20351
20352    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20353    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20354        self.highlighted_rows
20355            .get(&TypeId::of::<T>())
20356            .map_or(&[] as &[_], |vec| vec.as_slice())
20357            .iter()
20358            .map(|highlight| (highlight.range.clone(), highlight.color))
20359    }
20360
20361    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20362    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20363    /// Allows to ignore certain kinds of highlights.
20364    pub fn highlighted_display_rows(
20365        &self,
20366        window: &mut Window,
20367        cx: &mut App,
20368    ) -> BTreeMap<DisplayRow, LineHighlight> {
20369        let snapshot = self.snapshot(window, cx);
20370        let mut used_highlight_orders = HashMap::default();
20371        self.highlighted_rows
20372            .iter()
20373            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20374            .fold(
20375                BTreeMap::<DisplayRow, LineHighlight>::new(),
20376                |mut unique_rows, highlight| {
20377                    let start = highlight.range.start.to_display_point(&snapshot);
20378                    let end = highlight.range.end.to_display_point(&snapshot);
20379                    let start_row = start.row().0;
20380                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20381                        && end.column() == 0
20382                    {
20383                        end.row().0.saturating_sub(1)
20384                    } else {
20385                        end.row().0
20386                    };
20387                    for row in start_row..=end_row {
20388                        let used_index =
20389                            used_highlight_orders.entry(row).or_insert(highlight.index);
20390                        if highlight.index >= *used_index {
20391                            *used_index = highlight.index;
20392                            unique_rows.insert(
20393                                DisplayRow(row),
20394                                LineHighlight {
20395                                    include_gutter: highlight.options.include_gutter,
20396                                    border: None,
20397                                    background: highlight.color.into(),
20398                                    type_id: Some(highlight.type_id),
20399                                },
20400                            );
20401                        }
20402                    }
20403                    unique_rows
20404                },
20405            )
20406    }
20407
20408    pub fn highlighted_display_row_for_autoscroll(
20409        &self,
20410        snapshot: &DisplaySnapshot,
20411    ) -> Option<DisplayRow> {
20412        self.highlighted_rows
20413            .values()
20414            .flat_map(|highlighted_rows| highlighted_rows.iter())
20415            .filter_map(|highlight| {
20416                if highlight.options.autoscroll {
20417                    Some(highlight.range.start.to_display_point(snapshot).row())
20418                } else {
20419                    None
20420                }
20421            })
20422            .min()
20423    }
20424
20425    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20426        self.highlight_background::<SearchWithinRange>(
20427            ranges,
20428            |colors| colors.colors().editor_document_highlight_read_background,
20429            cx,
20430        )
20431    }
20432
20433    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20434        self.breadcrumb_header = Some(new_header);
20435    }
20436
20437    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20438        self.clear_background_highlights::<SearchWithinRange>(cx);
20439    }
20440
20441    pub fn highlight_background<T: 'static>(
20442        &mut self,
20443        ranges: &[Range<Anchor>],
20444        color_fetcher: fn(&Theme) -> Hsla,
20445        cx: &mut Context<Self>,
20446    ) {
20447        self.background_highlights.insert(
20448            HighlightKey::Type(TypeId::of::<T>()),
20449            (color_fetcher, Arc::from(ranges)),
20450        );
20451        self.scrollbar_marker_state.dirty = true;
20452        cx.notify();
20453    }
20454
20455    pub fn highlight_background_key<T: 'static>(
20456        &mut self,
20457        key: usize,
20458        ranges: &[Range<Anchor>],
20459        color_fetcher: fn(&Theme) -> Hsla,
20460        cx: &mut Context<Self>,
20461    ) {
20462        self.background_highlights.insert(
20463            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20464            (color_fetcher, Arc::from(ranges)),
20465        );
20466        self.scrollbar_marker_state.dirty = true;
20467        cx.notify();
20468    }
20469
20470    pub fn clear_background_highlights<T: 'static>(
20471        &mut self,
20472        cx: &mut Context<Self>,
20473    ) -> Option<BackgroundHighlight> {
20474        let text_highlights = self
20475            .background_highlights
20476            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20477        if !text_highlights.1.is_empty() {
20478            self.scrollbar_marker_state.dirty = true;
20479            cx.notify();
20480        }
20481        Some(text_highlights)
20482    }
20483
20484    pub fn highlight_gutter<T: 'static>(
20485        &mut self,
20486        ranges: impl Into<Vec<Range<Anchor>>>,
20487        color_fetcher: fn(&App) -> Hsla,
20488        cx: &mut Context<Self>,
20489    ) {
20490        self.gutter_highlights
20491            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20492        cx.notify();
20493    }
20494
20495    pub fn clear_gutter_highlights<T: 'static>(
20496        &mut self,
20497        cx: &mut Context<Self>,
20498    ) -> Option<GutterHighlight> {
20499        cx.notify();
20500        self.gutter_highlights.remove(&TypeId::of::<T>())
20501    }
20502
20503    pub fn insert_gutter_highlight<T: 'static>(
20504        &mut self,
20505        range: Range<Anchor>,
20506        color_fetcher: fn(&App) -> Hsla,
20507        cx: &mut Context<Self>,
20508    ) {
20509        let snapshot = self.buffer().read(cx).snapshot(cx);
20510        let mut highlights = self
20511            .gutter_highlights
20512            .remove(&TypeId::of::<T>())
20513            .map(|(_, highlights)| highlights)
20514            .unwrap_or_default();
20515        let ix = highlights.binary_search_by(|highlight| {
20516            Ordering::Equal
20517                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20518                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20519        });
20520        if let Err(ix) = ix {
20521            highlights.insert(ix, range);
20522        }
20523        self.gutter_highlights
20524            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20525    }
20526
20527    pub fn remove_gutter_highlights<T: 'static>(
20528        &mut self,
20529        ranges_to_remove: Vec<Range<Anchor>>,
20530        cx: &mut Context<Self>,
20531    ) {
20532        let snapshot = self.buffer().read(cx).snapshot(cx);
20533        let Some((color_fetcher, mut gutter_highlights)) =
20534            self.gutter_highlights.remove(&TypeId::of::<T>())
20535        else {
20536            return;
20537        };
20538        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20539        gutter_highlights.retain(|highlight| {
20540            while let Some(range_to_remove) = ranges_to_remove.peek() {
20541                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20542                    Ordering::Less | Ordering::Equal => {
20543                        ranges_to_remove.next();
20544                    }
20545                    Ordering::Greater => {
20546                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20547                            Ordering::Less | Ordering::Equal => {
20548                                return false;
20549                            }
20550                            Ordering::Greater => break,
20551                        }
20552                    }
20553                }
20554            }
20555
20556            true
20557        });
20558        self.gutter_highlights
20559            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20560    }
20561
20562    #[cfg(feature = "test-support")]
20563    pub fn all_text_highlights(
20564        &self,
20565        window: &mut Window,
20566        cx: &mut Context<Self>,
20567    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20568        let snapshot = self.snapshot(window, cx);
20569        self.display_map.update(cx, |display_map, _| {
20570            display_map
20571                .all_text_highlights()
20572                .map(|highlight| {
20573                    let (style, ranges) = highlight.as_ref();
20574                    (
20575                        *style,
20576                        ranges
20577                            .iter()
20578                            .map(|range| range.clone().to_display_points(&snapshot))
20579                            .collect(),
20580                    )
20581                })
20582                .collect()
20583        })
20584    }
20585
20586    #[cfg(feature = "test-support")]
20587    pub fn all_text_background_highlights(
20588        &self,
20589        window: &mut Window,
20590        cx: &mut Context<Self>,
20591    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20592        let snapshot = self.snapshot(window, cx);
20593        let buffer = &snapshot.buffer_snapshot();
20594        let start = buffer.anchor_before(0);
20595        let end = buffer.anchor_after(buffer.len());
20596        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20597    }
20598
20599    #[cfg(any(test, feature = "test-support"))]
20600    pub fn sorted_background_highlights_in_range(
20601        &self,
20602        search_range: Range<Anchor>,
20603        display_snapshot: &DisplaySnapshot,
20604        theme: &Theme,
20605    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20606        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20607        res.sort_by(|a, b| {
20608            a.0.start
20609                .cmp(&b.0.start)
20610                .then_with(|| a.0.end.cmp(&b.0.end))
20611                .then_with(|| a.1.cmp(&b.1))
20612        });
20613        res
20614    }
20615
20616    #[cfg(feature = "test-support")]
20617    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20618        let snapshot = self.buffer().read(cx).snapshot(cx);
20619
20620        let highlights = self
20621            .background_highlights
20622            .get(&HighlightKey::Type(TypeId::of::<
20623                items::BufferSearchHighlights,
20624            >()));
20625
20626        if let Some((_color, ranges)) = highlights {
20627            ranges
20628                .iter()
20629                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20630                .collect_vec()
20631        } else {
20632            vec![]
20633        }
20634    }
20635
20636    fn document_highlights_for_position<'a>(
20637        &'a self,
20638        position: Anchor,
20639        buffer: &'a MultiBufferSnapshot,
20640    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20641        let read_highlights = self
20642            .background_highlights
20643            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20644            .map(|h| &h.1);
20645        let write_highlights = self
20646            .background_highlights
20647            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20648            .map(|h| &h.1);
20649        let left_position = position.bias_left(buffer);
20650        let right_position = position.bias_right(buffer);
20651        read_highlights
20652            .into_iter()
20653            .chain(write_highlights)
20654            .flat_map(move |ranges| {
20655                let start_ix = match ranges.binary_search_by(|probe| {
20656                    let cmp = probe.end.cmp(&left_position, buffer);
20657                    if cmp.is_ge() {
20658                        Ordering::Greater
20659                    } else {
20660                        Ordering::Less
20661                    }
20662                }) {
20663                    Ok(i) | Err(i) => i,
20664                };
20665
20666                ranges[start_ix..]
20667                    .iter()
20668                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20669            })
20670    }
20671
20672    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20673        self.background_highlights
20674            .get(&HighlightKey::Type(TypeId::of::<T>()))
20675            .is_some_and(|(_, highlights)| !highlights.is_empty())
20676    }
20677
20678    /// Returns all background highlights for a given range.
20679    ///
20680    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20681    pub fn background_highlights_in_range(
20682        &self,
20683        search_range: Range<Anchor>,
20684        display_snapshot: &DisplaySnapshot,
20685        theme: &Theme,
20686    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20687        let mut results = Vec::new();
20688        for (color_fetcher, ranges) in self.background_highlights.values() {
20689            let color = color_fetcher(theme);
20690            let start_ix = match ranges.binary_search_by(|probe| {
20691                let cmp = probe
20692                    .end
20693                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20694                if cmp.is_gt() {
20695                    Ordering::Greater
20696                } else {
20697                    Ordering::Less
20698                }
20699            }) {
20700                Ok(i) | Err(i) => i,
20701            };
20702            for range in &ranges[start_ix..] {
20703                if range
20704                    .start
20705                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20706                    .is_ge()
20707                {
20708                    break;
20709                }
20710
20711                let start = range.start.to_display_point(display_snapshot);
20712                let end = range.end.to_display_point(display_snapshot);
20713                results.push((start..end, color))
20714            }
20715        }
20716        results
20717    }
20718
20719    pub fn gutter_highlights_in_range(
20720        &self,
20721        search_range: Range<Anchor>,
20722        display_snapshot: &DisplaySnapshot,
20723        cx: &App,
20724    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20725        let mut results = Vec::new();
20726        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20727            let color = color_fetcher(cx);
20728            let start_ix = match ranges.binary_search_by(|probe| {
20729                let cmp = probe
20730                    .end
20731                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20732                if cmp.is_gt() {
20733                    Ordering::Greater
20734                } else {
20735                    Ordering::Less
20736                }
20737            }) {
20738                Ok(i) | Err(i) => i,
20739            };
20740            for range in &ranges[start_ix..] {
20741                if range
20742                    .start
20743                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20744                    .is_ge()
20745                {
20746                    break;
20747                }
20748
20749                let start = range.start.to_display_point(display_snapshot);
20750                let end = range.end.to_display_point(display_snapshot);
20751                results.push((start..end, color))
20752            }
20753        }
20754        results
20755    }
20756
20757    /// Get the text ranges corresponding to the redaction query
20758    pub fn redacted_ranges(
20759        &self,
20760        search_range: Range<Anchor>,
20761        display_snapshot: &DisplaySnapshot,
20762        cx: &App,
20763    ) -> Vec<Range<DisplayPoint>> {
20764        display_snapshot
20765            .buffer_snapshot()
20766            .redacted_ranges(search_range, |file| {
20767                if let Some(file) = file {
20768                    file.is_private()
20769                        && EditorSettings::get(
20770                            Some(SettingsLocation {
20771                                worktree_id: file.worktree_id(cx),
20772                                path: file.path().as_ref(),
20773                            }),
20774                            cx,
20775                        )
20776                        .redact_private_values
20777                } else {
20778                    false
20779                }
20780            })
20781            .map(|range| {
20782                range.start.to_display_point(display_snapshot)
20783                    ..range.end.to_display_point(display_snapshot)
20784            })
20785            .collect()
20786    }
20787
20788    pub fn highlight_text_key<T: 'static>(
20789        &mut self,
20790        key: usize,
20791        ranges: Vec<Range<Anchor>>,
20792        style: HighlightStyle,
20793        cx: &mut Context<Self>,
20794    ) {
20795        self.display_map.update(cx, |map, _| {
20796            map.highlight_text(
20797                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20798                ranges,
20799                style,
20800            );
20801        });
20802        cx.notify();
20803    }
20804
20805    pub fn highlight_text<T: 'static>(
20806        &mut self,
20807        ranges: Vec<Range<Anchor>>,
20808        style: HighlightStyle,
20809        cx: &mut Context<Self>,
20810    ) {
20811        self.display_map.update(cx, |map, _| {
20812            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20813        });
20814        cx.notify();
20815    }
20816
20817    pub fn text_highlights<'a, T: 'static>(
20818        &'a self,
20819        cx: &'a App,
20820    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20821        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20822    }
20823
20824    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20825        let cleared = self
20826            .display_map
20827            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20828        if cleared {
20829            cx.notify();
20830        }
20831    }
20832
20833    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20834        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20835            && self.focus_handle.is_focused(window)
20836    }
20837
20838    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20839        self.show_cursor_when_unfocused = is_enabled;
20840        cx.notify();
20841    }
20842
20843    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20844        cx.notify();
20845    }
20846
20847    fn on_debug_session_event(
20848        &mut self,
20849        _session: Entity<Session>,
20850        event: &SessionEvent,
20851        cx: &mut Context<Self>,
20852    ) {
20853        if let SessionEvent::InvalidateInlineValue = event {
20854            self.refresh_inline_values(cx);
20855        }
20856    }
20857
20858    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20859        let Some(project) = self.project.clone() else {
20860            return;
20861        };
20862
20863        if !self.inline_value_cache.enabled {
20864            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20865            self.splice_inlays(&inlays, Vec::new(), cx);
20866            return;
20867        }
20868
20869        let current_execution_position = self
20870            .highlighted_rows
20871            .get(&TypeId::of::<ActiveDebugLine>())
20872            .and_then(|lines| lines.last().map(|line| line.range.end));
20873
20874        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20875            let inline_values = editor
20876                .update(cx, |editor, cx| {
20877                    let Some(current_execution_position) = current_execution_position else {
20878                        return Some(Task::ready(Ok(Vec::new())));
20879                    };
20880
20881                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20882                        let snapshot = buffer.snapshot(cx);
20883
20884                        let excerpt = snapshot.excerpt_containing(
20885                            current_execution_position..current_execution_position,
20886                        )?;
20887
20888                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20889                    })?;
20890
20891                    let range =
20892                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20893
20894                    project.inline_values(buffer, range, cx)
20895                })
20896                .ok()
20897                .flatten()?
20898                .await
20899                .context("refreshing debugger inlays")
20900                .log_err()?;
20901
20902            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20903
20904            for (buffer_id, inline_value) in inline_values
20905                .into_iter()
20906                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20907            {
20908                buffer_inline_values
20909                    .entry(buffer_id)
20910                    .or_default()
20911                    .push(inline_value);
20912            }
20913
20914            editor
20915                .update(cx, |editor, cx| {
20916                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20917                    let mut new_inlays = Vec::default();
20918
20919                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20920                        let buffer_id = buffer_snapshot.remote_id();
20921                        buffer_inline_values
20922                            .get(&buffer_id)
20923                            .into_iter()
20924                            .flatten()
20925                            .for_each(|hint| {
20926                                let inlay = Inlay::debugger(
20927                                    post_inc(&mut editor.next_inlay_id),
20928                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20929                                    hint.text(),
20930                                );
20931                                if !inlay.text().chars().contains(&'\n') {
20932                                    new_inlays.push(inlay);
20933                                }
20934                            });
20935                    }
20936
20937                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20938                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20939
20940                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20941                })
20942                .ok()?;
20943            Some(())
20944        });
20945    }
20946
20947    fn on_buffer_event(
20948        &mut self,
20949        multibuffer: &Entity<MultiBuffer>,
20950        event: &multi_buffer::Event,
20951        window: &mut Window,
20952        cx: &mut Context<Self>,
20953    ) {
20954        match event {
20955            multi_buffer::Event::Edited { edited_buffer } => {
20956                self.scrollbar_marker_state.dirty = true;
20957                self.active_indent_guides_state.dirty = true;
20958                self.refresh_active_diagnostics(cx);
20959                self.refresh_code_actions(window, cx);
20960                self.refresh_selected_text_highlights(true, window, cx);
20961                self.refresh_single_line_folds(window, cx);
20962                self.refresh_matching_bracket_highlights(window, cx);
20963                if self.has_active_edit_prediction() {
20964                    self.update_visible_edit_prediction(window, cx);
20965                }
20966
20967                if let Some(buffer) = edited_buffer {
20968                    if buffer.read(cx).file().is_none() {
20969                        cx.emit(EditorEvent::TitleChanged);
20970                    }
20971
20972                    if self.project.is_some() {
20973                        let buffer_id = buffer.read(cx).remote_id();
20974                        self.register_buffer(buffer_id, cx);
20975                        self.update_lsp_data(Some(buffer_id), window, cx);
20976                        self.refresh_inlay_hints(
20977                            InlayHintRefreshReason::BufferEdited(buffer_id),
20978                            cx,
20979                        );
20980                    }
20981                }
20982
20983                cx.emit(EditorEvent::BufferEdited);
20984                cx.emit(SearchEvent::MatchesInvalidated);
20985
20986                let Some(project) = &self.project else { return };
20987                let (telemetry, is_via_ssh) = {
20988                    let project = project.read(cx);
20989                    let telemetry = project.client().telemetry().clone();
20990                    let is_via_ssh = project.is_via_remote_server();
20991                    (telemetry, is_via_ssh)
20992                };
20993                telemetry.log_edit_event("editor", is_via_ssh);
20994            }
20995            multi_buffer::Event::ExcerptsAdded {
20996                buffer,
20997                predecessor,
20998                excerpts,
20999            } => {
21000                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21001                let buffer_id = buffer.read(cx).remote_id();
21002                if self.buffer.read(cx).diff_for(buffer_id).is_none()
21003                    && let Some(project) = &self.project
21004                {
21005                    update_uncommitted_diff_for_buffer(
21006                        cx.entity(),
21007                        project,
21008                        [buffer.clone()],
21009                        self.buffer.clone(),
21010                        cx,
21011                    )
21012                    .detach();
21013                }
21014                self.update_lsp_data(Some(buffer_id), window, cx);
21015                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21016                cx.emit(EditorEvent::ExcerptsAdded {
21017                    buffer: buffer.clone(),
21018                    predecessor: *predecessor,
21019                    excerpts: excerpts.clone(),
21020                });
21021            }
21022            multi_buffer::Event::ExcerptsRemoved {
21023                ids,
21024                removed_buffer_ids,
21025            } => {
21026                if let Some(inlay_hints) = &mut self.inlay_hints {
21027                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
21028                }
21029                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
21030                for buffer_id in removed_buffer_ids {
21031                    self.registered_buffers.remove(buffer_id);
21032                }
21033                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21034                cx.emit(EditorEvent::ExcerptsRemoved {
21035                    ids: ids.clone(),
21036                    removed_buffer_ids: removed_buffer_ids.clone(),
21037                });
21038            }
21039            multi_buffer::Event::ExcerptsEdited {
21040                excerpt_ids,
21041                buffer_ids,
21042            } => {
21043                self.display_map.update(cx, |map, cx| {
21044                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
21045                });
21046                cx.emit(EditorEvent::ExcerptsEdited {
21047                    ids: excerpt_ids.clone(),
21048                });
21049            }
21050            multi_buffer::Event::ExcerptsExpanded { ids } => {
21051                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21052                self.refresh_document_highlights(cx);
21053                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
21054            }
21055            multi_buffer::Event::Reparsed(buffer_id) => {
21056                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21057                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21058
21059                cx.emit(EditorEvent::Reparsed(*buffer_id));
21060            }
21061            multi_buffer::Event::DiffHunksToggled => {
21062                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21063            }
21064            multi_buffer::Event::LanguageChanged(buffer_id) => {
21065                self.registered_buffers.remove(&buffer_id);
21066                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21067                cx.emit(EditorEvent::Reparsed(*buffer_id));
21068                cx.notify();
21069            }
21070            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
21071            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21072            multi_buffer::Event::FileHandleChanged
21073            | multi_buffer::Event::Reloaded
21074            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21075            multi_buffer::Event::DiagnosticsUpdated => {
21076                self.update_diagnostics_state(window, cx);
21077            }
21078            _ => {}
21079        };
21080    }
21081
21082    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21083        if !self.diagnostics_enabled() {
21084            return;
21085        }
21086        self.refresh_active_diagnostics(cx);
21087        self.refresh_inline_diagnostics(true, window, cx);
21088        self.scrollbar_marker_state.dirty = true;
21089        cx.notify();
21090    }
21091
21092    pub fn start_temporary_diff_override(&mut self) {
21093        self.load_diff_task.take();
21094        self.temporary_diff_override = true;
21095    }
21096
21097    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21098        self.temporary_diff_override = false;
21099        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21100        self.buffer.update(cx, |buffer, cx| {
21101            buffer.set_all_diff_hunks_collapsed(cx);
21102        });
21103
21104        if let Some(project) = self.project.clone() {
21105            self.load_diff_task = Some(
21106                update_uncommitted_diff_for_buffer(
21107                    cx.entity(),
21108                    &project,
21109                    self.buffer.read(cx).all_buffers(),
21110                    self.buffer.clone(),
21111                    cx,
21112                )
21113                .shared(),
21114            );
21115        }
21116    }
21117
21118    fn on_display_map_changed(
21119        &mut self,
21120        _: Entity<DisplayMap>,
21121        _: &mut Window,
21122        cx: &mut Context<Self>,
21123    ) {
21124        cx.notify();
21125    }
21126
21127    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21128        if self.diagnostics_enabled() {
21129            let new_severity = EditorSettings::get_global(cx)
21130                .diagnostics_max_severity
21131                .unwrap_or(DiagnosticSeverity::Hint);
21132            self.set_max_diagnostics_severity(new_severity, cx);
21133        }
21134        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21135        self.update_edit_prediction_settings(cx);
21136        self.refresh_edit_prediction(true, false, window, cx);
21137        self.refresh_inline_values(cx);
21138        self.refresh_inlay_hints(
21139            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21140                self.selections.newest_anchor().head(),
21141                &self.buffer.read(cx).snapshot(cx),
21142                cx,
21143            )),
21144            cx,
21145        );
21146
21147        let old_cursor_shape = self.cursor_shape;
21148        let old_show_breadcrumbs = self.show_breadcrumbs;
21149
21150        {
21151            let editor_settings = EditorSettings::get_global(cx);
21152            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21153            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21154            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21155            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21156        }
21157
21158        if old_cursor_shape != self.cursor_shape {
21159            cx.emit(EditorEvent::CursorShapeChanged);
21160        }
21161
21162        if old_show_breadcrumbs != self.show_breadcrumbs {
21163            cx.emit(EditorEvent::BreadcrumbsChanged);
21164        }
21165
21166        let project_settings = ProjectSettings::get_global(cx);
21167        self.serialize_dirty_buffers =
21168            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
21169
21170        if self.mode.is_full() {
21171            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21172            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21173            if self.show_inline_diagnostics != show_inline_diagnostics {
21174                self.show_inline_diagnostics = show_inline_diagnostics;
21175                self.refresh_inline_diagnostics(false, window, cx);
21176            }
21177
21178            if self.git_blame_inline_enabled != inline_blame_enabled {
21179                self.toggle_git_blame_inline_internal(false, window, cx);
21180            }
21181
21182            let minimap_settings = EditorSettings::get_global(cx).minimap;
21183            if self.minimap_visibility != MinimapVisibility::Disabled {
21184                if self.minimap_visibility.settings_visibility()
21185                    != minimap_settings.minimap_enabled()
21186                {
21187                    self.set_minimap_visibility(
21188                        MinimapVisibility::for_mode(self.mode(), cx),
21189                        window,
21190                        cx,
21191                    );
21192                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21193                    minimap_entity.update(cx, |minimap_editor, cx| {
21194                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21195                    })
21196                }
21197            }
21198        }
21199
21200        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21201            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21202        }) {
21203            if !inlay_splice.is_empty() {
21204                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21205            }
21206            self.refresh_colors_for_visible_range(None, window, cx);
21207        }
21208
21209        cx.notify();
21210    }
21211
21212    pub fn set_searchable(&mut self, searchable: bool) {
21213        self.searchable = searchable;
21214    }
21215
21216    pub fn searchable(&self) -> bool {
21217        self.searchable
21218    }
21219
21220    pub fn open_excerpts_in_split(
21221        &mut self,
21222        _: &OpenExcerptsSplit,
21223        window: &mut Window,
21224        cx: &mut Context<Self>,
21225    ) {
21226        self.open_excerpts_common(None, true, window, cx)
21227    }
21228
21229    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21230        self.open_excerpts_common(None, false, window, cx)
21231    }
21232
21233    fn open_excerpts_common(
21234        &mut self,
21235        jump_data: Option<JumpData>,
21236        split: bool,
21237        window: &mut Window,
21238        cx: &mut Context<Self>,
21239    ) {
21240        let Some(workspace) = self.workspace() else {
21241            cx.propagate();
21242            return;
21243        };
21244
21245        if self.buffer.read(cx).is_singleton() {
21246            cx.propagate();
21247            return;
21248        }
21249
21250        let mut new_selections_by_buffer = HashMap::default();
21251        match &jump_data {
21252            Some(JumpData::MultiBufferPoint {
21253                excerpt_id,
21254                position,
21255                anchor,
21256                line_offset_from_top,
21257            }) => {
21258                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21259                if let Some(buffer) = multi_buffer_snapshot
21260                    .buffer_id_for_excerpt(*excerpt_id)
21261                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21262                {
21263                    let buffer_snapshot = buffer.read(cx).snapshot();
21264                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21265                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21266                    } else {
21267                        buffer_snapshot.clip_point(*position, Bias::Left)
21268                    };
21269                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21270                    new_selections_by_buffer.insert(
21271                        buffer,
21272                        (
21273                            vec![jump_to_offset..jump_to_offset],
21274                            Some(*line_offset_from_top),
21275                        ),
21276                    );
21277                }
21278            }
21279            Some(JumpData::MultiBufferRow {
21280                row,
21281                line_offset_from_top,
21282            }) => {
21283                let point = MultiBufferPoint::new(row.0, 0);
21284                if let Some((buffer, buffer_point, _)) =
21285                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21286                {
21287                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21288                    new_selections_by_buffer
21289                        .entry(buffer)
21290                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21291                        .0
21292                        .push(buffer_offset..buffer_offset)
21293                }
21294            }
21295            None => {
21296                let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
21297                let multi_buffer = self.buffer.read(cx);
21298                for selection in selections {
21299                    for (snapshot, range, _, anchor) in multi_buffer
21300                        .snapshot(cx)
21301                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21302                    {
21303                        if let Some(anchor) = anchor {
21304                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21305                            else {
21306                                continue;
21307                            };
21308                            let offset = text::ToOffset::to_offset(
21309                                &anchor.text_anchor,
21310                                &buffer_handle.read(cx).snapshot(),
21311                            );
21312                            let range = offset..offset;
21313                            new_selections_by_buffer
21314                                .entry(buffer_handle)
21315                                .or_insert((Vec::new(), None))
21316                                .0
21317                                .push(range)
21318                        } else {
21319                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21320                            else {
21321                                continue;
21322                            };
21323                            new_selections_by_buffer
21324                                .entry(buffer_handle)
21325                                .or_insert((Vec::new(), None))
21326                                .0
21327                                .push(range)
21328                        }
21329                    }
21330                }
21331            }
21332        }
21333
21334        new_selections_by_buffer
21335            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21336
21337        if new_selections_by_buffer.is_empty() {
21338            return;
21339        }
21340
21341        // We defer the pane interaction because we ourselves are a workspace item
21342        // and activating a new item causes the pane to call a method on us reentrantly,
21343        // which panics if we're on the stack.
21344        window.defer(cx, move |window, cx| {
21345            workspace.update(cx, |workspace, cx| {
21346                let pane = if split {
21347                    workspace.adjacent_pane(window, cx)
21348                } else {
21349                    workspace.active_pane().clone()
21350                };
21351
21352                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21353                    let editor = buffer
21354                        .read(cx)
21355                        .file()
21356                        .is_none()
21357                        .then(|| {
21358                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21359                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21360                            // Instead, we try to activate the existing editor in the pane first.
21361                            let (editor, pane_item_index) =
21362                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21363                                    let editor = item.downcast::<Editor>()?;
21364                                    let singleton_buffer =
21365                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21366                                    if singleton_buffer == buffer {
21367                                        Some((editor, i))
21368                                    } else {
21369                                        None
21370                                    }
21371                                })?;
21372                            pane.update(cx, |pane, cx| {
21373                                pane.activate_item(pane_item_index, true, true, window, cx)
21374                            });
21375                            Some(editor)
21376                        })
21377                        .flatten()
21378                        .unwrap_or_else(|| {
21379                            workspace.open_project_item::<Self>(
21380                                pane.clone(),
21381                                buffer,
21382                                true,
21383                                true,
21384                                window,
21385                                cx,
21386                            )
21387                        });
21388
21389                    editor.update(cx, |editor, cx| {
21390                        let autoscroll = match scroll_offset {
21391                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21392                            None => Autoscroll::newest(),
21393                        };
21394                        let nav_history = editor.nav_history.take();
21395                        editor.change_selections(
21396                            SelectionEffects::scroll(autoscroll),
21397                            window,
21398                            cx,
21399                            |s| {
21400                                s.select_ranges(ranges);
21401                            },
21402                        );
21403                        editor.nav_history = nav_history;
21404                    });
21405                }
21406            })
21407        });
21408    }
21409
21410    // For now, don't allow opening excerpts in buffers that aren't backed by
21411    // regular project files.
21412    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21413        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21414    }
21415
21416    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21417        let snapshot = self.buffer.read(cx).read(cx);
21418        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21419        Some(
21420            ranges
21421                .iter()
21422                .map(move |range| {
21423                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21424                })
21425                .collect(),
21426        )
21427    }
21428
21429    fn selection_replacement_ranges(
21430        &self,
21431        range: Range<OffsetUtf16>,
21432        cx: &mut App,
21433    ) -> Vec<Range<OffsetUtf16>> {
21434        let selections = self
21435            .selections
21436            .all::<OffsetUtf16>(&self.display_snapshot(cx));
21437        let newest_selection = selections
21438            .iter()
21439            .max_by_key(|selection| selection.id)
21440            .unwrap();
21441        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21442        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21443        let snapshot = self.buffer.read(cx).read(cx);
21444        selections
21445            .into_iter()
21446            .map(|mut selection| {
21447                selection.start.0 =
21448                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21449                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21450                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21451                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21452            })
21453            .collect()
21454    }
21455
21456    fn report_editor_event(
21457        &self,
21458        reported_event: ReportEditorEvent,
21459        file_extension: Option<String>,
21460        cx: &App,
21461    ) {
21462        if cfg!(any(test, feature = "test-support")) {
21463            return;
21464        }
21465
21466        let Some(project) = &self.project else { return };
21467
21468        // If None, we are in a file without an extension
21469        let file = self
21470            .buffer
21471            .read(cx)
21472            .as_singleton()
21473            .and_then(|b| b.read(cx).file());
21474        let file_extension = file_extension.or(file
21475            .as_ref()
21476            .and_then(|file| Path::new(file.file_name(cx)).extension())
21477            .and_then(|e| e.to_str())
21478            .map(|a| a.to_string()));
21479
21480        let vim_mode = vim_flavor(cx).is_some();
21481
21482        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21483        let copilot_enabled = edit_predictions_provider
21484            == language::language_settings::EditPredictionProvider::Copilot;
21485        let copilot_enabled_for_language = self
21486            .buffer
21487            .read(cx)
21488            .language_settings(cx)
21489            .show_edit_predictions;
21490
21491        let project = project.read(cx);
21492        let event_type = reported_event.event_type();
21493
21494        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21495            telemetry::event!(
21496                event_type,
21497                type = if auto_saved {"autosave"} else {"manual"},
21498                file_extension,
21499                vim_mode,
21500                copilot_enabled,
21501                copilot_enabled_for_language,
21502                edit_predictions_provider,
21503                is_via_ssh = project.is_via_remote_server(),
21504            );
21505        } else {
21506            telemetry::event!(
21507                event_type,
21508                file_extension,
21509                vim_mode,
21510                copilot_enabled,
21511                copilot_enabled_for_language,
21512                edit_predictions_provider,
21513                is_via_ssh = project.is_via_remote_server(),
21514            );
21515        };
21516    }
21517
21518    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21519    /// with each line being an array of {text, highlight} objects.
21520    fn copy_highlight_json(
21521        &mut self,
21522        _: &CopyHighlightJson,
21523        window: &mut Window,
21524        cx: &mut Context<Self>,
21525    ) {
21526        #[derive(Serialize)]
21527        struct Chunk<'a> {
21528            text: String,
21529            highlight: Option<&'a str>,
21530        }
21531
21532        let snapshot = self.buffer.read(cx).snapshot(cx);
21533        let range = self
21534            .selected_text_range(false, window, cx)
21535            .and_then(|selection| {
21536                if selection.range.is_empty() {
21537                    None
21538                } else {
21539                    Some(
21540                        snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.start))
21541                            ..snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.end)),
21542                    )
21543                }
21544            })
21545            .unwrap_or_else(|| 0..snapshot.len());
21546
21547        let chunks = snapshot.chunks(range, true);
21548        let mut lines = Vec::new();
21549        let mut line: VecDeque<Chunk> = VecDeque::new();
21550
21551        let Some(style) = self.style.as_ref() else {
21552            return;
21553        };
21554
21555        for chunk in chunks {
21556            let highlight = chunk
21557                .syntax_highlight_id
21558                .and_then(|id| id.name(&style.syntax));
21559            let mut chunk_lines = chunk.text.split('\n').peekable();
21560            while let Some(text) = chunk_lines.next() {
21561                let mut merged_with_last_token = false;
21562                if let Some(last_token) = line.back_mut()
21563                    && last_token.highlight == highlight
21564                {
21565                    last_token.text.push_str(text);
21566                    merged_with_last_token = true;
21567                }
21568
21569                if !merged_with_last_token {
21570                    line.push_back(Chunk {
21571                        text: text.into(),
21572                        highlight,
21573                    });
21574                }
21575
21576                if chunk_lines.peek().is_some() {
21577                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21578                        line.pop_front();
21579                    }
21580                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21581                        line.pop_back();
21582                    }
21583
21584                    lines.push(mem::take(&mut line));
21585                }
21586            }
21587        }
21588
21589        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21590            return;
21591        };
21592        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21593    }
21594
21595    pub fn open_context_menu(
21596        &mut self,
21597        _: &OpenContextMenu,
21598        window: &mut Window,
21599        cx: &mut Context<Self>,
21600    ) {
21601        self.request_autoscroll(Autoscroll::newest(), cx);
21602        let position = self
21603            .selections
21604            .newest_display(&self.display_snapshot(cx))
21605            .start;
21606        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21607    }
21608
21609    pub fn replay_insert_event(
21610        &mut self,
21611        text: &str,
21612        relative_utf16_range: Option<Range<isize>>,
21613        window: &mut Window,
21614        cx: &mut Context<Self>,
21615    ) {
21616        if !self.input_enabled {
21617            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21618            return;
21619        }
21620        if let Some(relative_utf16_range) = relative_utf16_range {
21621            let selections = self
21622                .selections
21623                .all::<OffsetUtf16>(&self.display_snapshot(cx));
21624            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21625                let new_ranges = selections.into_iter().map(|range| {
21626                    let start = OffsetUtf16(
21627                        range
21628                            .head()
21629                            .0
21630                            .saturating_add_signed(relative_utf16_range.start),
21631                    );
21632                    let end = OffsetUtf16(
21633                        range
21634                            .head()
21635                            .0
21636                            .saturating_add_signed(relative_utf16_range.end),
21637                    );
21638                    start..end
21639                });
21640                s.select_ranges(new_ranges);
21641            });
21642        }
21643
21644        self.handle_input(text, window, cx);
21645    }
21646
21647    pub fn is_focused(&self, window: &Window) -> bool {
21648        self.focus_handle.is_focused(window)
21649    }
21650
21651    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21652        cx.emit(EditorEvent::Focused);
21653
21654        if let Some(descendant) = self
21655            .last_focused_descendant
21656            .take()
21657            .and_then(|descendant| descendant.upgrade())
21658        {
21659            window.focus(&descendant);
21660        } else {
21661            if let Some(blame) = self.blame.as_ref() {
21662                blame.update(cx, GitBlame::focus)
21663            }
21664
21665            self.blink_manager.update(cx, BlinkManager::enable);
21666            self.show_cursor_names(window, cx);
21667            self.buffer.update(cx, |buffer, cx| {
21668                buffer.finalize_last_transaction(cx);
21669                if self.leader_id.is_none() {
21670                    buffer.set_active_selections(
21671                        &self.selections.disjoint_anchors_arc(),
21672                        self.selections.line_mode(),
21673                        self.cursor_shape,
21674                        cx,
21675                    );
21676                }
21677            });
21678        }
21679    }
21680
21681    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21682        cx.emit(EditorEvent::FocusedIn)
21683    }
21684
21685    fn handle_focus_out(
21686        &mut self,
21687        event: FocusOutEvent,
21688        _window: &mut Window,
21689        cx: &mut Context<Self>,
21690    ) {
21691        if event.blurred != self.focus_handle {
21692            self.last_focused_descendant = Some(event.blurred);
21693        }
21694        self.selection_drag_state = SelectionDragState::None;
21695        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21696    }
21697
21698    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21699        self.blink_manager.update(cx, BlinkManager::disable);
21700        self.buffer
21701            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21702
21703        if let Some(blame) = self.blame.as_ref() {
21704            blame.update(cx, GitBlame::blur)
21705        }
21706        if !self.hover_state.focused(window, cx) {
21707            hide_hover(self, cx);
21708        }
21709        if !self
21710            .context_menu
21711            .borrow()
21712            .as_ref()
21713            .is_some_and(|context_menu| context_menu.focused(window, cx))
21714        {
21715            self.hide_context_menu(window, cx);
21716        }
21717        self.take_active_edit_prediction(cx);
21718        cx.emit(EditorEvent::Blurred);
21719        cx.notify();
21720    }
21721
21722    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21723        let mut pending: String = window
21724            .pending_input_keystrokes()
21725            .into_iter()
21726            .flatten()
21727            .filter_map(|keystroke| {
21728                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21729                    keystroke.key_char.clone()
21730                } else {
21731                    None
21732                }
21733            })
21734            .collect();
21735
21736        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21737            pending = "".to_string();
21738        }
21739
21740        let existing_pending = self
21741            .text_highlights::<PendingInput>(cx)
21742            .map(|(_, ranges)| ranges.to_vec());
21743        if existing_pending.is_none() && pending.is_empty() {
21744            return;
21745        }
21746        let transaction =
21747            self.transact(window, cx, |this, window, cx| {
21748                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
21749                let edits = selections
21750                    .iter()
21751                    .map(|selection| (selection.end..selection.end, pending.clone()));
21752                this.edit(edits, cx);
21753                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21754                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21755                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21756                    }));
21757                });
21758                if let Some(existing_ranges) = existing_pending {
21759                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21760                    this.edit(edits, cx);
21761                }
21762            });
21763
21764        let snapshot = self.snapshot(window, cx);
21765        let ranges = self
21766            .selections
21767            .all::<usize>(&snapshot.display_snapshot)
21768            .into_iter()
21769            .map(|selection| {
21770                snapshot.buffer_snapshot().anchor_after(selection.end)
21771                    ..snapshot
21772                        .buffer_snapshot()
21773                        .anchor_before(selection.end + pending.len())
21774            })
21775            .collect();
21776
21777        if pending.is_empty() {
21778            self.clear_highlights::<PendingInput>(cx);
21779        } else {
21780            self.highlight_text::<PendingInput>(
21781                ranges,
21782                HighlightStyle {
21783                    underline: Some(UnderlineStyle {
21784                        thickness: px(1.),
21785                        color: None,
21786                        wavy: false,
21787                    }),
21788                    ..Default::default()
21789                },
21790                cx,
21791            );
21792        }
21793
21794        self.ime_transaction = self.ime_transaction.or(transaction);
21795        if let Some(transaction) = self.ime_transaction {
21796            self.buffer.update(cx, |buffer, cx| {
21797                buffer.group_until_transaction(transaction, cx);
21798            });
21799        }
21800
21801        if self.text_highlights::<PendingInput>(cx).is_none() {
21802            self.ime_transaction.take();
21803        }
21804    }
21805
21806    pub fn register_action_renderer(
21807        &mut self,
21808        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21809    ) -> Subscription {
21810        let id = self.next_editor_action_id.post_inc();
21811        self.editor_actions
21812            .borrow_mut()
21813            .insert(id, Box::new(listener));
21814
21815        let editor_actions = self.editor_actions.clone();
21816        Subscription::new(move || {
21817            editor_actions.borrow_mut().remove(&id);
21818        })
21819    }
21820
21821    pub fn register_action<A: Action>(
21822        &mut self,
21823        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21824    ) -> Subscription {
21825        let id = self.next_editor_action_id.post_inc();
21826        let listener = Arc::new(listener);
21827        self.editor_actions.borrow_mut().insert(
21828            id,
21829            Box::new(move |_, window, _| {
21830                let listener = listener.clone();
21831                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21832                    let action = action.downcast_ref().unwrap();
21833                    if phase == DispatchPhase::Bubble {
21834                        listener(action, window, cx)
21835                    }
21836                })
21837            }),
21838        );
21839
21840        let editor_actions = self.editor_actions.clone();
21841        Subscription::new(move || {
21842            editor_actions.borrow_mut().remove(&id);
21843        })
21844    }
21845
21846    pub fn file_header_size(&self) -> u32 {
21847        FILE_HEADER_HEIGHT
21848    }
21849
21850    pub fn restore(
21851        &mut self,
21852        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21853        window: &mut Window,
21854        cx: &mut Context<Self>,
21855    ) {
21856        let workspace = self.workspace();
21857        let project = self.project();
21858        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21859            let mut tasks = Vec::new();
21860            for (buffer_id, changes) in revert_changes {
21861                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21862                    buffer.update(cx, |buffer, cx| {
21863                        buffer.edit(
21864                            changes
21865                                .into_iter()
21866                                .map(|(range, text)| (range, text.to_string())),
21867                            None,
21868                            cx,
21869                        );
21870                    });
21871
21872                    if let Some(project) =
21873                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21874                    {
21875                        project.update(cx, |project, cx| {
21876                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21877                        })
21878                    }
21879                }
21880            }
21881            tasks
21882        });
21883        cx.spawn_in(window, async move |_, cx| {
21884            for (buffer, task) in save_tasks {
21885                let result = task.await;
21886                if result.is_err() {
21887                    let Some(path) = buffer
21888                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21889                        .ok()
21890                    else {
21891                        continue;
21892                    };
21893                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21894                        let Some(task) = cx
21895                            .update_window_entity(workspace, |workspace, window, cx| {
21896                                workspace
21897                                    .open_path_preview(path, None, false, false, false, window, cx)
21898                            })
21899                            .ok()
21900                        else {
21901                            continue;
21902                        };
21903                        task.await.log_err();
21904                    }
21905                }
21906            }
21907        })
21908        .detach();
21909        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21910            selections.refresh()
21911        });
21912    }
21913
21914    pub fn to_pixel_point(
21915        &self,
21916        source: multi_buffer::Anchor,
21917        editor_snapshot: &EditorSnapshot,
21918        window: &mut Window,
21919    ) -> Option<gpui::Point<Pixels>> {
21920        let source_point = source.to_display_point(editor_snapshot);
21921        self.display_to_pixel_point(source_point, editor_snapshot, window)
21922    }
21923
21924    pub fn display_to_pixel_point(
21925        &self,
21926        source: DisplayPoint,
21927        editor_snapshot: &EditorSnapshot,
21928        window: &mut Window,
21929    ) -> Option<gpui::Point<Pixels>> {
21930        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21931        let text_layout_details = self.text_layout_details(window);
21932        let scroll_top = text_layout_details
21933            .scroll_anchor
21934            .scroll_position(editor_snapshot)
21935            .y;
21936
21937        if source.row().as_f64() < scroll_top.floor() {
21938            return None;
21939        }
21940        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21941        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
21942        Some(gpui::Point::new(source_x, source_y))
21943    }
21944
21945    pub fn has_visible_completions_menu(&self) -> bool {
21946        !self.edit_prediction_preview_is_active()
21947            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21948                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21949            })
21950    }
21951
21952    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21953        if self.mode.is_minimap() {
21954            return;
21955        }
21956        self.addons
21957            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21958    }
21959
21960    pub fn unregister_addon<T: Addon>(&mut self) {
21961        self.addons.remove(&std::any::TypeId::of::<T>());
21962    }
21963
21964    pub fn addon<T: Addon>(&self) -> Option<&T> {
21965        let type_id = std::any::TypeId::of::<T>();
21966        self.addons
21967            .get(&type_id)
21968            .and_then(|item| item.to_any().downcast_ref::<T>())
21969    }
21970
21971    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21972        let type_id = std::any::TypeId::of::<T>();
21973        self.addons
21974            .get_mut(&type_id)
21975            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21976    }
21977
21978    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21979        let text_layout_details = self.text_layout_details(window);
21980        let style = &text_layout_details.editor_style;
21981        let font_id = window.text_system().resolve_font(&style.text.font());
21982        let font_size = style.text.font_size.to_pixels(window.rem_size());
21983        let line_height = style.text.line_height_in_pixels(window.rem_size());
21984        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21985        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21986
21987        CharacterDimensions {
21988            em_width,
21989            em_advance,
21990            line_height,
21991        }
21992    }
21993
21994    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21995        self.load_diff_task.clone()
21996    }
21997
21998    fn read_metadata_from_db(
21999        &mut self,
22000        item_id: u64,
22001        workspace_id: WorkspaceId,
22002        window: &mut Window,
22003        cx: &mut Context<Editor>,
22004    ) {
22005        if self.buffer_kind(cx) == ItemBufferKind::Singleton
22006            && !self.mode.is_minimap()
22007            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
22008        {
22009            let buffer_snapshot = OnceCell::new();
22010
22011            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
22012                && !folds.is_empty()
22013            {
22014                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22015                self.fold_ranges(
22016                    folds
22017                        .into_iter()
22018                        .map(|(start, end)| {
22019                            snapshot.clip_offset(start, Bias::Left)
22020                                ..snapshot.clip_offset(end, Bias::Right)
22021                        })
22022                        .collect(),
22023                    false,
22024                    window,
22025                    cx,
22026                );
22027            }
22028
22029            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
22030                && !selections.is_empty()
22031            {
22032                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22033                // skip adding the initial selection to selection history
22034                self.selection_history.mode = SelectionHistoryMode::Skipping;
22035                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22036                    s.select_ranges(selections.into_iter().map(|(start, end)| {
22037                        snapshot.clip_offset(start, Bias::Left)
22038                            ..snapshot.clip_offset(end, Bias::Right)
22039                    }));
22040                });
22041                self.selection_history.mode = SelectionHistoryMode::Normal;
22042            };
22043        }
22044
22045        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22046    }
22047
22048    fn update_lsp_data(
22049        &mut self,
22050        for_buffer: Option<BufferId>,
22051        window: &mut Window,
22052        cx: &mut Context<'_, Self>,
22053    ) {
22054        self.pull_diagnostics(for_buffer, window, cx);
22055        self.refresh_colors_for_visible_range(for_buffer, window, cx);
22056    }
22057
22058    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
22059        if self.ignore_lsp_data() {
22060            return;
22061        }
22062        for (_, (visible_buffer, _, _)) in self.visible_excerpts(cx) {
22063            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
22064        }
22065    }
22066
22067    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
22068        if !self.registered_buffers.contains_key(&buffer_id)
22069            && let Some(project) = self.project.as_ref()
22070        {
22071            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
22072                project.update(cx, |project, cx| {
22073                    self.registered_buffers.insert(
22074                        buffer_id,
22075                        project.register_buffer_with_language_servers(&buffer, cx),
22076                    );
22077                });
22078            } else {
22079                self.registered_buffers.remove(&buffer_id);
22080            }
22081        }
22082    }
22083
22084    fn ignore_lsp_data(&self) -> bool {
22085        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
22086        // skip any LSP updates for it.
22087        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
22088    }
22089}
22090
22091fn edit_for_markdown_paste<'a>(
22092    buffer: &MultiBufferSnapshot,
22093    range: Range<usize>,
22094    to_insert: &'a str,
22095    url: Option<url::Url>,
22096) -> (Range<usize>, Cow<'a, str>) {
22097    if url.is_none() {
22098        return (range, Cow::Borrowed(to_insert));
22099    };
22100
22101    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22102
22103    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22104        Cow::Borrowed(to_insert)
22105    } else {
22106        Cow::Owned(format!("[{old_text}]({to_insert})"))
22107    };
22108    (range, new_text)
22109}
22110
22111#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
22112pub enum VimFlavor {
22113    Vim,
22114    Helix,
22115}
22116
22117pub fn vim_flavor(cx: &App) -> Option<VimFlavor> {
22118    if vim_mode_setting::HelixModeSetting::try_get(cx)
22119        .map(|helix_mode| helix_mode.0)
22120        .unwrap_or(false)
22121    {
22122        Some(VimFlavor::Helix)
22123    } else if vim_mode_setting::VimModeSetting::try_get(cx)
22124        .map(|vim_mode| vim_mode.0)
22125        .unwrap_or(false)
22126    {
22127        Some(VimFlavor::Vim)
22128    } else {
22129        None // neither vim nor helix mode
22130    }
22131}
22132
22133fn process_completion_for_edit(
22134    completion: &Completion,
22135    intent: CompletionIntent,
22136    buffer: &Entity<Buffer>,
22137    cursor_position: &text::Anchor,
22138    cx: &mut Context<Editor>,
22139) -> CompletionEdit {
22140    let buffer = buffer.read(cx);
22141    let buffer_snapshot = buffer.snapshot();
22142    let (snippet, new_text) = if completion.is_snippet() {
22143        let mut snippet_source = completion.new_text.clone();
22144        // Workaround for typescript language server issues so that methods don't expand within
22145        // strings and functions with type expressions. The previous point is used because the query
22146        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22147        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22148        let previous_point = if previous_point.column > 0 {
22149            cursor_position.to_previous_offset(&buffer_snapshot)
22150        } else {
22151            cursor_position.to_offset(&buffer_snapshot)
22152        };
22153        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22154            && scope.prefers_label_for_snippet_in_completion()
22155            && let Some(label) = completion.label()
22156            && matches!(
22157                completion.kind(),
22158                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22159            )
22160        {
22161            snippet_source = label;
22162        }
22163        match Snippet::parse(&snippet_source).log_err() {
22164            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22165            None => (None, completion.new_text.clone()),
22166        }
22167    } else {
22168        (None, completion.new_text.clone())
22169    };
22170
22171    let mut range_to_replace = {
22172        let replace_range = &completion.replace_range;
22173        if let CompletionSource::Lsp {
22174            insert_range: Some(insert_range),
22175            ..
22176        } = &completion.source
22177        {
22178            debug_assert_eq!(
22179                insert_range.start, replace_range.start,
22180                "insert_range and replace_range should start at the same position"
22181            );
22182            debug_assert!(
22183                insert_range
22184                    .start
22185                    .cmp(cursor_position, &buffer_snapshot)
22186                    .is_le(),
22187                "insert_range should start before or at cursor position"
22188            );
22189            debug_assert!(
22190                replace_range
22191                    .start
22192                    .cmp(cursor_position, &buffer_snapshot)
22193                    .is_le(),
22194                "replace_range should start before or at cursor position"
22195            );
22196
22197            let should_replace = match intent {
22198                CompletionIntent::CompleteWithInsert => false,
22199                CompletionIntent::CompleteWithReplace => true,
22200                CompletionIntent::Complete | CompletionIntent::Compose => {
22201                    let insert_mode =
22202                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22203                            .completions
22204                            .lsp_insert_mode;
22205                    match insert_mode {
22206                        LspInsertMode::Insert => false,
22207                        LspInsertMode::Replace => true,
22208                        LspInsertMode::ReplaceSubsequence => {
22209                            let mut text_to_replace = buffer.chars_for_range(
22210                                buffer.anchor_before(replace_range.start)
22211                                    ..buffer.anchor_after(replace_range.end),
22212                            );
22213                            let mut current_needle = text_to_replace.next();
22214                            for haystack_ch in completion.label.text.chars() {
22215                                if let Some(needle_ch) = current_needle
22216                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22217                                {
22218                                    current_needle = text_to_replace.next();
22219                                }
22220                            }
22221                            current_needle.is_none()
22222                        }
22223                        LspInsertMode::ReplaceSuffix => {
22224                            if replace_range
22225                                .end
22226                                .cmp(cursor_position, &buffer_snapshot)
22227                                .is_gt()
22228                            {
22229                                let range_after_cursor = *cursor_position..replace_range.end;
22230                                let text_after_cursor = buffer
22231                                    .text_for_range(
22232                                        buffer.anchor_before(range_after_cursor.start)
22233                                            ..buffer.anchor_after(range_after_cursor.end),
22234                                    )
22235                                    .collect::<String>()
22236                                    .to_ascii_lowercase();
22237                                completion
22238                                    .label
22239                                    .text
22240                                    .to_ascii_lowercase()
22241                                    .ends_with(&text_after_cursor)
22242                            } else {
22243                                true
22244                            }
22245                        }
22246                    }
22247                }
22248            };
22249
22250            if should_replace {
22251                replace_range.clone()
22252            } else {
22253                insert_range.clone()
22254            }
22255        } else {
22256            replace_range.clone()
22257        }
22258    };
22259
22260    if range_to_replace
22261        .end
22262        .cmp(cursor_position, &buffer_snapshot)
22263        .is_lt()
22264    {
22265        range_to_replace.end = *cursor_position;
22266    }
22267
22268    CompletionEdit {
22269        new_text,
22270        replace_range: range_to_replace.to_offset(buffer),
22271        snippet,
22272    }
22273}
22274
22275struct CompletionEdit {
22276    new_text: String,
22277    replace_range: Range<usize>,
22278    snippet: Option<Snippet>,
22279}
22280
22281fn insert_extra_newline_brackets(
22282    buffer: &MultiBufferSnapshot,
22283    range: Range<usize>,
22284    language: &language::LanguageScope,
22285) -> bool {
22286    let leading_whitespace_len = buffer
22287        .reversed_chars_at(range.start)
22288        .take_while(|c| c.is_whitespace() && *c != '\n')
22289        .map(|c| c.len_utf8())
22290        .sum::<usize>();
22291    let trailing_whitespace_len = buffer
22292        .chars_at(range.end)
22293        .take_while(|c| c.is_whitespace() && *c != '\n')
22294        .map(|c| c.len_utf8())
22295        .sum::<usize>();
22296    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22297
22298    language.brackets().any(|(pair, enabled)| {
22299        let pair_start = pair.start.trim_end();
22300        let pair_end = pair.end.trim_start();
22301
22302        enabled
22303            && pair.newline
22304            && buffer.contains_str_at(range.end, pair_end)
22305            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22306    })
22307}
22308
22309fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22310    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22311        [(buffer, range, _)] => (*buffer, range.clone()),
22312        _ => return false,
22313    };
22314    let pair = {
22315        let mut result: Option<BracketMatch> = None;
22316
22317        for pair in buffer
22318            .all_bracket_ranges(range.clone())
22319            .filter(move |pair| {
22320                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22321            })
22322        {
22323            let len = pair.close_range.end - pair.open_range.start;
22324
22325            if let Some(existing) = &result {
22326                let existing_len = existing.close_range.end - existing.open_range.start;
22327                if len > existing_len {
22328                    continue;
22329                }
22330            }
22331
22332            result = Some(pair);
22333        }
22334
22335        result
22336    };
22337    let Some(pair) = pair else {
22338        return false;
22339    };
22340    pair.newline_only
22341        && buffer
22342            .chars_for_range(pair.open_range.end..range.start)
22343            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22344            .all(|c| c.is_whitespace() && c != '\n')
22345}
22346
22347fn update_uncommitted_diff_for_buffer(
22348    editor: Entity<Editor>,
22349    project: &Entity<Project>,
22350    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22351    buffer: Entity<MultiBuffer>,
22352    cx: &mut App,
22353) -> Task<()> {
22354    let mut tasks = Vec::new();
22355    project.update(cx, |project, cx| {
22356        for buffer in buffers {
22357            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22358                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22359            }
22360        }
22361    });
22362    cx.spawn(async move |cx| {
22363        let diffs = future::join_all(tasks).await;
22364        if editor
22365            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22366            .unwrap_or(false)
22367        {
22368            return;
22369        }
22370
22371        buffer
22372            .update(cx, |buffer, cx| {
22373                for diff in diffs.into_iter().flatten() {
22374                    buffer.add_diff(diff, cx);
22375                }
22376            })
22377            .ok();
22378    })
22379}
22380
22381fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22382    let tab_size = tab_size.get() as usize;
22383    let mut width = offset;
22384
22385    for ch in text.chars() {
22386        width += if ch == '\t' {
22387            tab_size - (width % tab_size)
22388        } else {
22389            1
22390        };
22391    }
22392
22393    width - offset
22394}
22395
22396#[cfg(test)]
22397mod tests {
22398    use super::*;
22399
22400    #[test]
22401    fn test_string_size_with_expanded_tabs() {
22402        let nz = |val| NonZeroU32::new(val).unwrap();
22403        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22404        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22405        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22406        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22407        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22408        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22409        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22410        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22411    }
22412}
22413
22414/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22415struct WordBreakingTokenizer<'a> {
22416    input: &'a str,
22417}
22418
22419impl<'a> WordBreakingTokenizer<'a> {
22420    fn new(input: &'a str) -> Self {
22421        Self { input }
22422    }
22423}
22424
22425fn is_char_ideographic(ch: char) -> bool {
22426    use unicode_script::Script::*;
22427    use unicode_script::UnicodeScript;
22428    matches!(ch.script(), Han | Tangut | Yi)
22429}
22430
22431fn is_grapheme_ideographic(text: &str) -> bool {
22432    text.chars().any(is_char_ideographic)
22433}
22434
22435fn is_grapheme_whitespace(text: &str) -> bool {
22436    text.chars().any(|x| x.is_whitespace())
22437}
22438
22439fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22440    text.chars()
22441        .next()
22442        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22443}
22444
22445#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22446enum WordBreakToken<'a> {
22447    Word { token: &'a str, grapheme_len: usize },
22448    InlineWhitespace { token: &'a str, grapheme_len: usize },
22449    Newline,
22450}
22451
22452impl<'a> Iterator for WordBreakingTokenizer<'a> {
22453    /// Yields a span, the count of graphemes in the token, and whether it was
22454    /// whitespace. Note that it also breaks at word boundaries.
22455    type Item = WordBreakToken<'a>;
22456
22457    fn next(&mut self) -> Option<Self::Item> {
22458        use unicode_segmentation::UnicodeSegmentation;
22459        if self.input.is_empty() {
22460            return None;
22461        }
22462
22463        let mut iter = self.input.graphemes(true).peekable();
22464        let mut offset = 0;
22465        let mut grapheme_len = 0;
22466        if let Some(first_grapheme) = iter.next() {
22467            let is_newline = first_grapheme == "\n";
22468            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22469            offset += first_grapheme.len();
22470            grapheme_len += 1;
22471            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22472                if let Some(grapheme) = iter.peek().copied()
22473                    && should_stay_with_preceding_ideograph(grapheme)
22474                {
22475                    offset += grapheme.len();
22476                    grapheme_len += 1;
22477                }
22478            } else {
22479                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22480                let mut next_word_bound = words.peek().copied();
22481                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22482                    next_word_bound = words.next();
22483                }
22484                while let Some(grapheme) = iter.peek().copied() {
22485                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22486                        break;
22487                    };
22488                    if is_grapheme_whitespace(grapheme) != is_whitespace
22489                        || (grapheme == "\n") != is_newline
22490                    {
22491                        break;
22492                    };
22493                    offset += grapheme.len();
22494                    grapheme_len += 1;
22495                    iter.next();
22496                }
22497            }
22498            let token = &self.input[..offset];
22499            self.input = &self.input[offset..];
22500            if token == "\n" {
22501                Some(WordBreakToken::Newline)
22502            } else if is_whitespace {
22503                Some(WordBreakToken::InlineWhitespace {
22504                    token,
22505                    grapheme_len,
22506                })
22507            } else {
22508                Some(WordBreakToken::Word {
22509                    token,
22510                    grapheme_len,
22511                })
22512            }
22513        } else {
22514            None
22515        }
22516    }
22517}
22518
22519#[test]
22520fn test_word_breaking_tokenizer() {
22521    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22522        ("", &[]),
22523        ("  ", &[whitespace("  ", 2)]),
22524        ("Ʒ", &[word("Ʒ", 1)]),
22525        ("Ǽ", &[word("Ǽ", 1)]),
22526        ("", &[word("", 1)]),
22527        ("⋑⋑", &[word("⋑⋑", 2)]),
22528        (
22529            "原理,进而",
22530            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22531        ),
22532        (
22533            "hello world",
22534            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22535        ),
22536        (
22537            "hello, world",
22538            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22539        ),
22540        (
22541            "  hello world",
22542            &[
22543                whitespace("  ", 2),
22544                word("hello", 5),
22545                whitespace(" ", 1),
22546                word("world", 5),
22547            ],
22548        ),
22549        (
22550            "这是什么 \n 钢笔",
22551            &[
22552                word("", 1),
22553                word("", 1),
22554                word("", 1),
22555                word("", 1),
22556                whitespace(" ", 1),
22557                newline(),
22558                whitespace(" ", 1),
22559                word("", 1),
22560                word("", 1),
22561            ],
22562        ),
22563        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22564    ];
22565
22566    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22567        WordBreakToken::Word {
22568            token,
22569            grapheme_len,
22570        }
22571    }
22572
22573    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22574        WordBreakToken::InlineWhitespace {
22575            token,
22576            grapheme_len,
22577        }
22578    }
22579
22580    fn newline() -> WordBreakToken<'static> {
22581        WordBreakToken::Newline
22582    }
22583
22584    for (input, result) in tests {
22585        assert_eq!(
22586            WordBreakingTokenizer::new(input)
22587                .collect::<Vec<_>>()
22588                .as_slice(),
22589            *result,
22590        );
22591    }
22592}
22593
22594fn wrap_with_prefix(
22595    first_line_prefix: String,
22596    subsequent_lines_prefix: String,
22597    unwrapped_text: String,
22598    wrap_column: usize,
22599    tab_size: NonZeroU32,
22600    preserve_existing_whitespace: bool,
22601) -> String {
22602    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22603    let subsequent_lines_prefix_len =
22604        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22605    let mut wrapped_text = String::new();
22606    let mut current_line = first_line_prefix;
22607    let mut is_first_line = true;
22608
22609    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22610    let mut current_line_len = first_line_prefix_len;
22611    let mut in_whitespace = false;
22612    for token in tokenizer {
22613        let have_preceding_whitespace = in_whitespace;
22614        match token {
22615            WordBreakToken::Word {
22616                token,
22617                grapheme_len,
22618            } => {
22619                in_whitespace = false;
22620                let current_prefix_len = if is_first_line {
22621                    first_line_prefix_len
22622                } else {
22623                    subsequent_lines_prefix_len
22624                };
22625                if current_line_len + grapheme_len > wrap_column
22626                    && current_line_len != current_prefix_len
22627                {
22628                    wrapped_text.push_str(current_line.trim_end());
22629                    wrapped_text.push('\n');
22630                    is_first_line = false;
22631                    current_line = subsequent_lines_prefix.clone();
22632                    current_line_len = subsequent_lines_prefix_len;
22633                }
22634                current_line.push_str(token);
22635                current_line_len += grapheme_len;
22636            }
22637            WordBreakToken::InlineWhitespace {
22638                mut token,
22639                mut grapheme_len,
22640            } => {
22641                in_whitespace = true;
22642                if have_preceding_whitespace && !preserve_existing_whitespace {
22643                    continue;
22644                }
22645                if !preserve_existing_whitespace {
22646                    // Keep a single whitespace grapheme as-is
22647                    if let Some(first) =
22648                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
22649                    {
22650                        token = first;
22651                    } else {
22652                        token = " ";
22653                    }
22654                    grapheme_len = 1;
22655                }
22656                let current_prefix_len = if is_first_line {
22657                    first_line_prefix_len
22658                } else {
22659                    subsequent_lines_prefix_len
22660                };
22661                if current_line_len + grapheme_len > wrap_column {
22662                    wrapped_text.push_str(current_line.trim_end());
22663                    wrapped_text.push('\n');
22664                    is_first_line = false;
22665                    current_line = subsequent_lines_prefix.clone();
22666                    current_line_len = subsequent_lines_prefix_len;
22667                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22668                    current_line.push_str(token);
22669                    current_line_len += grapheme_len;
22670                }
22671            }
22672            WordBreakToken::Newline => {
22673                in_whitespace = true;
22674                let current_prefix_len = if is_first_line {
22675                    first_line_prefix_len
22676                } else {
22677                    subsequent_lines_prefix_len
22678                };
22679                if preserve_existing_whitespace {
22680                    wrapped_text.push_str(current_line.trim_end());
22681                    wrapped_text.push('\n');
22682                    is_first_line = false;
22683                    current_line = subsequent_lines_prefix.clone();
22684                    current_line_len = subsequent_lines_prefix_len;
22685                } else if have_preceding_whitespace {
22686                    continue;
22687                } else if current_line_len + 1 > wrap_column
22688                    && current_line_len != current_prefix_len
22689                {
22690                    wrapped_text.push_str(current_line.trim_end());
22691                    wrapped_text.push('\n');
22692                    is_first_line = false;
22693                    current_line = subsequent_lines_prefix.clone();
22694                    current_line_len = subsequent_lines_prefix_len;
22695                } else if current_line_len != current_prefix_len {
22696                    current_line.push(' ');
22697                    current_line_len += 1;
22698                }
22699            }
22700        }
22701    }
22702
22703    if !current_line.is_empty() {
22704        wrapped_text.push_str(&current_line);
22705    }
22706    wrapped_text
22707}
22708
22709#[test]
22710fn test_wrap_with_prefix() {
22711    assert_eq!(
22712        wrap_with_prefix(
22713            "# ".to_string(),
22714            "# ".to_string(),
22715            "abcdefg".to_string(),
22716            4,
22717            NonZeroU32::new(4).unwrap(),
22718            false,
22719        ),
22720        "# abcdefg"
22721    );
22722    assert_eq!(
22723        wrap_with_prefix(
22724            "".to_string(),
22725            "".to_string(),
22726            "\thello world".to_string(),
22727            8,
22728            NonZeroU32::new(4).unwrap(),
22729            false,
22730        ),
22731        "hello\nworld"
22732    );
22733    assert_eq!(
22734        wrap_with_prefix(
22735            "// ".to_string(),
22736            "// ".to_string(),
22737            "xx \nyy zz aa bb cc".to_string(),
22738            12,
22739            NonZeroU32::new(4).unwrap(),
22740            false,
22741        ),
22742        "// xx yy zz\n// aa bb cc"
22743    );
22744    assert_eq!(
22745        wrap_with_prefix(
22746            String::new(),
22747            String::new(),
22748            "这是什么 \n 钢笔".to_string(),
22749            3,
22750            NonZeroU32::new(4).unwrap(),
22751            false,
22752        ),
22753        "这是什\n么 钢\n"
22754    );
22755    assert_eq!(
22756        wrap_with_prefix(
22757            String::new(),
22758            String::new(),
22759            format!("foo{}bar", '\u{2009}'), // thin space
22760            80,
22761            NonZeroU32::new(4).unwrap(),
22762            false,
22763        ),
22764        format!("foo{}bar", '\u{2009}')
22765    );
22766}
22767
22768pub trait CollaborationHub {
22769    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22770    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22771    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22772}
22773
22774impl CollaborationHub for Entity<Project> {
22775    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22776        self.read(cx).collaborators()
22777    }
22778
22779    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22780        self.read(cx).user_store().read(cx).participant_indices()
22781    }
22782
22783    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22784        let this = self.read(cx);
22785        let user_ids = this.collaborators().values().map(|c| c.user_id);
22786        this.user_store().read(cx).participant_names(user_ids, cx)
22787    }
22788}
22789
22790pub trait SemanticsProvider {
22791    fn hover(
22792        &self,
22793        buffer: &Entity<Buffer>,
22794        position: text::Anchor,
22795        cx: &mut App,
22796    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22797
22798    fn inline_values(
22799        &self,
22800        buffer_handle: Entity<Buffer>,
22801        range: Range<text::Anchor>,
22802        cx: &mut App,
22803    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22804
22805    fn applicable_inlay_chunks(
22806        &self,
22807        buffer: &Entity<Buffer>,
22808        ranges: &[Range<text::Anchor>],
22809        cx: &mut App,
22810    ) -> Vec<Range<BufferRow>>;
22811
22812    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
22813
22814    fn inlay_hints(
22815        &self,
22816        invalidate: InvalidationStrategy,
22817        buffer: Entity<Buffer>,
22818        ranges: Vec<Range<text::Anchor>>,
22819        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
22820        cx: &mut App,
22821    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
22822
22823    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22824
22825    fn document_highlights(
22826        &self,
22827        buffer: &Entity<Buffer>,
22828        position: text::Anchor,
22829        cx: &mut App,
22830    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22831
22832    fn definitions(
22833        &self,
22834        buffer: &Entity<Buffer>,
22835        position: text::Anchor,
22836        kind: GotoDefinitionKind,
22837        cx: &mut App,
22838    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22839
22840    fn range_for_rename(
22841        &self,
22842        buffer: &Entity<Buffer>,
22843        position: text::Anchor,
22844        cx: &mut App,
22845    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22846
22847    fn perform_rename(
22848        &self,
22849        buffer: &Entity<Buffer>,
22850        position: text::Anchor,
22851        new_name: String,
22852        cx: &mut App,
22853    ) -> Option<Task<Result<ProjectTransaction>>>;
22854}
22855
22856pub trait CompletionProvider {
22857    fn completions(
22858        &self,
22859        excerpt_id: ExcerptId,
22860        buffer: &Entity<Buffer>,
22861        buffer_position: text::Anchor,
22862        trigger: CompletionContext,
22863        window: &mut Window,
22864        cx: &mut Context<Editor>,
22865    ) -> Task<Result<Vec<CompletionResponse>>>;
22866
22867    fn resolve_completions(
22868        &self,
22869        _buffer: Entity<Buffer>,
22870        _completion_indices: Vec<usize>,
22871        _completions: Rc<RefCell<Box<[Completion]>>>,
22872        _cx: &mut Context<Editor>,
22873    ) -> Task<Result<bool>> {
22874        Task::ready(Ok(false))
22875    }
22876
22877    fn apply_additional_edits_for_completion(
22878        &self,
22879        _buffer: Entity<Buffer>,
22880        _completions: Rc<RefCell<Box<[Completion]>>>,
22881        _completion_index: usize,
22882        _push_to_history: bool,
22883        _cx: &mut Context<Editor>,
22884    ) -> Task<Result<Option<language::Transaction>>> {
22885        Task::ready(Ok(None))
22886    }
22887
22888    fn is_completion_trigger(
22889        &self,
22890        buffer: &Entity<Buffer>,
22891        position: language::Anchor,
22892        text: &str,
22893        trigger_in_words: bool,
22894        menu_is_open: bool,
22895        cx: &mut Context<Editor>,
22896    ) -> bool;
22897
22898    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22899
22900    fn sort_completions(&self) -> bool {
22901        true
22902    }
22903
22904    fn filter_completions(&self) -> bool {
22905        true
22906    }
22907}
22908
22909pub trait CodeActionProvider {
22910    fn id(&self) -> Arc<str>;
22911
22912    fn code_actions(
22913        &self,
22914        buffer: &Entity<Buffer>,
22915        range: Range<text::Anchor>,
22916        window: &mut Window,
22917        cx: &mut App,
22918    ) -> Task<Result<Vec<CodeAction>>>;
22919
22920    fn apply_code_action(
22921        &self,
22922        buffer_handle: Entity<Buffer>,
22923        action: CodeAction,
22924        excerpt_id: ExcerptId,
22925        push_to_history: bool,
22926        window: &mut Window,
22927        cx: &mut App,
22928    ) -> Task<Result<ProjectTransaction>>;
22929}
22930
22931impl CodeActionProvider for Entity<Project> {
22932    fn id(&self) -> Arc<str> {
22933        "project".into()
22934    }
22935
22936    fn code_actions(
22937        &self,
22938        buffer: &Entity<Buffer>,
22939        range: Range<text::Anchor>,
22940        _window: &mut Window,
22941        cx: &mut App,
22942    ) -> Task<Result<Vec<CodeAction>>> {
22943        self.update(cx, |project, cx| {
22944            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22945            let code_actions = project.code_actions(buffer, range, None, cx);
22946            cx.background_spawn(async move {
22947                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22948                Ok(code_lens_actions
22949                    .context("code lens fetch")?
22950                    .into_iter()
22951                    .flatten()
22952                    .chain(
22953                        code_actions
22954                            .context("code action fetch")?
22955                            .into_iter()
22956                            .flatten(),
22957                    )
22958                    .collect())
22959            })
22960        })
22961    }
22962
22963    fn apply_code_action(
22964        &self,
22965        buffer_handle: Entity<Buffer>,
22966        action: CodeAction,
22967        _excerpt_id: ExcerptId,
22968        push_to_history: bool,
22969        _window: &mut Window,
22970        cx: &mut App,
22971    ) -> Task<Result<ProjectTransaction>> {
22972        self.update(cx, |project, cx| {
22973            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22974        })
22975    }
22976}
22977
22978fn snippet_completions(
22979    project: &Project,
22980    buffer: &Entity<Buffer>,
22981    buffer_position: text::Anchor,
22982    cx: &mut App,
22983) -> Task<Result<CompletionResponse>> {
22984    let languages = buffer.read(cx).languages_at(buffer_position);
22985    let snippet_store = project.snippets().read(cx);
22986
22987    let scopes: Vec<_> = languages
22988        .iter()
22989        .filter_map(|language| {
22990            let language_name = language.lsp_id();
22991            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22992
22993            if snippets.is_empty() {
22994                None
22995            } else {
22996                Some((language.default_scope(), snippets))
22997            }
22998        })
22999        .collect();
23000
23001    if scopes.is_empty() {
23002        return Task::ready(Ok(CompletionResponse {
23003            completions: vec![],
23004            display_options: CompletionDisplayOptions::default(),
23005            is_incomplete: false,
23006        }));
23007    }
23008
23009    let snapshot = buffer.read(cx).text_snapshot();
23010    let executor = cx.background_executor().clone();
23011
23012    cx.background_spawn(async move {
23013        let mut is_incomplete = false;
23014        let mut completions: Vec<Completion> = Vec::new();
23015        for (scope, snippets) in scopes.into_iter() {
23016            let classifier =
23017                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
23018
23019            const MAX_WORD_PREFIX_LEN: usize = 128;
23020            let last_word: String = snapshot
23021                .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
23022                .take(MAX_WORD_PREFIX_LEN)
23023                .take_while(|c| classifier.is_word(*c))
23024                .collect::<String>()
23025                .chars()
23026                .rev()
23027                .collect();
23028
23029            if last_word.is_empty() {
23030                return Ok(CompletionResponse {
23031                    completions: vec![],
23032                    display_options: CompletionDisplayOptions::default(),
23033                    is_incomplete: true,
23034                });
23035            }
23036
23037            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
23038            let to_lsp = |point: &text::Anchor| {
23039                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
23040                point_to_lsp(end)
23041            };
23042            let lsp_end = to_lsp(&buffer_position);
23043
23044            let candidates = snippets
23045                .iter()
23046                .enumerate()
23047                .flat_map(|(ix, snippet)| {
23048                    snippet
23049                        .prefix
23050                        .iter()
23051                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
23052                })
23053                .collect::<Vec<StringMatchCandidate>>();
23054
23055            const MAX_RESULTS: usize = 100;
23056            let mut matches = fuzzy::match_strings(
23057                &candidates,
23058                &last_word,
23059                last_word.chars().any(|c| c.is_uppercase()),
23060                true,
23061                MAX_RESULTS,
23062                &Default::default(),
23063                executor.clone(),
23064            )
23065            .await;
23066
23067            if matches.len() >= MAX_RESULTS {
23068                is_incomplete = true;
23069            }
23070
23071            // Remove all candidates where the query's start does not match the start of any word in the candidate
23072            if let Some(query_start) = last_word.chars().next() {
23073                matches.retain(|string_match| {
23074                    split_words(&string_match.string).any(|word| {
23075                        // Check that the first codepoint of the word as lowercase matches the first
23076                        // codepoint of the query as lowercase
23077                        word.chars()
23078                            .flat_map(|codepoint| codepoint.to_lowercase())
23079                            .zip(query_start.to_lowercase())
23080                            .all(|(word_cp, query_cp)| word_cp == query_cp)
23081                    })
23082                });
23083            }
23084
23085            let matched_strings = matches
23086                .into_iter()
23087                .map(|m| m.string)
23088                .collect::<HashSet<_>>();
23089
23090            completions.extend(snippets.iter().filter_map(|snippet| {
23091                let matching_prefix = snippet
23092                    .prefix
23093                    .iter()
23094                    .find(|prefix| matched_strings.contains(*prefix))?;
23095                let start = as_offset - last_word.len();
23096                let start = snapshot.anchor_before(start);
23097                let range = start..buffer_position;
23098                let lsp_start = to_lsp(&start);
23099                let lsp_range = lsp::Range {
23100                    start: lsp_start,
23101                    end: lsp_end,
23102                };
23103                Some(Completion {
23104                    replace_range: range,
23105                    new_text: snippet.body.clone(),
23106                    source: CompletionSource::Lsp {
23107                        insert_range: None,
23108                        server_id: LanguageServerId(usize::MAX),
23109                        resolved: true,
23110                        lsp_completion: Box::new(lsp::CompletionItem {
23111                            label: snippet.prefix.first().unwrap().clone(),
23112                            kind: Some(CompletionItemKind::SNIPPET),
23113                            label_details: snippet.description.as_ref().map(|description| {
23114                                lsp::CompletionItemLabelDetails {
23115                                    detail: Some(description.clone()),
23116                                    description: None,
23117                                }
23118                            }),
23119                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23120                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23121                                lsp::InsertReplaceEdit {
23122                                    new_text: snippet.body.clone(),
23123                                    insert: lsp_range,
23124                                    replace: lsp_range,
23125                                },
23126                            )),
23127                            filter_text: Some(snippet.body.clone()),
23128                            sort_text: Some(char::MAX.to_string()),
23129                            ..lsp::CompletionItem::default()
23130                        }),
23131                        lsp_defaults: None,
23132                    },
23133                    label: CodeLabel::plain(matching_prefix.clone(), None),
23134                    icon_path: None,
23135                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23136                        single_line: snippet.name.clone().into(),
23137                        plain_text: snippet
23138                            .description
23139                            .clone()
23140                            .map(|description| description.into()),
23141                    }),
23142                    insert_text_mode: None,
23143                    confirm: None,
23144                })
23145            }))
23146        }
23147
23148        Ok(CompletionResponse {
23149            completions,
23150            display_options: CompletionDisplayOptions::default(),
23151            is_incomplete,
23152        })
23153    })
23154}
23155
23156impl CompletionProvider for Entity<Project> {
23157    fn completions(
23158        &self,
23159        _excerpt_id: ExcerptId,
23160        buffer: &Entity<Buffer>,
23161        buffer_position: text::Anchor,
23162        options: CompletionContext,
23163        _window: &mut Window,
23164        cx: &mut Context<Editor>,
23165    ) -> Task<Result<Vec<CompletionResponse>>> {
23166        self.update(cx, |project, cx| {
23167            let snippets = snippet_completions(project, buffer, buffer_position, cx);
23168            let project_completions = project.completions(buffer, buffer_position, options, cx);
23169            cx.background_spawn(async move {
23170                let mut responses = project_completions.await?;
23171                let snippets = snippets.await?;
23172                if !snippets.completions.is_empty() {
23173                    responses.push(snippets);
23174                }
23175                Ok(responses)
23176            })
23177        })
23178    }
23179
23180    fn resolve_completions(
23181        &self,
23182        buffer: Entity<Buffer>,
23183        completion_indices: Vec<usize>,
23184        completions: Rc<RefCell<Box<[Completion]>>>,
23185        cx: &mut Context<Editor>,
23186    ) -> Task<Result<bool>> {
23187        self.update(cx, |project, cx| {
23188            project.lsp_store().update(cx, |lsp_store, cx| {
23189                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23190            })
23191        })
23192    }
23193
23194    fn apply_additional_edits_for_completion(
23195        &self,
23196        buffer: Entity<Buffer>,
23197        completions: Rc<RefCell<Box<[Completion]>>>,
23198        completion_index: usize,
23199        push_to_history: bool,
23200        cx: &mut Context<Editor>,
23201    ) -> Task<Result<Option<language::Transaction>>> {
23202        self.update(cx, |project, cx| {
23203            project.lsp_store().update(cx, |lsp_store, cx| {
23204                lsp_store.apply_additional_edits_for_completion(
23205                    buffer,
23206                    completions,
23207                    completion_index,
23208                    push_to_history,
23209                    cx,
23210                )
23211            })
23212        })
23213    }
23214
23215    fn is_completion_trigger(
23216        &self,
23217        buffer: &Entity<Buffer>,
23218        position: language::Anchor,
23219        text: &str,
23220        trigger_in_words: bool,
23221        menu_is_open: bool,
23222        cx: &mut Context<Editor>,
23223    ) -> bool {
23224        let mut chars = text.chars();
23225        let char = if let Some(char) = chars.next() {
23226            char
23227        } else {
23228            return false;
23229        };
23230        if chars.next().is_some() {
23231            return false;
23232        }
23233
23234        let buffer = buffer.read(cx);
23235        let snapshot = buffer.snapshot();
23236        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23237            return false;
23238        }
23239        let classifier = snapshot
23240            .char_classifier_at(position)
23241            .scope_context(Some(CharScopeContext::Completion));
23242        if trigger_in_words && classifier.is_word(char) {
23243            return true;
23244        }
23245
23246        buffer.completion_triggers().contains(text)
23247    }
23248}
23249
23250impl SemanticsProvider for Entity<Project> {
23251    fn hover(
23252        &self,
23253        buffer: &Entity<Buffer>,
23254        position: text::Anchor,
23255        cx: &mut App,
23256    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23257        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23258    }
23259
23260    fn document_highlights(
23261        &self,
23262        buffer: &Entity<Buffer>,
23263        position: text::Anchor,
23264        cx: &mut App,
23265    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23266        Some(self.update(cx, |project, cx| {
23267            project.document_highlights(buffer, position, cx)
23268        }))
23269    }
23270
23271    fn definitions(
23272        &self,
23273        buffer: &Entity<Buffer>,
23274        position: text::Anchor,
23275        kind: GotoDefinitionKind,
23276        cx: &mut App,
23277    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23278        Some(self.update(cx, |project, cx| match kind {
23279            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23280            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23281            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23282            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23283        }))
23284    }
23285
23286    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23287        self.update(cx, |project, cx| {
23288            if project
23289                .active_debug_session(cx)
23290                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23291            {
23292                return true;
23293            }
23294
23295            buffer.update(cx, |buffer, cx| {
23296                project.any_language_server_supports_inlay_hints(buffer, cx)
23297            })
23298        })
23299    }
23300
23301    fn inline_values(
23302        &self,
23303        buffer_handle: Entity<Buffer>,
23304        range: Range<text::Anchor>,
23305        cx: &mut App,
23306    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23307        self.update(cx, |project, cx| {
23308            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23309
23310            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23311        })
23312    }
23313
23314    fn applicable_inlay_chunks(
23315        &self,
23316        buffer: &Entity<Buffer>,
23317        ranges: &[Range<text::Anchor>],
23318        cx: &mut App,
23319    ) -> Vec<Range<BufferRow>> {
23320        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23321            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
23322        })
23323    }
23324
23325    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
23326        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
23327            lsp_store.invalidate_inlay_hints(for_buffers)
23328        });
23329    }
23330
23331    fn inlay_hints(
23332        &self,
23333        invalidate: InvalidationStrategy,
23334        buffer: Entity<Buffer>,
23335        ranges: Vec<Range<text::Anchor>>,
23336        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23337        cx: &mut App,
23338    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
23339        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23340            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
23341        }))
23342    }
23343
23344    fn range_for_rename(
23345        &self,
23346        buffer: &Entity<Buffer>,
23347        position: text::Anchor,
23348        cx: &mut App,
23349    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23350        Some(self.update(cx, |project, cx| {
23351            let buffer = buffer.clone();
23352            let task = project.prepare_rename(buffer.clone(), position, cx);
23353            cx.spawn(async move |_, cx| {
23354                Ok(match task.await? {
23355                    PrepareRenameResponse::Success(range) => Some(range),
23356                    PrepareRenameResponse::InvalidPosition => None,
23357                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23358                        // Fallback on using TreeSitter info to determine identifier range
23359                        buffer.read_with(cx, |buffer, _| {
23360                            let snapshot = buffer.snapshot();
23361                            let (range, kind) = snapshot.surrounding_word(position, None);
23362                            if kind != Some(CharKind::Word) {
23363                                return None;
23364                            }
23365                            Some(
23366                                snapshot.anchor_before(range.start)
23367                                    ..snapshot.anchor_after(range.end),
23368                            )
23369                        })?
23370                    }
23371                })
23372            })
23373        }))
23374    }
23375
23376    fn perform_rename(
23377        &self,
23378        buffer: &Entity<Buffer>,
23379        position: text::Anchor,
23380        new_name: String,
23381        cx: &mut App,
23382    ) -> Option<Task<Result<ProjectTransaction>>> {
23383        Some(self.update(cx, |project, cx| {
23384            project.perform_rename(buffer.clone(), position, new_name, cx)
23385        }))
23386    }
23387}
23388
23389fn consume_contiguous_rows(
23390    contiguous_row_selections: &mut Vec<Selection<Point>>,
23391    selection: &Selection<Point>,
23392    display_map: &DisplaySnapshot,
23393    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23394) -> (MultiBufferRow, MultiBufferRow) {
23395    contiguous_row_selections.push(selection.clone());
23396    let start_row = starting_row(selection, display_map);
23397    let mut end_row = ending_row(selection, display_map);
23398
23399    while let Some(next_selection) = selections.peek() {
23400        if next_selection.start.row <= end_row.0 {
23401            end_row = ending_row(next_selection, display_map);
23402            contiguous_row_selections.push(selections.next().unwrap().clone());
23403        } else {
23404            break;
23405        }
23406    }
23407    (start_row, end_row)
23408}
23409
23410fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23411    if selection.start.column > 0 {
23412        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23413    } else {
23414        MultiBufferRow(selection.start.row)
23415    }
23416}
23417
23418fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23419    if next_selection.end.column > 0 || next_selection.is_empty() {
23420        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23421    } else {
23422        MultiBufferRow(next_selection.end.row)
23423    }
23424}
23425
23426impl EditorSnapshot {
23427    pub fn remote_selections_in_range<'a>(
23428        &'a self,
23429        range: &'a Range<Anchor>,
23430        collaboration_hub: &dyn CollaborationHub,
23431        cx: &'a App,
23432    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23433        let participant_names = collaboration_hub.user_names(cx);
23434        let participant_indices = collaboration_hub.user_participant_indices(cx);
23435        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23436        let collaborators_by_replica_id = collaborators_by_peer_id
23437            .values()
23438            .map(|collaborator| (collaborator.replica_id, collaborator))
23439            .collect::<HashMap<_, _>>();
23440        self.buffer_snapshot()
23441            .selections_in_range(range, false)
23442            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23443                if replica_id == ReplicaId::AGENT {
23444                    Some(RemoteSelection {
23445                        replica_id,
23446                        selection,
23447                        cursor_shape,
23448                        line_mode,
23449                        collaborator_id: CollaboratorId::Agent,
23450                        user_name: Some("Agent".into()),
23451                        color: cx.theme().players().agent(),
23452                    })
23453                } else {
23454                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23455                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23456                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23457                    Some(RemoteSelection {
23458                        replica_id,
23459                        selection,
23460                        cursor_shape,
23461                        line_mode,
23462                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23463                        user_name,
23464                        color: if let Some(index) = participant_index {
23465                            cx.theme().players().color_for_participant(index.0)
23466                        } else {
23467                            cx.theme().players().absent()
23468                        },
23469                    })
23470                }
23471            })
23472    }
23473
23474    pub fn hunks_for_ranges(
23475        &self,
23476        ranges: impl IntoIterator<Item = Range<Point>>,
23477    ) -> Vec<MultiBufferDiffHunk> {
23478        let mut hunks = Vec::new();
23479        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23480            HashMap::default();
23481        for query_range in ranges {
23482            let query_rows =
23483                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23484            for hunk in self.buffer_snapshot().diff_hunks_in_range(
23485                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23486            ) {
23487                // Include deleted hunks that are adjacent to the query range, because
23488                // otherwise they would be missed.
23489                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23490                if hunk.status().is_deleted() {
23491                    intersects_range |= hunk.row_range.start == query_rows.end;
23492                    intersects_range |= hunk.row_range.end == query_rows.start;
23493                }
23494                if intersects_range {
23495                    if !processed_buffer_rows
23496                        .entry(hunk.buffer_id)
23497                        .or_default()
23498                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23499                    {
23500                        continue;
23501                    }
23502                    hunks.push(hunk);
23503                }
23504            }
23505        }
23506
23507        hunks
23508    }
23509
23510    fn display_diff_hunks_for_rows<'a>(
23511        &'a self,
23512        display_rows: Range<DisplayRow>,
23513        folded_buffers: &'a HashSet<BufferId>,
23514    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23515        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23516        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23517
23518        self.buffer_snapshot()
23519            .diff_hunks_in_range(buffer_start..buffer_end)
23520            .filter_map(|hunk| {
23521                if folded_buffers.contains(&hunk.buffer_id) {
23522                    return None;
23523                }
23524
23525                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23526                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23527
23528                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23529                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23530
23531                let display_hunk = if hunk_display_start.column() != 0 {
23532                    DisplayDiffHunk::Folded {
23533                        display_row: hunk_display_start.row(),
23534                    }
23535                } else {
23536                    let mut end_row = hunk_display_end.row();
23537                    if hunk_display_end.column() > 0 {
23538                        end_row.0 += 1;
23539                    }
23540                    let is_created_file = hunk.is_created_file();
23541                    DisplayDiffHunk::Unfolded {
23542                        status: hunk.status(),
23543                        diff_base_byte_range: hunk.diff_base_byte_range,
23544                        display_row_range: hunk_display_start.row()..end_row,
23545                        multi_buffer_range: Anchor::range_in_buffer(
23546                            hunk.excerpt_id,
23547                            hunk.buffer_id,
23548                            hunk.buffer_range,
23549                        ),
23550                        is_created_file,
23551                    }
23552                };
23553
23554                Some(display_hunk)
23555            })
23556    }
23557
23558    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23559        self.display_snapshot
23560            .buffer_snapshot()
23561            .language_at(position)
23562    }
23563
23564    pub fn is_focused(&self) -> bool {
23565        self.is_focused
23566    }
23567
23568    pub fn placeholder_text(&self) -> Option<String> {
23569        self.placeholder_display_snapshot
23570            .as_ref()
23571            .map(|display_map| display_map.text())
23572    }
23573
23574    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
23575        self.scroll_anchor.scroll_position(&self.display_snapshot)
23576    }
23577
23578    fn gutter_dimensions(
23579        &self,
23580        font_id: FontId,
23581        font_size: Pixels,
23582        max_line_number_width: Pixels,
23583        cx: &App,
23584    ) -> Option<GutterDimensions> {
23585        if !self.show_gutter {
23586            return None;
23587        }
23588
23589        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23590        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23591
23592        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23593            matches!(
23594                ProjectSettings::get_global(cx).git.git_gutter,
23595                GitGutterSetting::TrackedFiles
23596            )
23597        });
23598        let gutter_settings = EditorSettings::get_global(cx).gutter;
23599        let show_line_numbers = self
23600            .show_line_numbers
23601            .unwrap_or(gutter_settings.line_numbers);
23602        let line_gutter_width = if show_line_numbers {
23603            // Avoid flicker-like gutter resizes when the line number gains another digit by
23604            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23605            let min_width_for_number_on_gutter =
23606                ch_advance * gutter_settings.min_line_number_digits as f32;
23607            max_line_number_width.max(min_width_for_number_on_gutter)
23608        } else {
23609            0.0.into()
23610        };
23611
23612        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23613        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23614
23615        let git_blame_entries_width =
23616            self.git_blame_gutter_max_author_length
23617                .map(|max_author_length| {
23618                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23619                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23620
23621                    /// The number of characters to dedicate to gaps and margins.
23622                    const SPACING_WIDTH: usize = 4;
23623
23624                    let max_char_count = max_author_length.min(renderer.max_author_length())
23625                        + ::git::SHORT_SHA_LENGTH
23626                        + MAX_RELATIVE_TIMESTAMP.len()
23627                        + SPACING_WIDTH;
23628
23629                    ch_advance * max_char_count
23630                });
23631
23632        let is_singleton = self.buffer_snapshot().is_singleton();
23633
23634        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23635        left_padding += if !is_singleton {
23636            ch_width * 4.0
23637        } else if show_runnables || show_breakpoints {
23638            ch_width * 3.0
23639        } else if show_git_gutter && show_line_numbers {
23640            ch_width * 2.0
23641        } else if show_git_gutter || show_line_numbers {
23642            ch_width
23643        } else {
23644            px(0.)
23645        };
23646
23647        let shows_folds = is_singleton && gutter_settings.folds;
23648
23649        let right_padding = if shows_folds && show_line_numbers {
23650            ch_width * 4.0
23651        } else if shows_folds || (!is_singleton && show_line_numbers) {
23652            ch_width * 3.0
23653        } else if show_line_numbers {
23654            ch_width
23655        } else {
23656            px(0.)
23657        };
23658
23659        Some(GutterDimensions {
23660            left_padding,
23661            right_padding,
23662            width: line_gutter_width + left_padding + right_padding,
23663            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23664            git_blame_entries_width,
23665        })
23666    }
23667
23668    pub fn render_crease_toggle(
23669        &self,
23670        buffer_row: MultiBufferRow,
23671        row_contains_cursor: bool,
23672        editor: Entity<Editor>,
23673        window: &mut Window,
23674        cx: &mut App,
23675    ) -> Option<AnyElement> {
23676        let folded = self.is_line_folded(buffer_row);
23677        let mut is_foldable = false;
23678
23679        if let Some(crease) = self
23680            .crease_snapshot
23681            .query_row(buffer_row, self.buffer_snapshot())
23682        {
23683            is_foldable = true;
23684            match crease {
23685                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23686                    if let Some(render_toggle) = render_toggle {
23687                        let toggle_callback =
23688                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23689                                if folded {
23690                                    editor.update(cx, |editor, cx| {
23691                                        editor.fold_at(buffer_row, window, cx)
23692                                    });
23693                                } else {
23694                                    editor.update(cx, |editor, cx| {
23695                                        editor.unfold_at(buffer_row, window, cx)
23696                                    });
23697                                }
23698                            });
23699                        return Some((render_toggle)(
23700                            buffer_row,
23701                            folded,
23702                            toggle_callback,
23703                            window,
23704                            cx,
23705                        ));
23706                    }
23707                }
23708            }
23709        }
23710
23711        is_foldable |= self.starts_indent(buffer_row);
23712
23713        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23714            Some(
23715                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23716                    .toggle_state(folded)
23717                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23718                        if folded {
23719                            this.unfold_at(buffer_row, window, cx);
23720                        } else {
23721                            this.fold_at(buffer_row, window, cx);
23722                        }
23723                    }))
23724                    .into_any_element(),
23725            )
23726        } else {
23727            None
23728        }
23729    }
23730
23731    pub fn render_crease_trailer(
23732        &self,
23733        buffer_row: MultiBufferRow,
23734        window: &mut Window,
23735        cx: &mut App,
23736    ) -> Option<AnyElement> {
23737        let folded = self.is_line_folded(buffer_row);
23738        if let Crease::Inline { render_trailer, .. } = self
23739            .crease_snapshot
23740            .query_row(buffer_row, self.buffer_snapshot())?
23741        {
23742            let render_trailer = render_trailer.as_ref()?;
23743            Some(render_trailer(buffer_row, folded, window, cx))
23744        } else {
23745            None
23746        }
23747    }
23748}
23749
23750impl Deref for EditorSnapshot {
23751    type Target = DisplaySnapshot;
23752
23753    fn deref(&self) -> &Self::Target {
23754        &self.display_snapshot
23755    }
23756}
23757
23758#[derive(Clone, Debug, PartialEq, Eq)]
23759pub enum EditorEvent {
23760    InputIgnored {
23761        text: Arc<str>,
23762    },
23763    InputHandled {
23764        utf16_range_to_replace: Option<Range<isize>>,
23765        text: Arc<str>,
23766    },
23767    ExcerptsAdded {
23768        buffer: Entity<Buffer>,
23769        predecessor: ExcerptId,
23770        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23771    },
23772    ExcerptsRemoved {
23773        ids: Vec<ExcerptId>,
23774        removed_buffer_ids: Vec<BufferId>,
23775    },
23776    BufferFoldToggled {
23777        ids: Vec<ExcerptId>,
23778        folded: bool,
23779    },
23780    ExcerptsEdited {
23781        ids: Vec<ExcerptId>,
23782    },
23783    ExcerptsExpanded {
23784        ids: Vec<ExcerptId>,
23785    },
23786    BufferEdited,
23787    Edited {
23788        transaction_id: clock::Lamport,
23789    },
23790    Reparsed(BufferId),
23791    Focused,
23792    FocusedIn,
23793    Blurred,
23794    DirtyChanged,
23795    Saved,
23796    TitleChanged,
23797    SelectionsChanged {
23798        local: bool,
23799    },
23800    ScrollPositionChanged {
23801        local: bool,
23802        autoscroll: bool,
23803    },
23804    TransactionUndone {
23805        transaction_id: clock::Lamport,
23806    },
23807    TransactionBegun {
23808        transaction_id: clock::Lamport,
23809    },
23810    CursorShapeChanged,
23811    BreadcrumbsChanged,
23812    PushedToNavHistory {
23813        anchor: Anchor,
23814        is_deactivate: bool,
23815    },
23816}
23817
23818impl EventEmitter<EditorEvent> for Editor {}
23819
23820impl Focusable for Editor {
23821    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23822        self.focus_handle.clone()
23823    }
23824}
23825
23826impl Render for Editor {
23827    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23828        let settings = ThemeSettings::get_global(cx);
23829
23830        let mut text_style = match self.mode {
23831            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23832                color: cx.theme().colors().editor_foreground,
23833                font_family: settings.ui_font.family.clone(),
23834                font_features: settings.ui_font.features.clone(),
23835                font_fallbacks: settings.ui_font.fallbacks.clone(),
23836                font_size: rems(0.875).into(),
23837                font_weight: settings.ui_font.weight,
23838                line_height: relative(settings.buffer_line_height.value()),
23839                ..Default::default()
23840            },
23841            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23842                color: cx.theme().colors().editor_foreground,
23843                font_family: settings.buffer_font.family.clone(),
23844                font_features: settings.buffer_font.features.clone(),
23845                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23846                font_size: settings.buffer_font_size(cx).into(),
23847                font_weight: settings.buffer_font.weight,
23848                line_height: relative(settings.buffer_line_height.value()),
23849                ..Default::default()
23850            },
23851        };
23852        if let Some(text_style_refinement) = &self.text_style_refinement {
23853            text_style.refine(text_style_refinement)
23854        }
23855
23856        let background = match self.mode {
23857            EditorMode::SingleLine => cx.theme().system().transparent,
23858            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23859            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23860            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23861        };
23862
23863        EditorElement::new(
23864            &cx.entity(),
23865            EditorStyle {
23866                background,
23867                border: cx.theme().colors().border,
23868                local_player: cx.theme().players().local(),
23869                text: text_style,
23870                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23871                syntax: cx.theme().syntax().clone(),
23872                status: cx.theme().status().clone(),
23873                inlay_hints_style: make_inlay_hints_style(cx),
23874                edit_prediction_styles: make_suggestion_styles(cx),
23875                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23876                show_underlines: self.diagnostics_enabled(),
23877            },
23878        )
23879    }
23880}
23881
23882impl EntityInputHandler for Editor {
23883    fn text_for_range(
23884        &mut self,
23885        range_utf16: Range<usize>,
23886        adjusted_range: &mut Option<Range<usize>>,
23887        _: &mut Window,
23888        cx: &mut Context<Self>,
23889    ) -> Option<String> {
23890        let snapshot = self.buffer.read(cx).read(cx);
23891        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23892        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23893        if (start.0..end.0) != range_utf16 {
23894            adjusted_range.replace(start.0..end.0);
23895        }
23896        Some(snapshot.text_for_range(start..end).collect())
23897    }
23898
23899    fn selected_text_range(
23900        &mut self,
23901        ignore_disabled_input: bool,
23902        _: &mut Window,
23903        cx: &mut Context<Self>,
23904    ) -> Option<UTF16Selection> {
23905        // Prevent the IME menu from appearing when holding down an alphabetic key
23906        // while input is disabled.
23907        if !ignore_disabled_input && !self.input_enabled {
23908            return None;
23909        }
23910
23911        let selection = self
23912            .selections
23913            .newest::<OffsetUtf16>(&self.display_snapshot(cx));
23914        let range = selection.range();
23915
23916        Some(UTF16Selection {
23917            range: range.start.0..range.end.0,
23918            reversed: selection.reversed,
23919        })
23920    }
23921
23922    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23923        let snapshot = self.buffer.read(cx).read(cx);
23924        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23925        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23926    }
23927
23928    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23929        self.clear_highlights::<InputComposition>(cx);
23930        self.ime_transaction.take();
23931    }
23932
23933    fn replace_text_in_range(
23934        &mut self,
23935        range_utf16: Option<Range<usize>>,
23936        text: &str,
23937        window: &mut Window,
23938        cx: &mut Context<Self>,
23939    ) {
23940        if !self.input_enabled {
23941            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23942            return;
23943        }
23944
23945        self.transact(window, cx, |this, window, cx| {
23946            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23947                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23948                Some(this.selection_replacement_ranges(range_utf16, cx))
23949            } else {
23950                this.marked_text_ranges(cx)
23951            };
23952
23953            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23954                let newest_selection_id = this.selections.newest_anchor().id;
23955                this.selections
23956                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
23957                    .iter()
23958                    .zip(ranges_to_replace.iter())
23959                    .find_map(|(selection, range)| {
23960                        if selection.id == newest_selection_id {
23961                            Some(
23962                                (range.start.0 as isize - selection.head().0 as isize)
23963                                    ..(range.end.0 as isize - selection.head().0 as isize),
23964                            )
23965                        } else {
23966                            None
23967                        }
23968                    })
23969            });
23970
23971            cx.emit(EditorEvent::InputHandled {
23972                utf16_range_to_replace: range_to_replace,
23973                text: text.into(),
23974            });
23975
23976            if let Some(new_selected_ranges) = new_selected_ranges {
23977                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23978                    selections.select_ranges(new_selected_ranges)
23979                });
23980                this.backspace(&Default::default(), window, cx);
23981            }
23982
23983            this.handle_input(text, window, cx);
23984        });
23985
23986        if let Some(transaction) = self.ime_transaction {
23987            self.buffer.update(cx, |buffer, cx| {
23988                buffer.group_until_transaction(transaction, cx);
23989            });
23990        }
23991
23992        self.unmark_text(window, cx);
23993    }
23994
23995    fn replace_and_mark_text_in_range(
23996        &mut self,
23997        range_utf16: Option<Range<usize>>,
23998        text: &str,
23999        new_selected_range_utf16: Option<Range<usize>>,
24000        window: &mut Window,
24001        cx: &mut Context<Self>,
24002    ) {
24003        if !self.input_enabled {
24004            return;
24005        }
24006
24007        let transaction = self.transact(window, cx, |this, window, cx| {
24008            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
24009                let snapshot = this.buffer.read(cx).read(cx);
24010                if let Some(relative_range_utf16) = range_utf16.as_ref() {
24011                    for marked_range in &mut marked_ranges {
24012                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
24013                        marked_range.start.0 += relative_range_utf16.start;
24014                        marked_range.start =
24015                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
24016                        marked_range.end =
24017                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
24018                    }
24019                }
24020                Some(marked_ranges)
24021            } else if let Some(range_utf16) = range_utf16 {
24022                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
24023                Some(this.selection_replacement_ranges(range_utf16, cx))
24024            } else {
24025                None
24026            };
24027
24028            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
24029                let newest_selection_id = this.selections.newest_anchor().id;
24030                this.selections
24031                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
24032                    .iter()
24033                    .zip(ranges_to_replace.iter())
24034                    .find_map(|(selection, range)| {
24035                        if selection.id == newest_selection_id {
24036                            Some(
24037                                (range.start.0 as isize - selection.head().0 as isize)
24038                                    ..(range.end.0 as isize - selection.head().0 as isize),
24039                            )
24040                        } else {
24041                            None
24042                        }
24043                    })
24044            });
24045
24046            cx.emit(EditorEvent::InputHandled {
24047                utf16_range_to_replace: range_to_replace,
24048                text: text.into(),
24049            });
24050
24051            if let Some(ranges) = ranges_to_replace {
24052                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24053                    s.select_ranges(ranges)
24054                });
24055            }
24056
24057            let marked_ranges = {
24058                let snapshot = this.buffer.read(cx).read(cx);
24059                this.selections
24060                    .disjoint_anchors_arc()
24061                    .iter()
24062                    .map(|selection| {
24063                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
24064                    })
24065                    .collect::<Vec<_>>()
24066            };
24067
24068            if text.is_empty() {
24069                this.unmark_text(window, cx);
24070            } else {
24071                this.highlight_text::<InputComposition>(
24072                    marked_ranges.clone(),
24073                    HighlightStyle {
24074                        underline: Some(UnderlineStyle {
24075                            thickness: px(1.),
24076                            color: None,
24077                            wavy: false,
24078                        }),
24079                        ..Default::default()
24080                    },
24081                    cx,
24082                );
24083            }
24084
24085            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
24086            let use_autoclose = this.use_autoclose;
24087            let use_auto_surround = this.use_auto_surround;
24088            this.set_use_autoclose(false);
24089            this.set_use_auto_surround(false);
24090            this.handle_input(text, window, cx);
24091            this.set_use_autoclose(use_autoclose);
24092            this.set_use_auto_surround(use_auto_surround);
24093
24094            if let Some(new_selected_range) = new_selected_range_utf16 {
24095                let snapshot = this.buffer.read(cx).read(cx);
24096                let new_selected_ranges = marked_ranges
24097                    .into_iter()
24098                    .map(|marked_range| {
24099                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24100                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
24101                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
24102                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24103                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24104                    })
24105                    .collect::<Vec<_>>();
24106
24107                drop(snapshot);
24108                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24109                    selections.select_ranges(new_selected_ranges)
24110                });
24111            }
24112        });
24113
24114        self.ime_transaction = self.ime_transaction.or(transaction);
24115        if let Some(transaction) = self.ime_transaction {
24116            self.buffer.update(cx, |buffer, cx| {
24117                buffer.group_until_transaction(transaction, cx);
24118            });
24119        }
24120
24121        if self.text_highlights::<InputComposition>(cx).is_none() {
24122            self.ime_transaction.take();
24123        }
24124    }
24125
24126    fn bounds_for_range(
24127        &mut self,
24128        range_utf16: Range<usize>,
24129        element_bounds: gpui::Bounds<Pixels>,
24130        window: &mut Window,
24131        cx: &mut Context<Self>,
24132    ) -> Option<gpui::Bounds<Pixels>> {
24133        let text_layout_details = self.text_layout_details(window);
24134        let CharacterDimensions {
24135            em_width,
24136            em_advance,
24137            line_height,
24138        } = self.character_dimensions(window);
24139
24140        let snapshot = self.snapshot(window, cx);
24141        let scroll_position = snapshot.scroll_position();
24142        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24143
24144        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
24145        let x = Pixels::from(
24146            ScrollOffset::from(
24147                snapshot.x_for_display_point(start, &text_layout_details)
24148                    + self.gutter_dimensions.full_width(),
24149            ) - scroll_left,
24150        );
24151        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24152
24153        Some(Bounds {
24154            origin: element_bounds.origin + point(x, y),
24155            size: size(em_width, line_height),
24156        })
24157    }
24158
24159    fn character_index_for_point(
24160        &mut self,
24161        point: gpui::Point<Pixels>,
24162        _window: &mut Window,
24163        _cx: &mut Context<Self>,
24164    ) -> Option<usize> {
24165        let position_map = self.last_position_map.as_ref()?;
24166        if !position_map.text_hitbox.contains(&point) {
24167            return None;
24168        }
24169        let display_point = position_map.point_for_position(point).previous_valid;
24170        let anchor = position_map
24171            .snapshot
24172            .display_point_to_anchor(display_point, Bias::Left);
24173        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24174        Some(utf16_offset.0)
24175    }
24176
24177    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
24178        self.input_enabled
24179    }
24180}
24181
24182trait SelectionExt {
24183    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24184    fn spanned_rows(
24185        &self,
24186        include_end_if_at_line_start: bool,
24187        map: &DisplaySnapshot,
24188    ) -> Range<MultiBufferRow>;
24189}
24190
24191impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24192    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24193        let start = self
24194            .start
24195            .to_point(map.buffer_snapshot())
24196            .to_display_point(map);
24197        let end = self
24198            .end
24199            .to_point(map.buffer_snapshot())
24200            .to_display_point(map);
24201        if self.reversed {
24202            end..start
24203        } else {
24204            start..end
24205        }
24206    }
24207
24208    fn spanned_rows(
24209        &self,
24210        include_end_if_at_line_start: bool,
24211        map: &DisplaySnapshot,
24212    ) -> Range<MultiBufferRow> {
24213        let start = self.start.to_point(map.buffer_snapshot());
24214        let mut end = self.end.to_point(map.buffer_snapshot());
24215        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24216            end.row -= 1;
24217        }
24218
24219        let buffer_start = map.prev_line_boundary(start).0;
24220        let buffer_end = map.next_line_boundary(end).0;
24221        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24222    }
24223}
24224
24225impl<T: InvalidationRegion> InvalidationStack<T> {
24226    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24227    where
24228        S: Clone + ToOffset,
24229    {
24230        while let Some(region) = self.last() {
24231            let all_selections_inside_invalidation_ranges =
24232                if selections.len() == region.ranges().len() {
24233                    selections
24234                        .iter()
24235                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24236                        .all(|(selection, invalidation_range)| {
24237                            let head = selection.head().to_offset(buffer);
24238                            invalidation_range.start <= head && invalidation_range.end >= head
24239                        })
24240                } else {
24241                    false
24242                };
24243
24244            if all_selections_inside_invalidation_ranges {
24245                break;
24246            } else {
24247                self.pop();
24248            }
24249        }
24250    }
24251}
24252
24253impl<T> Default for InvalidationStack<T> {
24254    fn default() -> Self {
24255        Self(Default::default())
24256    }
24257}
24258
24259impl<T> Deref for InvalidationStack<T> {
24260    type Target = Vec<T>;
24261
24262    fn deref(&self) -> &Self::Target {
24263        &self.0
24264    }
24265}
24266
24267impl<T> DerefMut for InvalidationStack<T> {
24268    fn deref_mut(&mut self) -> &mut Self::Target {
24269        &mut self.0
24270    }
24271}
24272
24273impl InvalidationRegion for SnippetState {
24274    fn ranges(&self) -> &[Range<Anchor>] {
24275        &self.ranges[self.active_index]
24276    }
24277}
24278
24279fn edit_prediction_edit_text(
24280    current_snapshot: &BufferSnapshot,
24281    edits: &[(Range<Anchor>, String)],
24282    edit_preview: &EditPreview,
24283    include_deletions: bool,
24284    cx: &App,
24285) -> HighlightedText {
24286    let edits = edits
24287        .iter()
24288        .map(|(anchor, text)| {
24289            (
24290                anchor.start.text_anchor..anchor.end.text_anchor,
24291                text.clone(),
24292            )
24293        })
24294        .collect::<Vec<_>>();
24295
24296    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24297}
24298
24299fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
24300    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24301    // Just show the raw edit text with basic styling
24302    let mut text = String::new();
24303    let mut highlights = Vec::new();
24304
24305    let insertion_highlight_style = HighlightStyle {
24306        color: Some(cx.theme().colors().text),
24307        ..Default::default()
24308    };
24309
24310    for (_, edit_text) in edits {
24311        let start_offset = text.len();
24312        text.push_str(edit_text);
24313        let end_offset = text.len();
24314
24315        if start_offset < end_offset {
24316            highlights.push((start_offset..end_offset, insertion_highlight_style));
24317        }
24318    }
24319
24320    HighlightedText {
24321        text: text.into(),
24322        highlights,
24323    }
24324}
24325
24326pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24327    match severity {
24328        lsp::DiagnosticSeverity::ERROR => colors.error,
24329        lsp::DiagnosticSeverity::WARNING => colors.warning,
24330        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24331        lsp::DiagnosticSeverity::HINT => colors.info,
24332        _ => colors.ignored,
24333    }
24334}
24335
24336pub fn styled_runs_for_code_label<'a>(
24337    label: &'a CodeLabel,
24338    syntax_theme: &'a theme::SyntaxTheme,
24339) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24340    let fade_out = HighlightStyle {
24341        fade_out: Some(0.35),
24342        ..Default::default()
24343    };
24344
24345    let mut prev_end = label.filter_range.end;
24346    label
24347        .runs
24348        .iter()
24349        .enumerate()
24350        .flat_map(move |(ix, (range, highlight_id))| {
24351            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24352                style
24353            } else {
24354                return Default::default();
24355            };
24356            let muted_style = style.highlight(fade_out);
24357
24358            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24359            if range.start >= label.filter_range.end {
24360                if range.start > prev_end {
24361                    runs.push((prev_end..range.start, fade_out));
24362                }
24363                runs.push((range.clone(), muted_style));
24364            } else if range.end <= label.filter_range.end {
24365                runs.push((range.clone(), style));
24366            } else {
24367                runs.push((range.start..label.filter_range.end, style));
24368                runs.push((label.filter_range.end..range.end, muted_style));
24369            }
24370            prev_end = cmp::max(prev_end, range.end);
24371
24372            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24373                runs.push((prev_end..label.text.len(), fade_out));
24374            }
24375
24376            runs
24377        })
24378}
24379
24380pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24381    let mut prev_index = 0;
24382    let mut prev_codepoint: Option<char> = None;
24383    text.char_indices()
24384        .chain([(text.len(), '\0')])
24385        .filter_map(move |(index, codepoint)| {
24386            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24387            let is_boundary = index == text.len()
24388                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24389                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24390            if is_boundary {
24391                let chunk = &text[prev_index..index];
24392                prev_index = index;
24393                Some(chunk)
24394            } else {
24395                None
24396            }
24397        })
24398}
24399
24400pub trait RangeToAnchorExt: Sized {
24401    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24402
24403    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24404        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
24405        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24406    }
24407}
24408
24409impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24410    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24411        let start_offset = self.start.to_offset(snapshot);
24412        let end_offset = self.end.to_offset(snapshot);
24413        if start_offset == end_offset {
24414            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24415        } else {
24416            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24417        }
24418    }
24419}
24420
24421pub trait RowExt {
24422    fn as_f64(&self) -> f64;
24423
24424    fn next_row(&self) -> Self;
24425
24426    fn previous_row(&self) -> Self;
24427
24428    fn minus(&self, other: Self) -> u32;
24429}
24430
24431impl RowExt for DisplayRow {
24432    fn as_f64(&self) -> f64 {
24433        self.0 as _
24434    }
24435
24436    fn next_row(&self) -> Self {
24437        Self(self.0 + 1)
24438    }
24439
24440    fn previous_row(&self) -> Self {
24441        Self(self.0.saturating_sub(1))
24442    }
24443
24444    fn minus(&self, other: Self) -> u32 {
24445        self.0 - other.0
24446    }
24447}
24448
24449impl RowExt for MultiBufferRow {
24450    fn as_f64(&self) -> f64 {
24451        self.0 as _
24452    }
24453
24454    fn next_row(&self) -> Self {
24455        Self(self.0 + 1)
24456    }
24457
24458    fn previous_row(&self) -> Self {
24459        Self(self.0.saturating_sub(1))
24460    }
24461
24462    fn minus(&self, other: Self) -> u32 {
24463        self.0 - other.0
24464    }
24465}
24466
24467trait RowRangeExt {
24468    type Row;
24469
24470    fn len(&self) -> usize;
24471
24472    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24473}
24474
24475impl RowRangeExt for Range<MultiBufferRow> {
24476    type Row = MultiBufferRow;
24477
24478    fn len(&self) -> usize {
24479        (self.end.0 - self.start.0) as usize
24480    }
24481
24482    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24483        (self.start.0..self.end.0).map(MultiBufferRow)
24484    }
24485}
24486
24487impl RowRangeExt for Range<DisplayRow> {
24488    type Row = DisplayRow;
24489
24490    fn len(&self) -> usize {
24491        (self.end.0 - self.start.0) as usize
24492    }
24493
24494    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24495        (self.start.0..self.end.0).map(DisplayRow)
24496    }
24497}
24498
24499/// If select range has more than one line, we
24500/// just point the cursor to range.start.
24501fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24502    if range.start.row == range.end.row {
24503        range
24504    } else {
24505        range.start..range.start
24506    }
24507}
24508pub struct KillRing(ClipboardItem);
24509impl Global for KillRing {}
24510
24511const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24512
24513enum BreakpointPromptEditAction {
24514    Log,
24515    Condition,
24516    HitCondition,
24517}
24518
24519struct BreakpointPromptEditor {
24520    pub(crate) prompt: Entity<Editor>,
24521    editor: WeakEntity<Editor>,
24522    breakpoint_anchor: Anchor,
24523    breakpoint: Breakpoint,
24524    edit_action: BreakpointPromptEditAction,
24525    block_ids: HashSet<CustomBlockId>,
24526    editor_margins: Arc<Mutex<EditorMargins>>,
24527    _subscriptions: Vec<Subscription>,
24528}
24529
24530impl BreakpointPromptEditor {
24531    const MAX_LINES: u8 = 4;
24532
24533    fn new(
24534        editor: WeakEntity<Editor>,
24535        breakpoint_anchor: Anchor,
24536        breakpoint: Breakpoint,
24537        edit_action: BreakpointPromptEditAction,
24538        window: &mut Window,
24539        cx: &mut Context<Self>,
24540    ) -> Self {
24541        let base_text = match edit_action {
24542            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24543            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24544            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24545        }
24546        .map(|msg| msg.to_string())
24547        .unwrap_or_default();
24548
24549        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24550        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24551
24552        let prompt = cx.new(|cx| {
24553            let mut prompt = Editor::new(
24554                EditorMode::AutoHeight {
24555                    min_lines: 1,
24556                    max_lines: Some(Self::MAX_LINES as usize),
24557                },
24558                buffer,
24559                None,
24560                window,
24561                cx,
24562            );
24563            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24564            prompt.set_show_cursor_when_unfocused(false, cx);
24565            prompt.set_placeholder_text(
24566                match edit_action {
24567                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24568                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24569                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24570                },
24571                window,
24572                cx,
24573            );
24574
24575            prompt
24576        });
24577
24578        Self {
24579            prompt,
24580            editor,
24581            breakpoint_anchor,
24582            breakpoint,
24583            edit_action,
24584            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24585            block_ids: Default::default(),
24586            _subscriptions: vec![],
24587        }
24588    }
24589
24590    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24591        self.block_ids.extend(block_ids)
24592    }
24593
24594    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24595        if let Some(editor) = self.editor.upgrade() {
24596            let message = self
24597                .prompt
24598                .read(cx)
24599                .buffer
24600                .read(cx)
24601                .as_singleton()
24602                .expect("A multi buffer in breakpoint prompt isn't possible")
24603                .read(cx)
24604                .as_rope()
24605                .to_string();
24606
24607            editor.update(cx, |editor, cx| {
24608                editor.edit_breakpoint_at_anchor(
24609                    self.breakpoint_anchor,
24610                    self.breakpoint.clone(),
24611                    match self.edit_action {
24612                        BreakpointPromptEditAction::Log => {
24613                            BreakpointEditAction::EditLogMessage(message.into())
24614                        }
24615                        BreakpointPromptEditAction::Condition => {
24616                            BreakpointEditAction::EditCondition(message.into())
24617                        }
24618                        BreakpointPromptEditAction::HitCondition => {
24619                            BreakpointEditAction::EditHitCondition(message.into())
24620                        }
24621                    },
24622                    cx,
24623                );
24624
24625                editor.remove_blocks(self.block_ids.clone(), None, cx);
24626                cx.focus_self(window);
24627            });
24628        }
24629    }
24630
24631    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24632        self.editor
24633            .update(cx, |editor, cx| {
24634                editor.remove_blocks(self.block_ids.clone(), None, cx);
24635                window.focus(&editor.focus_handle);
24636            })
24637            .log_err();
24638    }
24639
24640    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24641        let settings = ThemeSettings::get_global(cx);
24642        let text_style = TextStyle {
24643            color: if self.prompt.read(cx).read_only(cx) {
24644                cx.theme().colors().text_disabled
24645            } else {
24646                cx.theme().colors().text
24647            },
24648            font_family: settings.buffer_font.family.clone(),
24649            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24650            font_size: settings.buffer_font_size(cx).into(),
24651            font_weight: settings.buffer_font.weight,
24652            line_height: relative(settings.buffer_line_height.value()),
24653            ..Default::default()
24654        };
24655        EditorElement::new(
24656            &self.prompt,
24657            EditorStyle {
24658                background: cx.theme().colors().editor_background,
24659                local_player: cx.theme().players().local(),
24660                text: text_style,
24661                ..Default::default()
24662            },
24663        )
24664    }
24665}
24666
24667impl Render for BreakpointPromptEditor {
24668    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24669        let editor_margins = *self.editor_margins.lock();
24670        let gutter_dimensions = editor_margins.gutter;
24671        h_flex()
24672            .key_context("Editor")
24673            .bg(cx.theme().colors().editor_background)
24674            .border_y_1()
24675            .border_color(cx.theme().status().info_border)
24676            .size_full()
24677            .py(window.line_height() / 2.5)
24678            .on_action(cx.listener(Self::confirm))
24679            .on_action(cx.listener(Self::cancel))
24680            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24681            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24682    }
24683}
24684
24685impl Focusable for BreakpointPromptEditor {
24686    fn focus_handle(&self, cx: &App) -> FocusHandle {
24687        self.prompt.focus_handle(cx)
24688    }
24689}
24690
24691fn all_edits_insertions_or_deletions(
24692    edits: &Vec<(Range<Anchor>, String)>,
24693    snapshot: &MultiBufferSnapshot,
24694) -> bool {
24695    let mut all_insertions = true;
24696    let mut all_deletions = true;
24697
24698    for (range, new_text) in edits.iter() {
24699        let range_is_empty = range.to_offset(snapshot).is_empty();
24700        let text_is_empty = new_text.is_empty();
24701
24702        if range_is_empty != text_is_empty {
24703            if range_is_empty {
24704                all_deletions = false;
24705            } else {
24706                all_insertions = false;
24707            }
24708        } else {
24709            return false;
24710        }
24711
24712        if !all_insertions && !all_deletions {
24713            return false;
24714        }
24715    }
24716    all_insertions || all_deletions
24717}
24718
24719struct MissingEditPredictionKeybindingTooltip;
24720
24721impl Render for MissingEditPredictionKeybindingTooltip {
24722    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24723        ui::tooltip_container(cx, |container, cx| {
24724            container
24725                .flex_shrink_0()
24726                .max_w_80()
24727                .min_h(rems_from_px(124.))
24728                .justify_between()
24729                .child(
24730                    v_flex()
24731                        .flex_1()
24732                        .text_ui_sm(cx)
24733                        .child(Label::new("Conflict with Accept Keybinding"))
24734                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24735                )
24736                .child(
24737                    h_flex()
24738                        .pb_1()
24739                        .gap_1()
24740                        .items_end()
24741                        .w_full()
24742                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24743                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
24744                        }))
24745                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24746                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24747                        })),
24748                )
24749        })
24750    }
24751}
24752
24753#[derive(Debug, Clone, Copy, PartialEq)]
24754pub struct LineHighlight {
24755    pub background: Background,
24756    pub border: Option<gpui::Hsla>,
24757    pub include_gutter: bool,
24758    pub type_id: Option<TypeId>,
24759}
24760
24761struct LineManipulationResult {
24762    pub new_text: String,
24763    pub line_count_before: usize,
24764    pub line_count_after: usize,
24765}
24766
24767fn render_diff_hunk_controls(
24768    row: u32,
24769    status: &DiffHunkStatus,
24770    hunk_range: Range<Anchor>,
24771    is_created_file: bool,
24772    line_height: Pixels,
24773    editor: &Entity<Editor>,
24774    _window: &mut Window,
24775    cx: &mut App,
24776) -> AnyElement {
24777    h_flex()
24778        .h(line_height)
24779        .mr_1()
24780        .gap_1()
24781        .px_0p5()
24782        .pb_1()
24783        .border_x_1()
24784        .border_b_1()
24785        .border_color(cx.theme().colors().border_variant)
24786        .rounded_b_lg()
24787        .bg(cx.theme().colors().editor_background)
24788        .gap_1()
24789        .block_mouse_except_scroll()
24790        .shadow_md()
24791        .child(if status.has_secondary_hunk() {
24792            Button::new(("stage", row as u64), "Stage")
24793                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24794                .tooltip({
24795                    let focus_handle = editor.focus_handle(cx);
24796                    move |_window, cx| {
24797                        Tooltip::for_action_in(
24798                            "Stage Hunk",
24799                            &::git::ToggleStaged,
24800                            &focus_handle,
24801                            cx,
24802                        )
24803                    }
24804                })
24805                .on_click({
24806                    let editor = editor.clone();
24807                    move |_event, _window, cx| {
24808                        editor.update(cx, |editor, cx| {
24809                            editor.stage_or_unstage_diff_hunks(
24810                                true,
24811                                vec![hunk_range.start..hunk_range.start],
24812                                cx,
24813                            );
24814                        });
24815                    }
24816                })
24817        } else {
24818            Button::new(("unstage", row as u64), "Unstage")
24819                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24820                .tooltip({
24821                    let focus_handle = editor.focus_handle(cx);
24822                    move |_window, cx| {
24823                        Tooltip::for_action_in(
24824                            "Unstage Hunk",
24825                            &::git::ToggleStaged,
24826                            &focus_handle,
24827                            cx,
24828                        )
24829                    }
24830                })
24831                .on_click({
24832                    let editor = editor.clone();
24833                    move |_event, _window, cx| {
24834                        editor.update(cx, |editor, cx| {
24835                            editor.stage_or_unstage_diff_hunks(
24836                                false,
24837                                vec![hunk_range.start..hunk_range.start],
24838                                cx,
24839                            );
24840                        });
24841                    }
24842                })
24843        })
24844        .child(
24845            Button::new(("restore", row as u64), "Restore")
24846                .tooltip({
24847                    let focus_handle = editor.focus_handle(cx);
24848                    move |_window, cx| {
24849                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
24850                    }
24851                })
24852                .on_click({
24853                    let editor = editor.clone();
24854                    move |_event, window, cx| {
24855                        editor.update(cx, |editor, cx| {
24856                            let snapshot = editor.snapshot(window, cx);
24857                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
24858                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24859                        });
24860                    }
24861                })
24862                .disabled(is_created_file),
24863        )
24864        .when(
24865            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24866            |el| {
24867                el.child(
24868                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24869                        .shape(IconButtonShape::Square)
24870                        .icon_size(IconSize::Small)
24871                        // .disabled(!has_multiple_hunks)
24872                        .tooltip({
24873                            let focus_handle = editor.focus_handle(cx);
24874                            move |_window, cx| {
24875                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
24876                            }
24877                        })
24878                        .on_click({
24879                            let editor = editor.clone();
24880                            move |_event, window, cx| {
24881                                editor.update(cx, |editor, cx| {
24882                                    let snapshot = editor.snapshot(window, cx);
24883                                    let position =
24884                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
24885                                    editor.go_to_hunk_before_or_after_position(
24886                                        &snapshot,
24887                                        position,
24888                                        Direction::Next,
24889                                        window,
24890                                        cx,
24891                                    );
24892                                    editor.expand_selected_diff_hunks(cx);
24893                                });
24894                            }
24895                        }),
24896                )
24897                .child(
24898                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24899                        .shape(IconButtonShape::Square)
24900                        .icon_size(IconSize::Small)
24901                        // .disabled(!has_multiple_hunks)
24902                        .tooltip({
24903                            let focus_handle = editor.focus_handle(cx);
24904                            move |_window, cx| {
24905                                Tooltip::for_action_in(
24906                                    "Previous Hunk",
24907                                    &GoToPreviousHunk,
24908                                    &focus_handle,
24909                                    cx,
24910                                )
24911                            }
24912                        })
24913                        .on_click({
24914                            let editor = editor.clone();
24915                            move |_event, window, cx| {
24916                                editor.update(cx, |editor, cx| {
24917                                    let snapshot = editor.snapshot(window, cx);
24918                                    let point =
24919                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
24920                                    editor.go_to_hunk_before_or_after_position(
24921                                        &snapshot,
24922                                        point,
24923                                        Direction::Prev,
24924                                        window,
24925                                        cx,
24926                                    );
24927                                    editor.expand_selected_diff_hunks(cx);
24928                                });
24929                            }
24930                        }),
24931                )
24932            },
24933        )
24934        .into_any_element()
24935}
24936
24937pub fn multibuffer_context_lines(cx: &App) -> u32 {
24938    EditorSettings::try_get(cx)
24939        .map(|settings| settings.excerpt_context_lines)
24940        .unwrap_or(2)
24941        .min(32)
24942}