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>, Arc<str>)>,
  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(Debug, Clone, Copy, PartialEq, Eq)]
  816pub enum BufferSerialization {
  817    All,
  818    NonDirtyBuffers,
  819}
  820
  821impl BufferSerialization {
  822    fn new(restore_unsaved_buffers: bool) -> Self {
  823        if restore_unsaved_buffers {
  824            Self::All
  825        } else {
  826            Self::NonDirtyBuffers
  827        }
  828    }
  829}
  830
  831#[derive(Clone, Debug)]
  832struct RunnableTasks {
  833    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  834    offset: multi_buffer::Anchor,
  835    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  836    column: u32,
  837    // Values of all named captures, including those starting with '_'
  838    extra_variables: HashMap<String, String>,
  839    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  840    context_range: Range<BufferOffset>,
  841}
  842
  843impl RunnableTasks {
  844    fn resolve<'a>(
  845        &'a self,
  846        cx: &'a task::TaskContext,
  847    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  848        self.templates.iter().filter_map(|(kind, template)| {
  849            template
  850                .resolve_task(&kind.to_id_base(), cx)
  851                .map(|task| (kind.clone(), task))
  852        })
  853    }
  854}
  855
  856#[derive(Clone)]
  857pub struct ResolvedTasks {
  858    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  859    position: Anchor,
  860}
  861
  862#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  863struct BufferOffset(usize);
  864
  865/// Addons allow storing per-editor state in other crates (e.g. Vim)
  866pub trait Addon: 'static {
  867    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  868
  869    fn render_buffer_header_controls(
  870        &self,
  871        _: &ExcerptInfo,
  872        _: &Window,
  873        _: &App,
  874    ) -> Option<AnyElement> {
  875        None
  876    }
  877
  878    fn override_status_for_buffer_id(&self, _: BufferId, _: &App) -> Option<FileStatus> {
  879        None
  880    }
  881
  882    fn to_any(&self) -> &dyn std::any::Any;
  883
  884    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  885        None
  886    }
  887}
  888
  889struct ChangeLocation {
  890    current: Option<Vec<Anchor>>,
  891    original: Vec<Anchor>,
  892}
  893impl ChangeLocation {
  894    fn locations(&self) -> &[Anchor] {
  895        self.current.as_ref().unwrap_or(&self.original)
  896    }
  897}
  898
  899/// A set of caret positions, registered when the editor was edited.
  900pub struct ChangeList {
  901    changes: Vec<ChangeLocation>,
  902    /// Currently "selected" change.
  903    position: Option<usize>,
  904}
  905
  906impl ChangeList {
  907    pub fn new() -> Self {
  908        Self {
  909            changes: Vec::new(),
  910            position: None,
  911        }
  912    }
  913
  914    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  915    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  916    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  917        if self.changes.is_empty() {
  918            return None;
  919        }
  920
  921        let prev = self.position.unwrap_or(self.changes.len());
  922        let next = if direction == Direction::Prev {
  923            prev.saturating_sub(count)
  924        } else {
  925            (prev + count).min(self.changes.len() - 1)
  926        };
  927        self.position = Some(next);
  928        self.changes.get(next).map(|change| change.locations())
  929    }
  930
  931    /// Adds a new change to the list, resetting the change list position.
  932    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  933        self.position.take();
  934        if let Some(last) = self.changes.last_mut()
  935            && group
  936        {
  937            last.current = Some(new_positions)
  938        } else {
  939            self.changes.push(ChangeLocation {
  940                original: new_positions,
  941                current: None,
  942            });
  943        }
  944    }
  945
  946    pub fn last(&self) -> Option<&[Anchor]> {
  947        self.changes.last().map(|change| change.locations())
  948    }
  949
  950    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  951        self.changes.last().map(|change| change.original.as_slice())
  952    }
  953
  954    pub fn invert_last_group(&mut self) {
  955        if let Some(last) = self.changes.last_mut()
  956            && let Some(current) = last.current.as_mut()
  957        {
  958            mem::swap(&mut last.original, current);
  959        }
  960    }
  961}
  962
  963#[derive(Clone)]
  964struct InlineBlamePopoverState {
  965    scroll_handle: ScrollHandle,
  966    commit_message: Option<ParsedCommitMessage>,
  967    markdown: Entity<Markdown>,
  968}
  969
  970struct InlineBlamePopover {
  971    position: gpui::Point<Pixels>,
  972    hide_task: Option<Task<()>>,
  973    popover_bounds: Option<Bounds<Pixels>>,
  974    popover_state: InlineBlamePopoverState,
  975    keyboard_grace: bool,
  976}
  977
  978enum SelectionDragState {
  979    /// State when no drag related activity is detected.
  980    None,
  981    /// State when the mouse is down on a selection that is about to be dragged.
  982    ReadyToDrag {
  983        selection: Selection<Anchor>,
  984        click_position: gpui::Point<Pixels>,
  985        mouse_down_time: Instant,
  986    },
  987    /// State when the mouse is dragging the selection in the editor.
  988    Dragging {
  989        selection: Selection<Anchor>,
  990        drop_cursor: Selection<Anchor>,
  991        hide_drop_cursor: bool,
  992    },
  993}
  994
  995enum ColumnarSelectionState {
  996    FromMouse {
  997        selection_tail: Anchor,
  998        display_point: Option<DisplayPoint>,
  999    },
 1000    FromSelection {
 1001        selection_tail: Anchor,
 1002    },
 1003}
 1004
 1005/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1006/// a breakpoint on them.
 1007#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1008struct PhantomBreakpointIndicator {
 1009    display_row: DisplayRow,
 1010    /// There's a small debounce between hovering over the line and showing the indicator.
 1011    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1012    is_active: bool,
 1013    collides_with_existing_breakpoint: bool,
 1014}
 1015
 1016/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1017///
 1018/// See the [module level documentation](self) for more information.
 1019pub struct Editor {
 1020    focus_handle: FocusHandle,
 1021    last_focused_descendant: Option<WeakFocusHandle>,
 1022    /// The text buffer being edited
 1023    buffer: Entity<MultiBuffer>,
 1024    /// Map of how text in the buffer should be displayed.
 1025    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1026    pub display_map: Entity<DisplayMap>,
 1027    placeholder_display_map: Option<Entity<DisplayMap>>,
 1028    pub selections: SelectionsCollection,
 1029    pub scroll_manager: ScrollManager,
 1030    /// When inline assist editors are linked, they all render cursors because
 1031    /// typing enters text into each of them, even the ones that aren't focused.
 1032    pub(crate) show_cursor_when_unfocused: bool,
 1033    columnar_selection_state: Option<ColumnarSelectionState>,
 1034    add_selections_state: Option<AddSelectionsState>,
 1035    select_next_state: Option<SelectNextState>,
 1036    select_prev_state: Option<SelectNextState>,
 1037    selection_history: SelectionHistory,
 1038    defer_selection_effects: bool,
 1039    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1040    autoclose_regions: Vec<AutocloseRegion>,
 1041    snippet_stack: InvalidationStack<SnippetState>,
 1042    select_syntax_node_history: SelectSyntaxNodeHistory,
 1043    ime_transaction: Option<TransactionId>,
 1044    pub diagnostics_max_severity: DiagnosticSeverity,
 1045    active_diagnostics: ActiveDiagnostic,
 1046    show_inline_diagnostics: bool,
 1047    inline_diagnostics_update: Task<()>,
 1048    inline_diagnostics_enabled: bool,
 1049    diagnostics_enabled: bool,
 1050    word_completions_enabled: bool,
 1051    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1052    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1053    hard_wrap: Option<usize>,
 1054    project: Option<Entity<Project>>,
 1055    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1056    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1057    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1058    blink_manager: Entity<BlinkManager>,
 1059    show_cursor_names: bool,
 1060    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1061    pub show_local_selections: bool,
 1062    mode: EditorMode,
 1063    show_breadcrumbs: bool,
 1064    show_gutter: bool,
 1065    show_scrollbars: ScrollbarAxes,
 1066    minimap_visibility: MinimapVisibility,
 1067    offset_content: bool,
 1068    disable_expand_excerpt_buttons: bool,
 1069    show_line_numbers: Option<bool>,
 1070    use_relative_line_numbers: Option<bool>,
 1071    show_git_diff_gutter: Option<bool>,
 1072    show_code_actions: Option<bool>,
 1073    show_runnables: Option<bool>,
 1074    show_breakpoints: Option<bool>,
 1075    show_wrap_guides: Option<bool>,
 1076    show_indent_guides: Option<bool>,
 1077    highlight_order: usize,
 1078    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1079    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1080    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1081    scrollbar_marker_state: ScrollbarMarkerState,
 1082    active_indent_guides_state: ActiveIndentGuidesState,
 1083    nav_history: Option<ItemNavHistory>,
 1084    context_menu: RefCell<Option<CodeContextMenu>>,
 1085    context_menu_options: Option<ContextMenuOptions>,
 1086    mouse_context_menu: Option<MouseContextMenu>,
 1087    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1088    inline_blame_popover: Option<InlineBlamePopover>,
 1089    inline_blame_popover_show_task: Option<Task<()>>,
 1090    signature_help_state: SignatureHelpState,
 1091    auto_signature_help: Option<bool>,
 1092    find_all_references_task_sources: Vec<Anchor>,
 1093    next_completion_id: CompletionId,
 1094    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1095    code_actions_task: Option<Task<Result<()>>>,
 1096    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1097    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1098    document_highlights_task: Option<Task<()>>,
 1099    linked_editing_range_task: Option<Task<Option<()>>>,
 1100    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1101    pending_rename: Option<RenameState>,
 1102    searchable: bool,
 1103    cursor_shape: CursorShape,
 1104    current_line_highlight: Option<CurrentLineHighlight>,
 1105    autoindent_mode: Option<AutoindentMode>,
 1106    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1107    input_enabled: bool,
 1108    use_modal_editing: bool,
 1109    read_only: bool,
 1110    leader_id: Option<CollaboratorId>,
 1111    remote_id: Option<ViewId>,
 1112    pub hover_state: HoverState,
 1113    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1114    gutter_hovered: bool,
 1115    hovered_link_state: Option<HoveredLinkState>,
 1116    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1117    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1118    active_edit_prediction: Option<EditPredictionState>,
 1119    /// Used to prevent flickering as the user types while the menu is open
 1120    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1121    edit_prediction_settings: EditPredictionSettings,
 1122    edit_predictions_hidden_for_vim_mode: bool,
 1123    show_edit_predictions_override: Option<bool>,
 1124    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1125    edit_prediction_preview: EditPredictionPreview,
 1126    edit_prediction_indent_conflict: bool,
 1127    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1128    next_inlay_id: usize,
 1129    next_color_inlay_id: usize,
 1130    _subscriptions: Vec<Subscription>,
 1131    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1132    gutter_dimensions: GutterDimensions,
 1133    style: Option<EditorStyle>,
 1134    text_style_refinement: Option<TextStyleRefinement>,
 1135    next_editor_action_id: EditorActionId,
 1136    editor_actions: Rc<
 1137        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1138    >,
 1139    use_autoclose: bool,
 1140    use_auto_surround: bool,
 1141    auto_replace_emoji_shortcode: bool,
 1142    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1143    show_git_blame_gutter: bool,
 1144    show_git_blame_inline: bool,
 1145    show_git_blame_inline_delay_task: Option<Task<()>>,
 1146    git_blame_inline_enabled: bool,
 1147    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1148    buffer_serialization: Option<BufferSerialization>,
 1149    show_selection_menu: Option<bool>,
 1150    blame: Option<Entity<GitBlame>>,
 1151    blame_subscription: Option<Subscription>,
 1152    custom_context_menu: Option<
 1153        Box<
 1154            dyn 'static
 1155                + Fn(
 1156                    &mut Self,
 1157                    DisplayPoint,
 1158                    &mut Window,
 1159                    &mut Context<Self>,
 1160                ) -> Option<Entity<ui::ContextMenu>>,
 1161        >,
 1162    >,
 1163    last_bounds: Option<Bounds<Pixels>>,
 1164    last_position_map: Option<Rc<PositionMap>>,
 1165    expect_bounds_change: Option<Bounds<Pixels>>,
 1166    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1167    tasks_update_task: Option<Task<()>>,
 1168    breakpoint_store: Option<Entity<BreakpointStore>>,
 1169    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1170    hovered_diff_hunk_row: Option<DisplayRow>,
 1171    pull_diagnostics_task: Task<()>,
 1172    in_project_search: bool,
 1173    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1174    breadcrumb_header: Option<String>,
 1175    focused_block: Option<FocusedBlock>,
 1176    next_scroll_position: NextScrollCursorCenterTopBottom,
 1177    addons: HashMap<TypeId, Box<dyn Addon>>,
 1178    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1179    load_diff_task: Option<Shared<Task<()>>>,
 1180    /// Whether we are temporarily displaying a diff other than git's
 1181    temporary_diff_override: bool,
 1182    selection_mark_mode: bool,
 1183    toggle_fold_multiple_buffers: Task<()>,
 1184    _scroll_cursor_center_top_bottom_task: Task<()>,
 1185    serialize_selections: Task<()>,
 1186    serialize_folds: Task<()>,
 1187    mouse_cursor_hidden: bool,
 1188    minimap: Option<Entity<Self>>,
 1189    hide_mouse_mode: HideMouseMode,
 1190    pub change_list: ChangeList,
 1191    inline_value_cache: InlineValueCache,
 1192    selection_drag_state: SelectionDragState,
 1193    colors: Option<LspColorData>,
 1194    post_scroll_update: Task<()>,
 1195    refresh_colors_task: Task<()>,
 1196    inlay_hints: Option<LspInlayHintData>,
 1197    folding_newlines: Task<()>,
 1198    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1199}
 1200
 1201fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1202    if debounce_ms > 0 {
 1203        Some(Duration::from_millis(debounce_ms))
 1204    } else {
 1205        None
 1206    }
 1207}
 1208
 1209#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1210enum NextScrollCursorCenterTopBottom {
 1211    #[default]
 1212    Center,
 1213    Top,
 1214    Bottom,
 1215}
 1216
 1217impl NextScrollCursorCenterTopBottom {
 1218    fn next(&self) -> Self {
 1219        match self {
 1220            Self::Center => Self::Top,
 1221            Self::Top => Self::Bottom,
 1222            Self::Bottom => Self::Center,
 1223        }
 1224    }
 1225}
 1226
 1227#[derive(Clone)]
 1228pub struct EditorSnapshot {
 1229    pub mode: EditorMode,
 1230    show_gutter: bool,
 1231    show_line_numbers: Option<bool>,
 1232    show_git_diff_gutter: Option<bool>,
 1233    show_code_actions: Option<bool>,
 1234    show_runnables: Option<bool>,
 1235    show_breakpoints: Option<bool>,
 1236    git_blame_gutter_max_author_length: Option<usize>,
 1237    pub display_snapshot: DisplaySnapshot,
 1238    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1239    is_focused: bool,
 1240    scroll_anchor: ScrollAnchor,
 1241    ongoing_scroll: OngoingScroll,
 1242    current_line_highlight: CurrentLineHighlight,
 1243    gutter_hovered: bool,
 1244}
 1245
 1246#[derive(Default, Debug, Clone, Copy)]
 1247pub struct GutterDimensions {
 1248    pub left_padding: Pixels,
 1249    pub right_padding: Pixels,
 1250    pub width: Pixels,
 1251    pub margin: Pixels,
 1252    pub git_blame_entries_width: Option<Pixels>,
 1253}
 1254
 1255impl GutterDimensions {
 1256    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1257        Self {
 1258            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1259            ..Default::default()
 1260        }
 1261    }
 1262
 1263    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1264        -cx.text_system().descent(font_id, font_size)
 1265    }
 1266    /// The full width of the space taken up by the gutter.
 1267    pub fn full_width(&self) -> Pixels {
 1268        self.margin + self.width
 1269    }
 1270
 1271    /// The width of the space reserved for the fold indicators,
 1272    /// use alongside 'justify_end' and `gutter_width` to
 1273    /// right align content with the line numbers
 1274    pub fn fold_area_width(&self) -> Pixels {
 1275        self.margin + self.right_padding
 1276    }
 1277}
 1278
 1279struct CharacterDimensions {
 1280    em_width: Pixels,
 1281    em_advance: Pixels,
 1282    line_height: Pixels,
 1283}
 1284
 1285#[derive(Debug)]
 1286pub struct RemoteSelection {
 1287    pub replica_id: ReplicaId,
 1288    pub selection: Selection<Anchor>,
 1289    pub cursor_shape: CursorShape,
 1290    pub collaborator_id: CollaboratorId,
 1291    pub line_mode: bool,
 1292    pub user_name: Option<SharedString>,
 1293    pub color: PlayerColor,
 1294}
 1295
 1296#[derive(Clone, Debug)]
 1297struct SelectionHistoryEntry {
 1298    selections: Arc<[Selection<Anchor>]>,
 1299    select_next_state: Option<SelectNextState>,
 1300    select_prev_state: Option<SelectNextState>,
 1301    add_selections_state: Option<AddSelectionsState>,
 1302}
 1303
 1304#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1305enum SelectionHistoryMode {
 1306    Normal,
 1307    Undoing,
 1308    Redoing,
 1309    Skipping,
 1310}
 1311
 1312#[derive(Clone, PartialEq, Eq, Hash)]
 1313struct HoveredCursor {
 1314    replica_id: ReplicaId,
 1315    selection_id: usize,
 1316}
 1317
 1318impl Default for SelectionHistoryMode {
 1319    fn default() -> Self {
 1320        Self::Normal
 1321    }
 1322}
 1323
 1324#[derive(Debug)]
 1325/// SelectionEffects controls the side-effects of updating the selection.
 1326///
 1327/// The default behaviour does "what you mostly want":
 1328/// - it pushes to the nav history if the cursor moved by >10 lines
 1329/// - it re-triggers completion requests
 1330/// - it scrolls to fit
 1331///
 1332/// You might want to modify these behaviours. For example when doing a "jump"
 1333/// like go to definition, we always want to add to nav history; but when scrolling
 1334/// in vim mode we never do.
 1335///
 1336/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1337/// move.
 1338#[derive(Clone)]
 1339pub struct SelectionEffects {
 1340    nav_history: Option<bool>,
 1341    completions: bool,
 1342    scroll: Option<Autoscroll>,
 1343}
 1344
 1345impl Default for SelectionEffects {
 1346    fn default() -> Self {
 1347        Self {
 1348            nav_history: None,
 1349            completions: true,
 1350            scroll: Some(Autoscroll::fit()),
 1351        }
 1352    }
 1353}
 1354impl SelectionEffects {
 1355    pub fn scroll(scroll: Autoscroll) -> Self {
 1356        Self {
 1357            scroll: Some(scroll),
 1358            ..Default::default()
 1359        }
 1360    }
 1361
 1362    pub fn no_scroll() -> Self {
 1363        Self {
 1364            scroll: None,
 1365            ..Default::default()
 1366        }
 1367    }
 1368
 1369    pub fn completions(self, completions: bool) -> Self {
 1370        Self {
 1371            completions,
 1372            ..self
 1373        }
 1374    }
 1375
 1376    pub fn nav_history(self, nav_history: bool) -> Self {
 1377        Self {
 1378            nav_history: Some(nav_history),
 1379            ..self
 1380        }
 1381    }
 1382}
 1383
 1384struct DeferredSelectionEffectsState {
 1385    changed: bool,
 1386    effects: SelectionEffects,
 1387    old_cursor_position: Anchor,
 1388    history_entry: SelectionHistoryEntry,
 1389}
 1390
 1391#[derive(Default)]
 1392struct SelectionHistory {
 1393    #[allow(clippy::type_complexity)]
 1394    selections_by_transaction:
 1395        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1396    mode: SelectionHistoryMode,
 1397    undo_stack: VecDeque<SelectionHistoryEntry>,
 1398    redo_stack: VecDeque<SelectionHistoryEntry>,
 1399}
 1400
 1401impl SelectionHistory {
 1402    #[track_caller]
 1403    fn insert_transaction(
 1404        &mut self,
 1405        transaction_id: TransactionId,
 1406        selections: Arc<[Selection<Anchor>]>,
 1407    ) {
 1408        if selections.is_empty() {
 1409            log::error!(
 1410                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1411                std::panic::Location::caller()
 1412            );
 1413            return;
 1414        }
 1415        self.selections_by_transaction
 1416            .insert(transaction_id, (selections, None));
 1417    }
 1418
 1419    #[allow(clippy::type_complexity)]
 1420    fn transaction(
 1421        &self,
 1422        transaction_id: TransactionId,
 1423    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1424        self.selections_by_transaction.get(&transaction_id)
 1425    }
 1426
 1427    #[allow(clippy::type_complexity)]
 1428    fn transaction_mut(
 1429        &mut self,
 1430        transaction_id: TransactionId,
 1431    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1432        self.selections_by_transaction.get_mut(&transaction_id)
 1433    }
 1434
 1435    fn push(&mut self, entry: SelectionHistoryEntry) {
 1436        if !entry.selections.is_empty() {
 1437            match self.mode {
 1438                SelectionHistoryMode::Normal => {
 1439                    self.push_undo(entry);
 1440                    self.redo_stack.clear();
 1441                }
 1442                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1443                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1444                SelectionHistoryMode::Skipping => {}
 1445            }
 1446        }
 1447    }
 1448
 1449    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1450        if self
 1451            .undo_stack
 1452            .back()
 1453            .is_none_or(|e| e.selections != entry.selections)
 1454        {
 1455            self.undo_stack.push_back(entry);
 1456            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1457                self.undo_stack.pop_front();
 1458            }
 1459        }
 1460    }
 1461
 1462    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1463        if self
 1464            .redo_stack
 1465            .back()
 1466            .is_none_or(|e| e.selections != entry.selections)
 1467        {
 1468            self.redo_stack.push_back(entry);
 1469            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1470                self.redo_stack.pop_front();
 1471            }
 1472        }
 1473    }
 1474}
 1475
 1476#[derive(Clone, Copy)]
 1477pub struct RowHighlightOptions {
 1478    pub autoscroll: bool,
 1479    pub include_gutter: bool,
 1480}
 1481
 1482impl Default for RowHighlightOptions {
 1483    fn default() -> Self {
 1484        Self {
 1485            autoscroll: Default::default(),
 1486            include_gutter: true,
 1487        }
 1488    }
 1489}
 1490
 1491struct RowHighlight {
 1492    index: usize,
 1493    range: Range<Anchor>,
 1494    color: Hsla,
 1495    options: RowHighlightOptions,
 1496    type_id: TypeId,
 1497}
 1498
 1499#[derive(Clone, Debug)]
 1500struct AddSelectionsState {
 1501    groups: Vec<AddSelectionsGroup>,
 1502}
 1503
 1504#[derive(Clone, Debug)]
 1505struct AddSelectionsGroup {
 1506    above: bool,
 1507    stack: Vec<usize>,
 1508}
 1509
 1510#[derive(Clone)]
 1511struct SelectNextState {
 1512    query: AhoCorasick,
 1513    wordwise: bool,
 1514    done: bool,
 1515}
 1516
 1517impl std::fmt::Debug for SelectNextState {
 1518    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1519        f.debug_struct(std::any::type_name::<Self>())
 1520            .field("wordwise", &self.wordwise)
 1521            .field("done", &self.done)
 1522            .finish()
 1523    }
 1524}
 1525
 1526#[derive(Debug)]
 1527struct AutocloseRegion {
 1528    selection_id: usize,
 1529    range: Range<Anchor>,
 1530    pair: BracketPair,
 1531}
 1532
 1533#[derive(Debug)]
 1534struct SnippetState {
 1535    ranges: Vec<Vec<Range<Anchor>>>,
 1536    active_index: usize,
 1537    choices: Vec<Option<Vec<String>>>,
 1538}
 1539
 1540#[doc(hidden)]
 1541pub struct RenameState {
 1542    pub range: Range<Anchor>,
 1543    pub old_name: Arc<str>,
 1544    pub editor: Entity<Editor>,
 1545    block_id: CustomBlockId,
 1546}
 1547
 1548struct InvalidationStack<T>(Vec<T>);
 1549
 1550struct RegisteredEditPredictionProvider {
 1551    provider: Arc<dyn EditPredictionProviderHandle>,
 1552    _subscription: Subscription,
 1553}
 1554
 1555#[derive(Debug, PartialEq, Eq)]
 1556pub struct ActiveDiagnosticGroup {
 1557    pub active_range: Range<Anchor>,
 1558    pub active_message: String,
 1559    pub group_id: usize,
 1560    pub blocks: HashSet<CustomBlockId>,
 1561}
 1562
 1563#[derive(Debug, PartialEq, Eq)]
 1564
 1565pub(crate) enum ActiveDiagnostic {
 1566    None,
 1567    All,
 1568    Group(ActiveDiagnosticGroup),
 1569}
 1570
 1571#[derive(Serialize, Deserialize, Clone, Debug)]
 1572pub struct ClipboardSelection {
 1573    /// The number of bytes in this selection.
 1574    pub len: usize,
 1575    /// Whether this was a full-line selection.
 1576    pub is_entire_line: bool,
 1577    /// The indentation of the first line when this content was originally copied.
 1578    pub first_line_indent: u32,
 1579}
 1580
 1581// selections, scroll behavior, was newest selection reversed
 1582type SelectSyntaxNodeHistoryState = (
 1583    Box<[Selection<usize>]>,
 1584    SelectSyntaxNodeScrollBehavior,
 1585    bool,
 1586);
 1587
 1588#[derive(Default)]
 1589struct SelectSyntaxNodeHistory {
 1590    stack: Vec<SelectSyntaxNodeHistoryState>,
 1591    // disable temporarily to allow changing selections without losing the stack
 1592    pub disable_clearing: bool,
 1593}
 1594
 1595impl SelectSyntaxNodeHistory {
 1596    pub fn try_clear(&mut self) {
 1597        if !self.disable_clearing {
 1598            self.stack.clear();
 1599        }
 1600    }
 1601
 1602    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1603        self.stack.push(selection);
 1604    }
 1605
 1606    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1607        self.stack.pop()
 1608    }
 1609}
 1610
 1611enum SelectSyntaxNodeScrollBehavior {
 1612    CursorTop,
 1613    FitSelection,
 1614    CursorBottom,
 1615}
 1616
 1617#[derive(Debug)]
 1618pub(crate) struct NavigationData {
 1619    cursor_anchor: Anchor,
 1620    cursor_position: Point,
 1621    scroll_anchor: ScrollAnchor,
 1622    scroll_top_row: u32,
 1623}
 1624
 1625#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1626pub enum GotoDefinitionKind {
 1627    Symbol,
 1628    Declaration,
 1629    Type,
 1630    Implementation,
 1631}
 1632
 1633pub enum FormatTarget {
 1634    Buffers(HashSet<Entity<Buffer>>),
 1635    Ranges(Vec<Range<MultiBufferPoint>>),
 1636}
 1637
 1638pub(crate) struct FocusedBlock {
 1639    id: BlockId,
 1640    focus_handle: WeakFocusHandle,
 1641}
 1642
 1643#[derive(Clone)]
 1644enum JumpData {
 1645    MultiBufferRow {
 1646        row: MultiBufferRow,
 1647        line_offset_from_top: u32,
 1648    },
 1649    MultiBufferPoint {
 1650        excerpt_id: ExcerptId,
 1651        position: Point,
 1652        anchor: text::Anchor,
 1653        line_offset_from_top: u32,
 1654    },
 1655}
 1656
 1657pub enum MultibufferSelectionMode {
 1658    First,
 1659    All,
 1660}
 1661
 1662#[derive(Clone, Copy, Debug, Default)]
 1663pub struct RewrapOptions {
 1664    pub override_language_settings: bool,
 1665    pub preserve_existing_whitespace: bool,
 1666}
 1667
 1668impl Editor {
 1669    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1670        let buffer = cx.new(|cx| Buffer::local("", cx));
 1671        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1672        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1673    }
 1674
 1675    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1676        let buffer = cx.new(|cx| Buffer::local("", cx));
 1677        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1678        Self::new(EditorMode::full(), buffer, None, window, cx)
 1679    }
 1680
 1681    pub fn auto_height(
 1682        min_lines: usize,
 1683        max_lines: usize,
 1684        window: &mut Window,
 1685        cx: &mut Context<Self>,
 1686    ) -> Self {
 1687        let buffer = cx.new(|cx| Buffer::local("", cx));
 1688        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1689        Self::new(
 1690            EditorMode::AutoHeight {
 1691                min_lines,
 1692                max_lines: Some(max_lines),
 1693            },
 1694            buffer,
 1695            None,
 1696            window,
 1697            cx,
 1698        )
 1699    }
 1700
 1701    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1702    /// The editor grows as tall as needed to fit its content.
 1703    pub fn auto_height_unbounded(
 1704        min_lines: usize,
 1705        window: &mut Window,
 1706        cx: &mut Context<Self>,
 1707    ) -> Self {
 1708        let buffer = cx.new(|cx| Buffer::local("", cx));
 1709        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1710        Self::new(
 1711            EditorMode::AutoHeight {
 1712                min_lines,
 1713                max_lines: None,
 1714            },
 1715            buffer,
 1716            None,
 1717            window,
 1718            cx,
 1719        )
 1720    }
 1721
 1722    pub fn for_buffer(
 1723        buffer: Entity<Buffer>,
 1724        project: Option<Entity<Project>>,
 1725        window: &mut Window,
 1726        cx: &mut Context<Self>,
 1727    ) -> Self {
 1728        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1729        Self::new(EditorMode::full(), buffer, project, window, cx)
 1730    }
 1731
 1732    pub fn for_multibuffer(
 1733        buffer: Entity<MultiBuffer>,
 1734        project: Option<Entity<Project>>,
 1735        window: &mut Window,
 1736        cx: &mut Context<Self>,
 1737    ) -> Self {
 1738        Self::new(EditorMode::full(), buffer, project, window, cx)
 1739    }
 1740
 1741    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1742        let mut clone = Self::new(
 1743            self.mode.clone(),
 1744            self.buffer.clone(),
 1745            self.project.clone(),
 1746            window,
 1747            cx,
 1748        );
 1749        self.display_map.update(cx, |display_map, cx| {
 1750            let snapshot = display_map.snapshot(cx);
 1751            clone.display_map.update(cx, |display_map, cx| {
 1752                display_map.set_state(&snapshot, cx);
 1753            });
 1754        });
 1755        clone.folds_did_change(cx);
 1756        clone.selections.clone_state(&self.selections);
 1757        clone.scroll_manager.clone_state(&self.scroll_manager);
 1758        clone.searchable = self.searchable;
 1759        clone.read_only = self.read_only;
 1760        clone
 1761    }
 1762
 1763    pub fn new(
 1764        mode: EditorMode,
 1765        buffer: Entity<MultiBuffer>,
 1766        project: Option<Entity<Project>>,
 1767        window: &mut Window,
 1768        cx: &mut Context<Self>,
 1769    ) -> Self {
 1770        Editor::new_internal(mode, buffer, project, None, window, cx)
 1771    }
 1772
 1773    fn new_internal(
 1774        mode: EditorMode,
 1775        multi_buffer: Entity<MultiBuffer>,
 1776        project: Option<Entity<Project>>,
 1777        display_map: Option<Entity<DisplayMap>>,
 1778        window: &mut Window,
 1779        cx: &mut Context<Self>,
 1780    ) -> Self {
 1781        debug_assert!(
 1782            display_map.is_none() || mode.is_minimap(),
 1783            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1784        );
 1785
 1786        let full_mode = mode.is_full();
 1787        let is_minimap = mode.is_minimap();
 1788        let diagnostics_max_severity = if full_mode {
 1789            EditorSettings::get_global(cx)
 1790                .diagnostics_max_severity
 1791                .unwrap_or(DiagnosticSeverity::Hint)
 1792        } else {
 1793            DiagnosticSeverity::Off
 1794        };
 1795        let style = window.text_style();
 1796        let font_size = style.font_size.to_pixels(window.rem_size());
 1797        let editor = cx.entity().downgrade();
 1798        let fold_placeholder = FoldPlaceholder {
 1799            constrain_width: false,
 1800            render: Arc::new(move |fold_id, fold_range, cx| {
 1801                let editor = editor.clone();
 1802                div()
 1803                    .id(fold_id)
 1804                    .bg(cx.theme().colors().ghost_element_background)
 1805                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1806                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1807                    .rounded_xs()
 1808                    .size_full()
 1809                    .cursor_pointer()
 1810                    .child("")
 1811                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1812                    .on_click(move |_, _window, cx| {
 1813                        editor
 1814                            .update(cx, |editor, cx| {
 1815                                editor.unfold_ranges(
 1816                                    &[fold_range.start..fold_range.end],
 1817                                    true,
 1818                                    false,
 1819                                    cx,
 1820                                );
 1821                                cx.stop_propagation();
 1822                            })
 1823                            .ok();
 1824                    })
 1825                    .into_any()
 1826            }),
 1827            merge_adjacent: true,
 1828            ..FoldPlaceholder::default()
 1829        };
 1830        let display_map = display_map.unwrap_or_else(|| {
 1831            cx.new(|cx| {
 1832                DisplayMap::new(
 1833                    multi_buffer.clone(),
 1834                    style.font(),
 1835                    font_size,
 1836                    None,
 1837                    FILE_HEADER_HEIGHT,
 1838                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1839                    fold_placeholder,
 1840                    diagnostics_max_severity,
 1841                    cx,
 1842                )
 1843            })
 1844        });
 1845
 1846        let selections = SelectionsCollection::new(display_map.clone(), multi_buffer.clone());
 1847
 1848        let blink_manager = cx.new(|cx| {
 1849            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1850            if is_minimap {
 1851                blink_manager.disable(cx);
 1852            }
 1853            blink_manager
 1854        });
 1855
 1856        let soft_wrap_mode_override =
 1857            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1858
 1859        let mut project_subscriptions = Vec::new();
 1860        if full_mode && let Some(project) = project.as_ref() {
 1861            project_subscriptions.push(cx.subscribe_in(
 1862                project,
 1863                window,
 1864                |editor, _, event, window, cx| match event {
 1865                    project::Event::RefreshCodeLens => {
 1866                        // we always query lens with actions, without storing them, always refreshing them
 1867                    }
 1868                    project::Event::RefreshInlayHints {
 1869                        server_id,
 1870                        request_id,
 1871                    } => {
 1872                        editor.refresh_inlay_hints(
 1873                            InlayHintRefreshReason::RefreshRequested {
 1874                                server_id: *server_id,
 1875                                request_id: *request_id,
 1876                            },
 1877                            cx,
 1878                        );
 1879                    }
 1880                    project::Event::LanguageServerRemoved(..) => {
 1881                        if editor.tasks_update_task.is_none() {
 1882                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1883                        }
 1884                        editor.registered_buffers.clear();
 1885                        editor.register_visible_buffers(cx);
 1886                    }
 1887                    project::Event::LanguageServerAdded(..) => {
 1888                        if editor.tasks_update_task.is_none() {
 1889                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1890                        }
 1891                    }
 1892                    project::Event::SnippetEdit(id, snippet_edits) => {
 1893                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1894                            let focus_handle = editor.focus_handle(cx);
 1895                            if focus_handle.is_focused(window) {
 1896                                let snapshot = buffer.read(cx).snapshot();
 1897                                for (range, snippet) in snippet_edits {
 1898                                    let editor_range =
 1899                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1900                                    editor
 1901                                        .insert_snippet(
 1902                                            &[editor_range],
 1903                                            snippet.clone(),
 1904                                            window,
 1905                                            cx,
 1906                                        )
 1907                                        .ok();
 1908                                }
 1909                            }
 1910                        }
 1911                    }
 1912                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1913                        let buffer_id = *buffer_id;
 1914                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 1915                            editor.register_buffer(buffer_id, cx);
 1916                            editor.update_lsp_data(Some(buffer_id), window, cx);
 1917                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 1918                            refresh_linked_ranges(editor, window, cx);
 1919                            editor.refresh_code_actions(window, cx);
 1920                            editor.refresh_document_highlights(cx);
 1921                        }
 1922                    }
 1923
 1924                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 1925                        let Some(workspace) = editor.workspace() else {
 1926                            return;
 1927                        };
 1928                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1929                        else {
 1930                            return;
 1931                        };
 1932
 1933                        if active_editor.entity_id() == cx.entity_id() {
 1934                            let entity_id = cx.entity_id();
 1935                            workspace.update(cx, |this, cx| {
 1936                                this.panes_mut()
 1937                                    .iter_mut()
 1938                                    .filter(|pane| pane.entity_id() != entity_id)
 1939                                    .for_each(|p| {
 1940                                        p.update(cx, |pane, _| {
 1941                                            pane.nav_history_mut().rename_item(
 1942                                                entity_id,
 1943                                                project_path.clone(),
 1944                                                abs_path.clone().into(),
 1945                                            );
 1946                                        })
 1947                                    });
 1948                            });
 1949                            let edited_buffers_already_open = {
 1950                                let other_editors: Vec<Entity<Editor>> = workspace
 1951                                    .read(cx)
 1952                                    .panes()
 1953                                    .iter()
 1954                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1955                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1956                                    .collect();
 1957
 1958                                transaction.0.keys().all(|buffer| {
 1959                                    other_editors.iter().any(|editor| {
 1960                                        let multi_buffer = editor.read(cx).buffer();
 1961                                        multi_buffer.read(cx).is_singleton()
 1962                                            && multi_buffer.read(cx).as_singleton().map_or(
 1963                                                false,
 1964                                                |singleton| {
 1965                                                    singleton.entity_id() == buffer.entity_id()
 1966                                                },
 1967                                            )
 1968                                    })
 1969                                })
 1970                            };
 1971                            if !edited_buffers_already_open {
 1972                                let workspace = workspace.downgrade();
 1973                                let transaction = transaction.clone();
 1974                                cx.defer_in(window, move |_, window, cx| {
 1975                                    cx.spawn_in(window, async move |editor, cx| {
 1976                                        Self::open_project_transaction(
 1977                                            &editor,
 1978                                            workspace,
 1979                                            transaction,
 1980                                            "Rename".to_string(),
 1981                                            cx,
 1982                                        )
 1983                                        .await
 1984                                        .ok()
 1985                                    })
 1986                                    .detach();
 1987                                });
 1988                            }
 1989                        }
 1990                    }
 1991
 1992                    _ => {}
 1993                },
 1994            ));
 1995            if let Some(task_inventory) = project
 1996                .read(cx)
 1997                .task_store()
 1998                .read(cx)
 1999                .task_inventory()
 2000                .cloned()
 2001            {
 2002                project_subscriptions.push(cx.observe_in(
 2003                    &task_inventory,
 2004                    window,
 2005                    |editor, _, window, cx| {
 2006                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2007                    },
 2008                ));
 2009            };
 2010
 2011            project_subscriptions.push(cx.subscribe_in(
 2012                &project.read(cx).breakpoint_store(),
 2013                window,
 2014                |editor, _, event, window, cx| match event {
 2015                    BreakpointStoreEvent::ClearDebugLines => {
 2016                        editor.clear_row_highlights::<ActiveDebugLine>();
 2017                        editor.refresh_inline_values(cx);
 2018                    }
 2019                    BreakpointStoreEvent::SetDebugLine => {
 2020                        if editor.go_to_active_debug_line(window, cx) {
 2021                            cx.stop_propagation();
 2022                        }
 2023
 2024                        editor.refresh_inline_values(cx);
 2025                    }
 2026                    _ => {}
 2027                },
 2028            ));
 2029            let git_store = project.read(cx).git_store().clone();
 2030            let project = project.clone();
 2031            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2032                if let GitStoreEvent::RepositoryAdded = event {
 2033                    this.load_diff_task = Some(
 2034                        update_uncommitted_diff_for_buffer(
 2035                            cx.entity(),
 2036                            &project,
 2037                            this.buffer.read(cx).all_buffers(),
 2038                            this.buffer.clone(),
 2039                            cx,
 2040                        )
 2041                        .shared(),
 2042                    );
 2043                }
 2044            }));
 2045        }
 2046
 2047        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2048
 2049        let inlay_hint_settings =
 2050            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2051        let focus_handle = cx.focus_handle();
 2052        if !is_minimap {
 2053            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2054                .detach();
 2055            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2056                .detach();
 2057            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2058                .detach();
 2059            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2060                .detach();
 2061            cx.observe_pending_input(window, Self::observe_pending_input)
 2062                .detach();
 2063        }
 2064
 2065        let show_indent_guides =
 2066            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2067                Some(false)
 2068            } else {
 2069                None
 2070            };
 2071
 2072        let breakpoint_store = match (&mode, project.as_ref()) {
 2073            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2074            _ => None,
 2075        };
 2076
 2077        let mut code_action_providers = Vec::new();
 2078        let mut load_uncommitted_diff = None;
 2079        if let Some(project) = project.clone() {
 2080            load_uncommitted_diff = Some(
 2081                update_uncommitted_diff_for_buffer(
 2082                    cx.entity(),
 2083                    &project,
 2084                    multi_buffer.read(cx).all_buffers(),
 2085                    multi_buffer.clone(),
 2086                    cx,
 2087                )
 2088                .shared(),
 2089            );
 2090            code_action_providers.push(Rc::new(project) as Rc<_>);
 2091        }
 2092
 2093        let mut editor = Self {
 2094            focus_handle,
 2095            show_cursor_when_unfocused: false,
 2096            last_focused_descendant: None,
 2097            buffer: multi_buffer.clone(),
 2098            display_map: display_map.clone(),
 2099            placeholder_display_map: None,
 2100            selections,
 2101            scroll_manager: ScrollManager::new(cx),
 2102            columnar_selection_state: None,
 2103            add_selections_state: None,
 2104            select_next_state: None,
 2105            select_prev_state: None,
 2106            selection_history: SelectionHistory::default(),
 2107            defer_selection_effects: false,
 2108            deferred_selection_effects_state: None,
 2109            autoclose_regions: Vec::new(),
 2110            snippet_stack: InvalidationStack::default(),
 2111            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2112            ime_transaction: None,
 2113            active_diagnostics: ActiveDiagnostic::None,
 2114            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2115            inline_diagnostics_update: Task::ready(()),
 2116            inline_diagnostics: Vec::new(),
 2117            soft_wrap_mode_override,
 2118            diagnostics_max_severity,
 2119            hard_wrap: None,
 2120            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2121            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2122            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2123            project,
 2124            blink_manager: blink_manager.clone(),
 2125            show_local_selections: true,
 2126            show_scrollbars: ScrollbarAxes {
 2127                horizontal: full_mode,
 2128                vertical: full_mode,
 2129            },
 2130            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2131            offset_content: !matches!(mode, EditorMode::SingleLine),
 2132            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2133            show_gutter: full_mode,
 2134            show_line_numbers: (!full_mode).then_some(false),
 2135            use_relative_line_numbers: None,
 2136            disable_expand_excerpt_buttons: !full_mode,
 2137            show_git_diff_gutter: None,
 2138            show_code_actions: None,
 2139            show_runnables: None,
 2140            show_breakpoints: None,
 2141            show_wrap_guides: None,
 2142            show_indent_guides,
 2143            highlight_order: 0,
 2144            highlighted_rows: HashMap::default(),
 2145            background_highlights: HashMap::default(),
 2146            gutter_highlights: HashMap::default(),
 2147            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2148            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2149            nav_history: None,
 2150            context_menu: RefCell::new(None),
 2151            context_menu_options: None,
 2152            mouse_context_menu: None,
 2153            completion_tasks: Vec::new(),
 2154            inline_blame_popover: None,
 2155            inline_blame_popover_show_task: None,
 2156            signature_help_state: SignatureHelpState::default(),
 2157            auto_signature_help: None,
 2158            find_all_references_task_sources: Vec::new(),
 2159            next_completion_id: 0,
 2160            next_inlay_id: 0,
 2161            code_action_providers,
 2162            available_code_actions: None,
 2163            code_actions_task: None,
 2164            quick_selection_highlight_task: None,
 2165            debounced_selection_highlight_task: None,
 2166            document_highlights_task: None,
 2167            linked_editing_range_task: None,
 2168            pending_rename: None,
 2169            searchable: !is_minimap,
 2170            cursor_shape: EditorSettings::get_global(cx)
 2171                .cursor_shape
 2172                .unwrap_or_default(),
 2173            current_line_highlight: None,
 2174            autoindent_mode: Some(AutoindentMode::EachLine),
 2175
 2176            workspace: None,
 2177            input_enabled: !is_minimap,
 2178            use_modal_editing: full_mode,
 2179            read_only: is_minimap,
 2180            use_autoclose: true,
 2181            use_auto_surround: true,
 2182            auto_replace_emoji_shortcode: false,
 2183            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2184            leader_id: None,
 2185            remote_id: None,
 2186            hover_state: HoverState::default(),
 2187            pending_mouse_down: None,
 2188            hovered_link_state: None,
 2189            edit_prediction_provider: None,
 2190            active_edit_prediction: None,
 2191            stale_edit_prediction_in_menu: None,
 2192            edit_prediction_preview: EditPredictionPreview::Inactive {
 2193                released_too_fast: false,
 2194            },
 2195            inline_diagnostics_enabled: full_mode,
 2196            diagnostics_enabled: full_mode,
 2197            word_completions_enabled: full_mode,
 2198            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2199            gutter_hovered: false,
 2200            pixel_position_of_newest_cursor: None,
 2201            last_bounds: None,
 2202            last_position_map: None,
 2203            expect_bounds_change: None,
 2204            gutter_dimensions: GutterDimensions::default(),
 2205            style: None,
 2206            show_cursor_names: false,
 2207            hovered_cursors: HashMap::default(),
 2208            next_editor_action_id: EditorActionId::default(),
 2209            editor_actions: Rc::default(),
 2210            edit_predictions_hidden_for_vim_mode: false,
 2211            show_edit_predictions_override: None,
 2212            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2213            edit_prediction_settings: EditPredictionSettings::Disabled,
 2214            edit_prediction_indent_conflict: false,
 2215            edit_prediction_requires_modifier_in_indent_conflict: true,
 2216            custom_context_menu: None,
 2217            show_git_blame_gutter: false,
 2218            show_git_blame_inline: false,
 2219            show_selection_menu: None,
 2220            show_git_blame_inline_delay_task: None,
 2221            git_blame_inline_enabled: full_mode
 2222                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2223            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2224            buffer_serialization: is_minimap.not().then(|| {
 2225                BufferSerialization::new(
 2226                    ProjectSettings::get_global(cx)
 2227                        .session
 2228                        .restore_unsaved_buffers,
 2229                )
 2230            }),
 2231            blame: None,
 2232            blame_subscription: None,
 2233            tasks: BTreeMap::default(),
 2234
 2235            breakpoint_store,
 2236            gutter_breakpoint_indicator: (None, None),
 2237            hovered_diff_hunk_row: None,
 2238            _subscriptions: (!is_minimap)
 2239                .then(|| {
 2240                    vec![
 2241                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2242                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2243                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2244                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2245                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2246                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2247                        cx.observe_window_activation(window, |editor, window, cx| {
 2248                            let active = window.is_window_active();
 2249                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2250                                if active {
 2251                                    blink_manager.enable(cx);
 2252                                } else {
 2253                                    blink_manager.disable(cx);
 2254                                }
 2255                            });
 2256                            if active {
 2257                                editor.show_mouse_cursor(cx);
 2258                            }
 2259                        }),
 2260                    ]
 2261                })
 2262                .unwrap_or_default(),
 2263            tasks_update_task: None,
 2264            pull_diagnostics_task: Task::ready(()),
 2265            colors: None,
 2266            refresh_colors_task: Task::ready(()),
 2267            inlay_hints: None,
 2268            next_color_inlay_id: 0,
 2269            post_scroll_update: Task::ready(()),
 2270            linked_edit_ranges: Default::default(),
 2271            in_project_search: false,
 2272            previous_search_ranges: None,
 2273            breadcrumb_header: None,
 2274            focused_block: None,
 2275            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2276            addons: HashMap::default(),
 2277            registered_buffers: HashMap::default(),
 2278            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2279            selection_mark_mode: false,
 2280            toggle_fold_multiple_buffers: Task::ready(()),
 2281            serialize_selections: Task::ready(()),
 2282            serialize_folds: Task::ready(()),
 2283            text_style_refinement: None,
 2284            load_diff_task: load_uncommitted_diff,
 2285            temporary_diff_override: false,
 2286            mouse_cursor_hidden: false,
 2287            minimap: None,
 2288            hide_mouse_mode: EditorSettings::get_global(cx)
 2289                .hide_mouse
 2290                .unwrap_or_default(),
 2291            change_list: ChangeList::new(),
 2292            mode,
 2293            selection_drag_state: SelectionDragState::None,
 2294            folding_newlines: Task::ready(()),
 2295            lookup_key: None,
 2296        };
 2297
 2298        if is_minimap {
 2299            return editor;
 2300        }
 2301
 2302        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2303            editor
 2304                ._subscriptions
 2305                .push(cx.observe(breakpoints, |_, _, cx| {
 2306                    cx.notify();
 2307                }));
 2308        }
 2309        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2310        editor._subscriptions.extend(project_subscriptions);
 2311
 2312        editor._subscriptions.push(cx.subscribe_in(
 2313            &cx.entity(),
 2314            window,
 2315            |editor, _, e: &EditorEvent, window, cx| match e {
 2316                EditorEvent::ScrollPositionChanged { local, .. } => {
 2317                    if *local {
 2318                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2319                        editor.inline_blame_popover.take();
 2320                        let new_anchor = editor.scroll_manager.anchor();
 2321                        let snapshot = editor.snapshot(window, cx);
 2322                        editor.update_restoration_data(cx, move |data| {
 2323                            data.scroll_position = (
 2324                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2325                                new_anchor.offset,
 2326                            );
 2327                        });
 2328
 2329                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2330                            cx.background_executor()
 2331                                .timer(Duration::from_millis(50))
 2332                                .await;
 2333                            editor
 2334                                .update_in(cx, |editor, window, cx| {
 2335                                    editor.register_visible_buffers(cx);
 2336                                    editor.refresh_colors_for_visible_range(None, window, cx);
 2337                                    editor.refresh_inlay_hints(
 2338                                        InlayHintRefreshReason::NewLinesShown,
 2339                                        cx,
 2340                                    );
 2341                                })
 2342                                .ok();
 2343                        });
 2344                    }
 2345                }
 2346                EditorEvent::Edited { .. } => {
 2347                    if vim_flavor(cx).is_none() {
 2348                        let display_map = editor.display_snapshot(cx);
 2349                        let selections = editor.selections.all_adjusted_display(&display_map);
 2350                        let pop_state = editor
 2351                            .change_list
 2352                            .last()
 2353                            .map(|previous| {
 2354                                previous.len() == selections.len()
 2355                                    && previous.iter().enumerate().all(|(ix, p)| {
 2356                                        p.to_display_point(&display_map).row()
 2357                                            == selections[ix].head().row()
 2358                                    })
 2359                            })
 2360                            .unwrap_or(false);
 2361                        let new_positions = selections
 2362                            .into_iter()
 2363                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2364                            .collect();
 2365                        editor
 2366                            .change_list
 2367                            .push_to_change_list(pop_state, new_positions);
 2368                    }
 2369                }
 2370                _ => (),
 2371            },
 2372        ));
 2373
 2374        if let Some(dap_store) = editor
 2375            .project
 2376            .as_ref()
 2377            .map(|project| project.read(cx).dap_store())
 2378        {
 2379            let weak_editor = cx.weak_entity();
 2380
 2381            editor
 2382                ._subscriptions
 2383                .push(
 2384                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2385                        let session_entity = cx.entity();
 2386                        weak_editor
 2387                            .update(cx, |editor, cx| {
 2388                                editor._subscriptions.push(
 2389                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2390                                );
 2391                            })
 2392                            .ok();
 2393                    }),
 2394                );
 2395
 2396            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2397                editor
 2398                    ._subscriptions
 2399                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2400            }
 2401        }
 2402
 2403        // skip adding the initial selection to selection history
 2404        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2405        editor.end_selection(window, cx);
 2406        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2407
 2408        editor.scroll_manager.show_scrollbars(window, cx);
 2409        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2410
 2411        if full_mode {
 2412            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2413            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2414
 2415            if editor.git_blame_inline_enabled {
 2416                editor.start_git_blame_inline(false, window, cx);
 2417            }
 2418
 2419            editor.go_to_active_debug_line(window, cx);
 2420
 2421            editor.minimap =
 2422                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2423            editor.colors = Some(LspColorData::new(cx));
 2424            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2425
 2426            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2427                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2428            }
 2429            editor.update_lsp_data(None, window, cx);
 2430            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2431        }
 2432
 2433        editor
 2434    }
 2435
 2436    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2437        self.selections.display_map(cx)
 2438    }
 2439
 2440    pub fn deploy_mouse_context_menu(
 2441        &mut self,
 2442        position: gpui::Point<Pixels>,
 2443        context_menu: Entity<ContextMenu>,
 2444        window: &mut Window,
 2445        cx: &mut Context<Self>,
 2446    ) {
 2447        self.mouse_context_menu = Some(MouseContextMenu::new(
 2448            self,
 2449            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2450            context_menu,
 2451            window,
 2452            cx,
 2453        ));
 2454    }
 2455
 2456    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2457        self.mouse_context_menu
 2458            .as_ref()
 2459            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2460    }
 2461
 2462    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2463        if self
 2464            .selections
 2465            .pending_anchor()
 2466            .is_some_and(|pending_selection| {
 2467                let snapshot = self.buffer().read(cx).snapshot(cx);
 2468                pending_selection.range().includes(range, &snapshot)
 2469            })
 2470        {
 2471            return true;
 2472        }
 2473
 2474        self.selections
 2475            .disjoint_in_range::<usize>(range.clone(), &self.display_snapshot(cx))
 2476            .into_iter()
 2477            .any(|selection| {
 2478                // This is needed to cover a corner case, if we just check for an existing
 2479                // selection in the fold range, having a cursor at the start of the fold
 2480                // marks it as selected. Non-empty selections don't cause this.
 2481                let length = selection.end - selection.start;
 2482                length > 0
 2483            })
 2484    }
 2485
 2486    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2487        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2488    }
 2489
 2490    fn key_context_internal(
 2491        &self,
 2492        has_active_edit_prediction: bool,
 2493        window: &mut Window,
 2494        cx: &mut App,
 2495    ) -> KeyContext {
 2496        let mut key_context = KeyContext::new_with_defaults();
 2497        key_context.add("Editor");
 2498        let mode = match self.mode {
 2499            EditorMode::SingleLine => "single_line",
 2500            EditorMode::AutoHeight { .. } => "auto_height",
 2501            EditorMode::Minimap { .. } => "minimap",
 2502            EditorMode::Full { .. } => "full",
 2503        };
 2504
 2505        if EditorSettings::jupyter_enabled(cx) {
 2506            key_context.add("jupyter");
 2507        }
 2508
 2509        key_context.set("mode", mode);
 2510        if self.pending_rename.is_some() {
 2511            key_context.add("renaming");
 2512        }
 2513
 2514        if let Some(snippet_stack) = self.snippet_stack.last() {
 2515            key_context.add("in_snippet");
 2516
 2517            if snippet_stack.active_index > 0 {
 2518                key_context.add("has_previous_tabstop");
 2519            }
 2520
 2521            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2522                key_context.add("has_next_tabstop");
 2523            }
 2524        }
 2525
 2526        match self.context_menu.borrow().as_ref() {
 2527            Some(CodeContextMenu::Completions(menu)) => {
 2528                if menu.visible() {
 2529                    key_context.add("menu");
 2530                    key_context.add("showing_completions");
 2531                }
 2532            }
 2533            Some(CodeContextMenu::CodeActions(menu)) => {
 2534                if menu.visible() {
 2535                    key_context.add("menu");
 2536                    key_context.add("showing_code_actions")
 2537                }
 2538            }
 2539            None => {}
 2540        }
 2541
 2542        if self.signature_help_state.has_multiple_signatures() {
 2543            key_context.add("showing_signature_help");
 2544        }
 2545
 2546        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2547        if !self.focus_handle(cx).contains_focused(window, cx)
 2548            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2549        {
 2550            for addon in self.addons.values() {
 2551                addon.extend_key_context(&mut key_context, cx)
 2552            }
 2553        }
 2554
 2555        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2556            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2557                Some(
 2558                    file.full_path(cx)
 2559                        .extension()?
 2560                        .to_string_lossy()
 2561                        .into_owned(),
 2562                )
 2563            }) {
 2564                key_context.set("extension", extension);
 2565            }
 2566        } else {
 2567            key_context.add("multibuffer");
 2568        }
 2569
 2570        if has_active_edit_prediction {
 2571            if self.edit_prediction_in_conflict() {
 2572                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2573            } else {
 2574                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2575                key_context.add("copilot_suggestion");
 2576            }
 2577        }
 2578
 2579        if self.selection_mark_mode {
 2580            key_context.add("selection_mode");
 2581        }
 2582
 2583        let disjoint = self.selections.disjoint_anchors();
 2584        let snapshot = self.snapshot(window, cx);
 2585        let snapshot = snapshot.buffer_snapshot();
 2586        if self.mode == EditorMode::SingleLine
 2587            && let [selection] = disjoint
 2588            && selection.start == selection.end
 2589            && selection.end.to_offset(snapshot) == snapshot.len()
 2590        {
 2591            key_context.add("end_of_input");
 2592        }
 2593
 2594        key_context
 2595    }
 2596
 2597    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2598        self.last_bounds.as_ref()
 2599    }
 2600
 2601    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2602        if self.mouse_cursor_hidden {
 2603            self.mouse_cursor_hidden = false;
 2604            cx.notify();
 2605        }
 2606    }
 2607
 2608    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2609        let hide_mouse_cursor = match origin {
 2610            HideMouseCursorOrigin::TypingAction => {
 2611                matches!(
 2612                    self.hide_mouse_mode,
 2613                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2614                )
 2615            }
 2616            HideMouseCursorOrigin::MovementAction => {
 2617                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2618            }
 2619        };
 2620        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2621            self.mouse_cursor_hidden = hide_mouse_cursor;
 2622            cx.notify();
 2623        }
 2624    }
 2625
 2626    pub fn edit_prediction_in_conflict(&self) -> bool {
 2627        if !self.show_edit_predictions_in_menu() {
 2628            return false;
 2629        }
 2630
 2631        let showing_completions = self
 2632            .context_menu
 2633            .borrow()
 2634            .as_ref()
 2635            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2636
 2637        showing_completions
 2638            || self.edit_prediction_requires_modifier()
 2639            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2640            // bindings to insert tab characters.
 2641            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2642    }
 2643
 2644    pub fn accept_edit_prediction_keybind(
 2645        &self,
 2646        accept_partial: bool,
 2647        window: &mut Window,
 2648        cx: &mut App,
 2649    ) -> AcceptEditPredictionBinding {
 2650        let key_context = self.key_context_internal(true, window, cx);
 2651        let in_conflict = self.edit_prediction_in_conflict();
 2652
 2653        let bindings = if accept_partial {
 2654            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2655        } else {
 2656            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2657        };
 2658
 2659        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2660        // just the first one.
 2661        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2662            !in_conflict
 2663                || binding
 2664                    .keystrokes()
 2665                    .first()
 2666                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2667        }))
 2668    }
 2669
 2670    pub fn new_file(
 2671        workspace: &mut Workspace,
 2672        _: &workspace::NewFile,
 2673        window: &mut Window,
 2674        cx: &mut Context<Workspace>,
 2675    ) {
 2676        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2677            "Failed to create buffer",
 2678            window,
 2679            cx,
 2680            |e, _, _| match e.error_code() {
 2681                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2682                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2683                e.error_tag("required").unwrap_or("the latest version")
 2684            )),
 2685                _ => None,
 2686            },
 2687        );
 2688    }
 2689
 2690    pub fn new_in_workspace(
 2691        workspace: &mut Workspace,
 2692        window: &mut Window,
 2693        cx: &mut Context<Workspace>,
 2694    ) -> Task<Result<Entity<Editor>>> {
 2695        let project = workspace.project().clone();
 2696        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2697
 2698        cx.spawn_in(window, async move |workspace, cx| {
 2699            let buffer = create.await?;
 2700            workspace.update_in(cx, |workspace, window, cx| {
 2701                let editor =
 2702                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2703                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2704                editor
 2705            })
 2706        })
 2707    }
 2708
 2709    fn new_file_vertical(
 2710        workspace: &mut Workspace,
 2711        _: &workspace::NewFileSplitVertical,
 2712        window: &mut Window,
 2713        cx: &mut Context<Workspace>,
 2714    ) {
 2715        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2716    }
 2717
 2718    fn new_file_horizontal(
 2719        workspace: &mut Workspace,
 2720        _: &workspace::NewFileSplitHorizontal,
 2721        window: &mut Window,
 2722        cx: &mut Context<Workspace>,
 2723    ) {
 2724        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2725    }
 2726
 2727    fn new_file_split(
 2728        workspace: &mut Workspace,
 2729        action: &workspace::NewFileSplit,
 2730        window: &mut Window,
 2731        cx: &mut Context<Workspace>,
 2732    ) {
 2733        Self::new_file_in_direction(workspace, action.0, window, cx)
 2734    }
 2735
 2736    fn new_file_in_direction(
 2737        workspace: &mut Workspace,
 2738        direction: SplitDirection,
 2739        window: &mut Window,
 2740        cx: &mut Context<Workspace>,
 2741    ) {
 2742        let project = workspace.project().clone();
 2743        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2744
 2745        cx.spawn_in(window, async move |workspace, cx| {
 2746            let buffer = create.await?;
 2747            workspace.update_in(cx, move |workspace, window, cx| {
 2748                workspace.split_item(
 2749                    direction,
 2750                    Box::new(
 2751                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2752                    ),
 2753                    window,
 2754                    cx,
 2755                )
 2756            })?;
 2757            anyhow::Ok(())
 2758        })
 2759        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2760            match e.error_code() {
 2761                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2762                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2763                e.error_tag("required").unwrap_or("the latest version")
 2764            )),
 2765                _ => None,
 2766            }
 2767        });
 2768    }
 2769
 2770    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2771        self.leader_id
 2772    }
 2773
 2774    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2775        &self.buffer
 2776    }
 2777
 2778    pub fn project(&self) -> Option<&Entity<Project>> {
 2779        self.project.as_ref()
 2780    }
 2781
 2782    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2783        self.workspace.as_ref()?.0.upgrade()
 2784    }
 2785
 2786    /// Returns the workspace serialization ID if this editor should be serialized.
 2787    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 2788        self.workspace
 2789            .as_ref()
 2790            .filter(|_| self.should_serialize_buffer())
 2791            .and_then(|workspace| workspace.1)
 2792    }
 2793
 2794    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2795        self.buffer().read(cx).title(cx)
 2796    }
 2797
 2798    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2799        let git_blame_gutter_max_author_length = self
 2800            .render_git_blame_gutter(cx)
 2801            .then(|| {
 2802                if let Some(blame) = self.blame.as_ref() {
 2803                    let max_author_length =
 2804                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2805                    Some(max_author_length)
 2806                } else {
 2807                    None
 2808                }
 2809            })
 2810            .flatten();
 2811
 2812        EditorSnapshot {
 2813            mode: self.mode.clone(),
 2814            show_gutter: self.show_gutter,
 2815            show_line_numbers: self.show_line_numbers,
 2816            show_git_diff_gutter: self.show_git_diff_gutter,
 2817            show_code_actions: self.show_code_actions,
 2818            show_runnables: self.show_runnables,
 2819            show_breakpoints: self.show_breakpoints,
 2820            git_blame_gutter_max_author_length,
 2821            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2822            placeholder_display_snapshot: self
 2823                .placeholder_display_map
 2824                .as_ref()
 2825                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2826            scroll_anchor: self.scroll_manager.anchor(),
 2827            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2828            is_focused: self.focus_handle.is_focused(window),
 2829            current_line_highlight: self
 2830                .current_line_highlight
 2831                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2832            gutter_hovered: self.gutter_hovered,
 2833        }
 2834    }
 2835
 2836    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2837        self.buffer.read(cx).language_at(point, cx)
 2838    }
 2839
 2840    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2841        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2842    }
 2843
 2844    pub fn active_excerpt(
 2845        &self,
 2846        cx: &App,
 2847    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2848        self.buffer
 2849            .read(cx)
 2850            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2851    }
 2852
 2853    pub fn mode(&self) -> &EditorMode {
 2854        &self.mode
 2855    }
 2856
 2857    pub fn set_mode(&mut self, mode: EditorMode) {
 2858        self.mode = mode;
 2859    }
 2860
 2861    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2862        self.collaboration_hub.as_deref()
 2863    }
 2864
 2865    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2866        self.collaboration_hub = Some(hub);
 2867    }
 2868
 2869    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2870        self.in_project_search = in_project_search;
 2871    }
 2872
 2873    pub fn set_custom_context_menu(
 2874        &mut self,
 2875        f: impl 'static
 2876        + Fn(
 2877            &mut Self,
 2878            DisplayPoint,
 2879            &mut Window,
 2880            &mut Context<Self>,
 2881        ) -> Option<Entity<ui::ContextMenu>>,
 2882    ) {
 2883        self.custom_context_menu = Some(Box::new(f))
 2884    }
 2885
 2886    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2887        self.completion_provider = provider;
 2888    }
 2889
 2890    #[cfg(any(test, feature = "test-support"))]
 2891    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2892        self.completion_provider.clone()
 2893    }
 2894
 2895    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2896        self.semantics_provider.clone()
 2897    }
 2898
 2899    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2900        self.semantics_provider = provider;
 2901    }
 2902
 2903    pub fn set_edit_prediction_provider<T>(
 2904        &mut self,
 2905        provider: Option<Entity<T>>,
 2906        window: &mut Window,
 2907        cx: &mut Context<Self>,
 2908    ) where
 2909        T: EditPredictionProvider,
 2910    {
 2911        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2912            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2913                if this.focus_handle.is_focused(window) {
 2914                    this.update_visible_edit_prediction(window, cx);
 2915                }
 2916            }),
 2917            provider: Arc::new(provider),
 2918        });
 2919        self.update_edit_prediction_settings(cx);
 2920        self.refresh_edit_prediction(false, false, window, cx);
 2921    }
 2922
 2923    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2924        self.placeholder_display_map
 2925            .as_ref()
 2926            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2927    }
 2928
 2929    pub fn set_placeholder_text(
 2930        &mut self,
 2931        placeholder_text: &str,
 2932        window: &mut Window,
 2933        cx: &mut Context<Self>,
 2934    ) {
 2935        let multibuffer = cx
 2936            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2937
 2938        let style = window.text_style();
 2939
 2940        self.placeholder_display_map = Some(cx.new(|cx| {
 2941            DisplayMap::new(
 2942                multibuffer,
 2943                style.font(),
 2944                style.font_size.to_pixels(window.rem_size()),
 2945                None,
 2946                FILE_HEADER_HEIGHT,
 2947                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2948                Default::default(),
 2949                DiagnosticSeverity::Off,
 2950                cx,
 2951            )
 2952        }));
 2953        cx.notify();
 2954    }
 2955
 2956    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2957        self.cursor_shape = cursor_shape;
 2958
 2959        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2960        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2961
 2962        cx.notify();
 2963    }
 2964
 2965    pub fn set_current_line_highlight(
 2966        &mut self,
 2967        current_line_highlight: Option<CurrentLineHighlight>,
 2968    ) {
 2969        self.current_line_highlight = current_line_highlight;
 2970    }
 2971
 2972    pub fn range_for_match<T: std::marker::Copy>(
 2973        &self,
 2974        range: &Range<T>,
 2975        collapse: bool,
 2976    ) -> Range<T> {
 2977        if collapse {
 2978            return range.start..range.start;
 2979        }
 2980        range.clone()
 2981    }
 2982
 2983    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2984        if self.display_map.read(cx).clip_at_line_ends != clip {
 2985            self.display_map
 2986                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2987        }
 2988    }
 2989
 2990    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2991        self.input_enabled = input_enabled;
 2992    }
 2993
 2994    pub fn set_edit_predictions_hidden_for_vim_mode(
 2995        &mut self,
 2996        hidden: bool,
 2997        window: &mut Window,
 2998        cx: &mut Context<Self>,
 2999    ) {
 3000        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3001            self.edit_predictions_hidden_for_vim_mode = hidden;
 3002            if hidden {
 3003                self.update_visible_edit_prediction(window, cx);
 3004            } else {
 3005                self.refresh_edit_prediction(true, false, window, cx);
 3006            }
 3007        }
 3008    }
 3009
 3010    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3011        self.menu_edit_predictions_policy = value;
 3012    }
 3013
 3014    pub fn set_autoindent(&mut self, autoindent: bool) {
 3015        if autoindent {
 3016            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3017        } else {
 3018            self.autoindent_mode = None;
 3019        }
 3020    }
 3021
 3022    pub fn read_only(&self, cx: &App) -> bool {
 3023        self.read_only || self.buffer.read(cx).read_only()
 3024    }
 3025
 3026    pub fn set_read_only(&mut self, read_only: bool) {
 3027        self.read_only = read_only;
 3028    }
 3029
 3030    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3031        self.use_autoclose = autoclose;
 3032    }
 3033
 3034    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3035        self.use_auto_surround = auto_surround;
 3036    }
 3037
 3038    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3039        self.auto_replace_emoji_shortcode = auto_replace;
 3040    }
 3041
 3042    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3043        self.buffer_serialization = should_serialize.then(|| {
 3044            BufferSerialization::new(
 3045                ProjectSettings::get_global(cx)
 3046                    .session
 3047                    .restore_unsaved_buffers,
 3048            )
 3049        })
 3050    }
 3051
 3052    fn should_serialize_buffer(&self) -> bool {
 3053        self.buffer_serialization.is_some()
 3054    }
 3055
 3056    pub fn toggle_edit_predictions(
 3057        &mut self,
 3058        _: &ToggleEditPrediction,
 3059        window: &mut Window,
 3060        cx: &mut Context<Self>,
 3061    ) {
 3062        if self.show_edit_predictions_override.is_some() {
 3063            self.set_show_edit_predictions(None, window, cx);
 3064        } else {
 3065            let show_edit_predictions = !self.edit_predictions_enabled();
 3066            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3067        }
 3068    }
 3069
 3070    pub fn set_show_edit_predictions(
 3071        &mut self,
 3072        show_edit_predictions: Option<bool>,
 3073        window: &mut Window,
 3074        cx: &mut Context<Self>,
 3075    ) {
 3076        self.show_edit_predictions_override = show_edit_predictions;
 3077        self.update_edit_prediction_settings(cx);
 3078
 3079        if let Some(false) = show_edit_predictions {
 3080            self.discard_edit_prediction(false, cx);
 3081        } else {
 3082            self.refresh_edit_prediction(false, true, window, cx);
 3083        }
 3084    }
 3085
 3086    fn edit_predictions_disabled_in_scope(
 3087        &self,
 3088        buffer: &Entity<Buffer>,
 3089        buffer_position: language::Anchor,
 3090        cx: &App,
 3091    ) -> bool {
 3092        let snapshot = buffer.read(cx).snapshot();
 3093        let settings = snapshot.settings_at(buffer_position, cx);
 3094
 3095        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3096            return false;
 3097        };
 3098
 3099        scope.override_name().is_some_and(|scope_name| {
 3100            settings
 3101                .edit_predictions_disabled_in
 3102                .iter()
 3103                .any(|s| s == scope_name)
 3104        })
 3105    }
 3106
 3107    pub fn set_use_modal_editing(&mut self, to: bool) {
 3108        self.use_modal_editing = to;
 3109    }
 3110
 3111    pub fn use_modal_editing(&self) -> bool {
 3112        self.use_modal_editing
 3113    }
 3114
 3115    fn selections_did_change(
 3116        &mut self,
 3117        local: bool,
 3118        old_cursor_position: &Anchor,
 3119        effects: SelectionEffects,
 3120        window: &mut Window,
 3121        cx: &mut Context<Self>,
 3122    ) {
 3123        window.invalidate_character_coordinates();
 3124
 3125        // Copy selections to primary selection buffer
 3126        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3127        if local {
 3128            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3129            let buffer_handle = self.buffer.read(cx).read(cx);
 3130
 3131            let mut text = String::new();
 3132            for (index, selection) in selections.iter().enumerate() {
 3133                let text_for_selection = buffer_handle
 3134                    .text_for_range(selection.start..selection.end)
 3135                    .collect::<String>();
 3136
 3137                text.push_str(&text_for_selection);
 3138                if index != selections.len() - 1 {
 3139                    text.push('\n');
 3140                }
 3141            }
 3142
 3143            if !text.is_empty() {
 3144                cx.write_to_primary(ClipboardItem::new_string(text));
 3145            }
 3146        }
 3147
 3148        let selection_anchors = self.selections.disjoint_anchors_arc();
 3149
 3150        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3151            self.buffer.update(cx, |buffer, cx| {
 3152                buffer.set_active_selections(
 3153                    &selection_anchors,
 3154                    self.selections.line_mode(),
 3155                    self.cursor_shape,
 3156                    cx,
 3157                )
 3158            });
 3159        }
 3160        let display_map = self
 3161            .display_map
 3162            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3163        let buffer = display_map.buffer_snapshot();
 3164        if self.selections.count() == 1 {
 3165            self.add_selections_state = None;
 3166        }
 3167        self.select_next_state = None;
 3168        self.select_prev_state = None;
 3169        self.select_syntax_node_history.try_clear();
 3170        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3171        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3172        self.take_rename(false, window, cx);
 3173
 3174        let newest_selection = self.selections.newest_anchor();
 3175        let new_cursor_position = newest_selection.head();
 3176        let selection_start = newest_selection.start;
 3177
 3178        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3179            self.push_to_nav_history(
 3180                *old_cursor_position,
 3181                Some(new_cursor_position.to_point(buffer)),
 3182                false,
 3183                effects.nav_history == Some(true),
 3184                cx,
 3185            );
 3186        }
 3187
 3188        if local {
 3189            if let Some(buffer_id) = new_cursor_position.buffer_id {
 3190                self.register_buffer(buffer_id, cx);
 3191            }
 3192
 3193            let mut context_menu = self.context_menu.borrow_mut();
 3194            let completion_menu = match context_menu.as_ref() {
 3195                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3196                Some(CodeContextMenu::CodeActions(_)) => {
 3197                    *context_menu = None;
 3198                    None
 3199                }
 3200                None => None,
 3201            };
 3202            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3203            drop(context_menu);
 3204
 3205            if effects.completions
 3206                && let Some(completion_position) = completion_position
 3207            {
 3208                let start_offset = selection_start.to_offset(buffer);
 3209                let position_matches = start_offset == completion_position.to_offset(buffer);
 3210                let continue_showing = if position_matches {
 3211                    if self.snippet_stack.is_empty() {
 3212                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3213                            == Some(CharKind::Word)
 3214                    } else {
 3215                        // Snippet choices can be shown even when the cursor is in whitespace.
 3216                        // Dismissing the menu with actions like backspace is handled by
 3217                        // invalidation regions.
 3218                        true
 3219                    }
 3220                } else {
 3221                    false
 3222                };
 3223
 3224                if continue_showing {
 3225                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3226                } else {
 3227                    self.hide_context_menu(window, cx);
 3228                }
 3229            }
 3230
 3231            hide_hover(self, cx);
 3232
 3233            if old_cursor_position.to_display_point(&display_map).row()
 3234                != new_cursor_position.to_display_point(&display_map).row()
 3235            {
 3236                self.available_code_actions.take();
 3237            }
 3238            self.refresh_code_actions(window, cx);
 3239            self.refresh_document_highlights(cx);
 3240            refresh_linked_ranges(self, window, cx);
 3241
 3242            self.refresh_selected_text_highlights(false, window, cx);
 3243            self.refresh_matching_bracket_highlights(window, cx);
 3244            self.update_visible_edit_prediction(window, cx);
 3245            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3246            self.inline_blame_popover.take();
 3247            if self.git_blame_inline_enabled {
 3248                self.start_inline_blame_timer(window, cx);
 3249            }
 3250        }
 3251
 3252        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3253        cx.emit(EditorEvent::SelectionsChanged { local });
 3254
 3255        let selections = &self.selections.disjoint_anchors_arc();
 3256        if selections.len() == 1 {
 3257            cx.emit(SearchEvent::ActiveMatchChanged)
 3258        }
 3259        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3260            let inmemory_selections = selections
 3261                .iter()
 3262                .map(|s| {
 3263                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3264                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3265                })
 3266                .collect();
 3267            self.update_restoration_data(cx, |data| {
 3268                data.selections = inmemory_selections;
 3269            });
 3270
 3271            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3272                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3273            {
 3274                let snapshot = self.buffer().read(cx).snapshot(cx);
 3275                let selections = selections.clone();
 3276                let background_executor = cx.background_executor().clone();
 3277                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3278                self.serialize_selections = cx.background_spawn(async move {
 3279                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3280                    let db_selections = selections
 3281                        .iter()
 3282                        .map(|selection| {
 3283                            (
 3284                                selection.start.to_offset(&snapshot),
 3285                                selection.end.to_offset(&snapshot),
 3286                            )
 3287                        })
 3288                        .collect();
 3289
 3290                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3291                        .await
 3292                        .with_context(|| {
 3293                            format!(
 3294                                "persisting editor selections for editor {editor_id}, \
 3295                                workspace {workspace_id:?}"
 3296                            )
 3297                        })
 3298                        .log_err();
 3299                });
 3300            }
 3301        }
 3302
 3303        cx.notify();
 3304    }
 3305
 3306    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3307        use text::ToOffset as _;
 3308        use text::ToPoint as _;
 3309
 3310        if self.mode.is_minimap()
 3311            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3312        {
 3313            return;
 3314        }
 3315
 3316        if !self.buffer().read(cx).is_singleton() {
 3317            return;
 3318        }
 3319
 3320        let display_snapshot = self
 3321            .display_map
 3322            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3323        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3324            return;
 3325        };
 3326        let inmemory_folds = display_snapshot
 3327            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3328            .map(|fold| {
 3329                fold.range.start.text_anchor.to_point(&snapshot)
 3330                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3331            })
 3332            .collect();
 3333        self.update_restoration_data(cx, |data| {
 3334            data.folds = inmemory_folds;
 3335        });
 3336
 3337        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3338            return;
 3339        };
 3340        let background_executor = cx.background_executor().clone();
 3341        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3342        let db_folds = display_snapshot
 3343            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3344            .map(|fold| {
 3345                (
 3346                    fold.range.start.text_anchor.to_offset(&snapshot),
 3347                    fold.range.end.text_anchor.to_offset(&snapshot),
 3348                )
 3349            })
 3350            .collect();
 3351        self.serialize_folds = cx.background_spawn(async move {
 3352            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3353            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3354                .await
 3355                .with_context(|| {
 3356                    format!(
 3357                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3358                    )
 3359                })
 3360                .log_err();
 3361        });
 3362    }
 3363
 3364    pub fn sync_selections(
 3365        &mut self,
 3366        other: Entity<Editor>,
 3367        cx: &mut Context<Self>,
 3368    ) -> gpui::Subscription {
 3369        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3370        if !other_selections.is_empty() {
 3371            self.selections.change_with(cx, |selections| {
 3372                selections.select_anchors(other_selections);
 3373            });
 3374        }
 3375
 3376        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3377            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3378                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3379                if other_selections.is_empty() {
 3380                    return;
 3381                }
 3382                this.selections.change_with(cx, |selections| {
 3383                    selections.select_anchors(other_selections);
 3384                });
 3385            }
 3386        });
 3387
 3388        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3389            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3390                let these_selections = this.selections.disjoint_anchors().to_vec();
 3391                if these_selections.is_empty() {
 3392                    return;
 3393                }
 3394                other.update(cx, |other_editor, cx| {
 3395                    other_editor.selections.change_with(cx, |selections| {
 3396                        selections.select_anchors(these_selections);
 3397                    })
 3398                });
 3399            }
 3400        });
 3401
 3402        Subscription::join(other_subscription, this_subscription)
 3403    }
 3404
 3405    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3406    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3407    /// effects of selection change occur at the end of the transaction.
 3408    pub fn change_selections<R>(
 3409        &mut self,
 3410        effects: SelectionEffects,
 3411        window: &mut Window,
 3412        cx: &mut Context<Self>,
 3413        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3414    ) -> R {
 3415        if let Some(state) = &mut self.deferred_selection_effects_state {
 3416            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3417            state.effects.completions = effects.completions;
 3418            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3419            let (changed, result) = self.selections.change_with(cx, change);
 3420            state.changed |= changed;
 3421            return result;
 3422        }
 3423        let mut state = DeferredSelectionEffectsState {
 3424            changed: false,
 3425            effects,
 3426            old_cursor_position: self.selections.newest_anchor().head(),
 3427            history_entry: SelectionHistoryEntry {
 3428                selections: self.selections.disjoint_anchors_arc(),
 3429                select_next_state: self.select_next_state.clone(),
 3430                select_prev_state: self.select_prev_state.clone(),
 3431                add_selections_state: self.add_selections_state.clone(),
 3432            },
 3433        };
 3434        let (changed, result) = self.selections.change_with(cx, change);
 3435        state.changed = state.changed || changed;
 3436        if self.defer_selection_effects {
 3437            self.deferred_selection_effects_state = Some(state);
 3438        } else {
 3439            self.apply_selection_effects(state, window, cx);
 3440        }
 3441        result
 3442    }
 3443
 3444    /// Defers the effects of selection change, so that the effects of multiple calls to
 3445    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3446    /// to selection history and the state of popovers based on selection position aren't
 3447    /// erroneously updated.
 3448    pub fn with_selection_effects_deferred<R>(
 3449        &mut self,
 3450        window: &mut Window,
 3451        cx: &mut Context<Self>,
 3452        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3453    ) -> R {
 3454        let already_deferred = self.defer_selection_effects;
 3455        self.defer_selection_effects = true;
 3456        let result = update(self, window, cx);
 3457        if !already_deferred {
 3458            self.defer_selection_effects = false;
 3459            if let Some(state) = self.deferred_selection_effects_state.take() {
 3460                self.apply_selection_effects(state, window, cx);
 3461            }
 3462        }
 3463        result
 3464    }
 3465
 3466    fn apply_selection_effects(
 3467        &mut self,
 3468        state: DeferredSelectionEffectsState,
 3469        window: &mut Window,
 3470        cx: &mut Context<Self>,
 3471    ) {
 3472        if state.changed {
 3473            self.selection_history.push(state.history_entry);
 3474
 3475            if let Some(autoscroll) = state.effects.scroll {
 3476                self.request_autoscroll(autoscroll, cx);
 3477            }
 3478
 3479            let old_cursor_position = &state.old_cursor_position;
 3480
 3481            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3482
 3483            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3484                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3485            }
 3486        }
 3487    }
 3488
 3489    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3490    where
 3491        I: IntoIterator<Item = (Range<S>, T)>,
 3492        S: ToOffset,
 3493        T: Into<Arc<str>>,
 3494    {
 3495        if self.read_only(cx) {
 3496            return;
 3497        }
 3498
 3499        self.buffer
 3500            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3501    }
 3502
 3503    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3504    where
 3505        I: IntoIterator<Item = (Range<S>, T)>,
 3506        S: ToOffset,
 3507        T: Into<Arc<str>>,
 3508    {
 3509        if self.read_only(cx) {
 3510            return;
 3511        }
 3512
 3513        self.buffer.update(cx, |buffer, cx| {
 3514            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3515        });
 3516    }
 3517
 3518    pub fn edit_with_block_indent<I, S, T>(
 3519        &mut self,
 3520        edits: I,
 3521        original_indent_columns: Vec<Option<u32>>,
 3522        cx: &mut Context<Self>,
 3523    ) where
 3524        I: IntoIterator<Item = (Range<S>, T)>,
 3525        S: ToOffset,
 3526        T: Into<Arc<str>>,
 3527    {
 3528        if self.read_only(cx) {
 3529            return;
 3530        }
 3531
 3532        self.buffer.update(cx, |buffer, cx| {
 3533            buffer.edit(
 3534                edits,
 3535                Some(AutoindentMode::Block {
 3536                    original_indent_columns,
 3537                }),
 3538                cx,
 3539            )
 3540        });
 3541    }
 3542
 3543    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3544        self.hide_context_menu(window, cx);
 3545
 3546        match phase {
 3547            SelectPhase::Begin {
 3548                position,
 3549                add,
 3550                click_count,
 3551            } => self.begin_selection(position, add, click_count, window, cx),
 3552            SelectPhase::BeginColumnar {
 3553                position,
 3554                goal_column,
 3555                reset,
 3556                mode,
 3557            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3558            SelectPhase::Extend {
 3559                position,
 3560                click_count,
 3561            } => self.extend_selection(position, click_count, window, cx),
 3562            SelectPhase::Update {
 3563                position,
 3564                goal_column,
 3565                scroll_delta,
 3566            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3567            SelectPhase::End => self.end_selection(window, cx),
 3568        }
 3569    }
 3570
 3571    fn extend_selection(
 3572        &mut self,
 3573        position: DisplayPoint,
 3574        click_count: usize,
 3575        window: &mut Window,
 3576        cx: &mut Context<Self>,
 3577    ) {
 3578        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3579        let tail = self.selections.newest::<usize>(&display_map).tail();
 3580        let click_count = click_count.max(match self.selections.select_mode() {
 3581            SelectMode::Character => 1,
 3582            SelectMode::Word(_) => 2,
 3583            SelectMode::Line(_) => 3,
 3584            SelectMode::All => 4,
 3585        });
 3586        self.begin_selection(position, false, click_count, window, cx);
 3587
 3588        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3589
 3590        let current_selection = match self.selections.select_mode() {
 3591            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3592            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3593        };
 3594
 3595        let mut pending_selection = self
 3596            .selections
 3597            .pending_anchor()
 3598            .cloned()
 3599            .expect("extend_selection not called with pending selection");
 3600
 3601        if pending_selection
 3602            .start
 3603            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3604            == Ordering::Greater
 3605        {
 3606            pending_selection.start = current_selection.start;
 3607        }
 3608        if pending_selection
 3609            .end
 3610            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3611            == Ordering::Less
 3612        {
 3613            pending_selection.end = current_selection.end;
 3614            pending_selection.reversed = true;
 3615        }
 3616
 3617        let mut pending_mode = self.selections.pending_mode().unwrap();
 3618        match &mut pending_mode {
 3619            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3620            _ => {}
 3621        }
 3622
 3623        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3624            SelectionEffects::scroll(Autoscroll::fit())
 3625        } else {
 3626            SelectionEffects::no_scroll()
 3627        };
 3628
 3629        self.change_selections(effects, window, cx, |s| {
 3630            s.set_pending(pending_selection.clone(), pending_mode);
 3631            s.set_is_extending(true);
 3632        });
 3633    }
 3634
 3635    fn begin_selection(
 3636        &mut self,
 3637        position: DisplayPoint,
 3638        add: bool,
 3639        click_count: usize,
 3640        window: &mut Window,
 3641        cx: &mut Context<Self>,
 3642    ) {
 3643        if !self.focus_handle.is_focused(window) {
 3644            self.last_focused_descendant = None;
 3645            window.focus(&self.focus_handle);
 3646        }
 3647
 3648        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3649        let buffer = display_map.buffer_snapshot();
 3650        let position = display_map.clip_point(position, Bias::Left);
 3651
 3652        let start;
 3653        let end;
 3654        let mode;
 3655        let mut auto_scroll;
 3656        match click_count {
 3657            1 => {
 3658                start = buffer.anchor_before(position.to_point(&display_map));
 3659                end = start;
 3660                mode = SelectMode::Character;
 3661                auto_scroll = true;
 3662            }
 3663            2 => {
 3664                let position = display_map
 3665                    .clip_point(position, Bias::Left)
 3666                    .to_offset(&display_map, Bias::Left);
 3667                let (range, _) = buffer.surrounding_word(position, None);
 3668                start = buffer.anchor_before(range.start);
 3669                end = buffer.anchor_before(range.end);
 3670                mode = SelectMode::Word(start..end);
 3671                auto_scroll = true;
 3672            }
 3673            3 => {
 3674                let position = display_map
 3675                    .clip_point(position, Bias::Left)
 3676                    .to_point(&display_map);
 3677                let line_start = display_map.prev_line_boundary(position).0;
 3678                let next_line_start = buffer.clip_point(
 3679                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3680                    Bias::Left,
 3681                );
 3682                start = buffer.anchor_before(line_start);
 3683                end = buffer.anchor_before(next_line_start);
 3684                mode = SelectMode::Line(start..end);
 3685                auto_scroll = true;
 3686            }
 3687            _ => {
 3688                start = buffer.anchor_before(0);
 3689                end = buffer.anchor_before(buffer.len());
 3690                mode = SelectMode::All;
 3691                auto_scroll = false;
 3692            }
 3693        }
 3694        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3695
 3696        let point_to_delete: Option<usize> = {
 3697            let selected_points: Vec<Selection<Point>> =
 3698                self.selections.disjoint_in_range(start..end, &display_map);
 3699
 3700            if !add || click_count > 1 {
 3701                None
 3702            } else if !selected_points.is_empty() {
 3703                Some(selected_points[0].id)
 3704            } else {
 3705                let clicked_point_already_selected =
 3706                    self.selections.disjoint_anchors().iter().find(|selection| {
 3707                        selection.start.to_point(buffer) == start.to_point(buffer)
 3708                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3709                    });
 3710
 3711                clicked_point_already_selected.map(|selection| selection.id)
 3712            }
 3713        };
 3714
 3715        let selections_count = self.selections.count();
 3716        let effects = if auto_scroll {
 3717            SelectionEffects::default()
 3718        } else {
 3719            SelectionEffects::no_scroll()
 3720        };
 3721
 3722        self.change_selections(effects, window, cx, |s| {
 3723            if let Some(point_to_delete) = point_to_delete {
 3724                s.delete(point_to_delete);
 3725
 3726                if selections_count == 1 {
 3727                    s.set_pending_anchor_range(start..end, mode);
 3728                }
 3729            } else {
 3730                if !add {
 3731                    s.clear_disjoint();
 3732                }
 3733
 3734                s.set_pending_anchor_range(start..end, mode);
 3735            }
 3736        });
 3737    }
 3738
 3739    fn begin_columnar_selection(
 3740        &mut self,
 3741        position: DisplayPoint,
 3742        goal_column: u32,
 3743        reset: bool,
 3744        mode: ColumnarMode,
 3745        window: &mut Window,
 3746        cx: &mut Context<Self>,
 3747    ) {
 3748        if !self.focus_handle.is_focused(window) {
 3749            self.last_focused_descendant = None;
 3750            window.focus(&self.focus_handle);
 3751        }
 3752
 3753        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3754
 3755        if reset {
 3756            let pointer_position = display_map
 3757                .buffer_snapshot()
 3758                .anchor_before(position.to_point(&display_map));
 3759
 3760            self.change_selections(
 3761                SelectionEffects::scroll(Autoscroll::newest()),
 3762                window,
 3763                cx,
 3764                |s| {
 3765                    s.clear_disjoint();
 3766                    s.set_pending_anchor_range(
 3767                        pointer_position..pointer_position,
 3768                        SelectMode::Character,
 3769                    );
 3770                },
 3771            );
 3772        };
 3773
 3774        let tail = self.selections.newest::<Point>(&display_map).tail();
 3775        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3776        self.columnar_selection_state = match mode {
 3777            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3778                selection_tail: selection_anchor,
 3779                display_point: if reset {
 3780                    if position.column() != goal_column {
 3781                        Some(DisplayPoint::new(position.row(), goal_column))
 3782                    } else {
 3783                        None
 3784                    }
 3785                } else {
 3786                    None
 3787                },
 3788            }),
 3789            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3790                selection_tail: selection_anchor,
 3791            }),
 3792        };
 3793
 3794        if !reset {
 3795            self.select_columns(position, goal_column, &display_map, window, cx);
 3796        }
 3797    }
 3798
 3799    fn update_selection(
 3800        &mut self,
 3801        position: DisplayPoint,
 3802        goal_column: u32,
 3803        scroll_delta: gpui::Point<f32>,
 3804        window: &mut Window,
 3805        cx: &mut Context<Self>,
 3806    ) {
 3807        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3808
 3809        if self.columnar_selection_state.is_some() {
 3810            self.select_columns(position, goal_column, &display_map, window, cx);
 3811        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3812            let buffer = display_map.buffer_snapshot();
 3813            let head;
 3814            let tail;
 3815            let mode = self.selections.pending_mode().unwrap();
 3816            match &mode {
 3817                SelectMode::Character => {
 3818                    head = position.to_point(&display_map);
 3819                    tail = pending.tail().to_point(buffer);
 3820                }
 3821                SelectMode::Word(original_range) => {
 3822                    let offset = display_map
 3823                        .clip_point(position, Bias::Left)
 3824                        .to_offset(&display_map, Bias::Left);
 3825                    let original_range = original_range.to_offset(buffer);
 3826
 3827                    let head_offset = if buffer.is_inside_word(offset, None)
 3828                        || original_range.contains(&offset)
 3829                    {
 3830                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3831                        if word_range.start < original_range.start {
 3832                            word_range.start
 3833                        } else {
 3834                            word_range.end
 3835                        }
 3836                    } else {
 3837                        offset
 3838                    };
 3839
 3840                    head = head_offset.to_point(buffer);
 3841                    if head_offset <= original_range.start {
 3842                        tail = original_range.end.to_point(buffer);
 3843                    } else {
 3844                        tail = original_range.start.to_point(buffer);
 3845                    }
 3846                }
 3847                SelectMode::Line(original_range) => {
 3848                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3849
 3850                    let position = display_map
 3851                        .clip_point(position, Bias::Left)
 3852                        .to_point(&display_map);
 3853                    let line_start = display_map.prev_line_boundary(position).0;
 3854                    let next_line_start = buffer.clip_point(
 3855                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3856                        Bias::Left,
 3857                    );
 3858
 3859                    if line_start < original_range.start {
 3860                        head = line_start
 3861                    } else {
 3862                        head = next_line_start
 3863                    }
 3864
 3865                    if head <= original_range.start {
 3866                        tail = original_range.end;
 3867                    } else {
 3868                        tail = original_range.start;
 3869                    }
 3870                }
 3871                SelectMode::All => {
 3872                    return;
 3873                }
 3874            };
 3875
 3876            if head < tail {
 3877                pending.start = buffer.anchor_before(head);
 3878                pending.end = buffer.anchor_before(tail);
 3879                pending.reversed = true;
 3880            } else {
 3881                pending.start = buffer.anchor_before(tail);
 3882                pending.end = buffer.anchor_before(head);
 3883                pending.reversed = false;
 3884            }
 3885
 3886            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3887                s.set_pending(pending.clone(), mode);
 3888            });
 3889        } else {
 3890            log::error!("update_selection dispatched with no pending selection");
 3891            return;
 3892        }
 3893
 3894        self.apply_scroll_delta(scroll_delta, window, cx);
 3895        cx.notify();
 3896    }
 3897
 3898    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3899        self.columnar_selection_state.take();
 3900        if let Some(pending_mode) = self.selections.pending_mode() {
 3901            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3902            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3903                s.select(selections);
 3904                s.clear_pending();
 3905                if s.is_extending() {
 3906                    s.set_is_extending(false);
 3907                } else {
 3908                    s.set_select_mode(pending_mode);
 3909                }
 3910            });
 3911        }
 3912    }
 3913
 3914    fn select_columns(
 3915        &mut self,
 3916        head: DisplayPoint,
 3917        goal_column: u32,
 3918        display_map: &DisplaySnapshot,
 3919        window: &mut Window,
 3920        cx: &mut Context<Self>,
 3921    ) {
 3922        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3923            return;
 3924        };
 3925
 3926        let tail = match columnar_state {
 3927            ColumnarSelectionState::FromMouse {
 3928                selection_tail,
 3929                display_point,
 3930            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3931            ColumnarSelectionState::FromSelection { selection_tail } => {
 3932                selection_tail.to_display_point(display_map)
 3933            }
 3934        };
 3935
 3936        let start_row = cmp::min(tail.row(), head.row());
 3937        let end_row = cmp::max(tail.row(), head.row());
 3938        let start_column = cmp::min(tail.column(), goal_column);
 3939        let end_column = cmp::max(tail.column(), goal_column);
 3940        let reversed = start_column < tail.column();
 3941
 3942        let selection_ranges = (start_row.0..=end_row.0)
 3943            .map(DisplayRow)
 3944            .filter_map(|row| {
 3945                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3946                    || start_column <= display_map.line_len(row))
 3947                    && !display_map.is_block_line(row)
 3948                {
 3949                    let start = display_map
 3950                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3951                        .to_point(display_map);
 3952                    let end = display_map
 3953                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3954                        .to_point(display_map);
 3955                    if reversed {
 3956                        Some(end..start)
 3957                    } else {
 3958                        Some(start..end)
 3959                    }
 3960                } else {
 3961                    None
 3962                }
 3963            })
 3964            .collect::<Vec<_>>();
 3965        if selection_ranges.is_empty() {
 3966            return;
 3967        }
 3968
 3969        let ranges = match columnar_state {
 3970            ColumnarSelectionState::FromMouse { .. } => {
 3971                let mut non_empty_ranges = selection_ranges
 3972                    .iter()
 3973                    .filter(|selection_range| selection_range.start != selection_range.end)
 3974                    .peekable();
 3975                if non_empty_ranges.peek().is_some() {
 3976                    non_empty_ranges.cloned().collect()
 3977                } else {
 3978                    selection_ranges
 3979                }
 3980            }
 3981            _ => selection_ranges,
 3982        };
 3983
 3984        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3985            s.select_ranges(ranges);
 3986        });
 3987        cx.notify();
 3988    }
 3989
 3990    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 3991        self.selections
 3992            .all_adjusted(snapshot)
 3993            .iter()
 3994            .any(|selection| !selection.is_empty())
 3995    }
 3996
 3997    pub fn has_pending_nonempty_selection(&self) -> bool {
 3998        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3999            Some(Selection { start, end, .. }) => start != end,
 4000            None => false,
 4001        };
 4002
 4003        pending_nonempty_selection
 4004            || (self.columnar_selection_state.is_some()
 4005                && self.selections.disjoint_anchors().len() > 1)
 4006    }
 4007
 4008    pub fn has_pending_selection(&self) -> bool {
 4009        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4010    }
 4011
 4012    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4013        self.selection_mark_mode = false;
 4014        self.selection_drag_state = SelectionDragState::None;
 4015
 4016        if self.clear_expanded_diff_hunks(cx) {
 4017            cx.notify();
 4018            return;
 4019        }
 4020        if self.dismiss_menus_and_popups(true, window, cx) {
 4021            return;
 4022        }
 4023
 4024        if self.mode.is_full()
 4025            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4026        {
 4027            return;
 4028        }
 4029
 4030        cx.propagate();
 4031    }
 4032
 4033    pub fn dismiss_menus_and_popups(
 4034        &mut self,
 4035        is_user_requested: bool,
 4036        window: &mut Window,
 4037        cx: &mut Context<Self>,
 4038    ) -> bool {
 4039        if self.take_rename(false, window, cx).is_some() {
 4040            return true;
 4041        }
 4042
 4043        if self.hide_blame_popover(true, cx) {
 4044            return true;
 4045        }
 4046
 4047        if hide_hover(self, cx) {
 4048            return true;
 4049        }
 4050
 4051        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 4052            return true;
 4053        }
 4054
 4055        if self.hide_context_menu(window, cx).is_some() {
 4056            return true;
 4057        }
 4058
 4059        if self.mouse_context_menu.take().is_some() {
 4060            return true;
 4061        }
 4062
 4063        if is_user_requested && self.discard_edit_prediction(true, cx) {
 4064            return true;
 4065        }
 4066
 4067        if self.snippet_stack.pop().is_some() {
 4068            return true;
 4069        }
 4070
 4071        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4072            self.dismiss_diagnostics(cx);
 4073            return true;
 4074        }
 4075
 4076        false
 4077    }
 4078
 4079    fn linked_editing_ranges_for(
 4080        &self,
 4081        selection: Range<text::Anchor>,
 4082        cx: &App,
 4083    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4084        if self.linked_edit_ranges.is_empty() {
 4085            return None;
 4086        }
 4087        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4088            selection.end.buffer_id.and_then(|end_buffer_id| {
 4089                if selection.start.buffer_id != Some(end_buffer_id) {
 4090                    return None;
 4091                }
 4092                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4093                let snapshot = buffer.read(cx).snapshot();
 4094                self.linked_edit_ranges
 4095                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4096                    .map(|ranges| (ranges, snapshot, buffer))
 4097            })?;
 4098        use text::ToOffset as TO;
 4099        // find offset from the start of current range to current cursor position
 4100        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4101
 4102        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4103        let start_difference = start_offset - start_byte_offset;
 4104        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4105        let end_difference = end_offset - start_byte_offset;
 4106        // Current range has associated linked ranges.
 4107        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4108        for range in linked_ranges.iter() {
 4109            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4110            let end_offset = start_offset + end_difference;
 4111            let start_offset = start_offset + start_difference;
 4112            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4113                continue;
 4114            }
 4115            if self.selections.disjoint_anchor_ranges().any(|s| {
 4116                if s.start.buffer_id != selection.start.buffer_id
 4117                    || s.end.buffer_id != selection.end.buffer_id
 4118                {
 4119                    return false;
 4120                }
 4121                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4122                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4123            }) {
 4124                continue;
 4125            }
 4126            let start = buffer_snapshot.anchor_after(start_offset);
 4127            let end = buffer_snapshot.anchor_after(end_offset);
 4128            linked_edits
 4129                .entry(buffer.clone())
 4130                .or_default()
 4131                .push(start..end);
 4132        }
 4133        Some(linked_edits)
 4134    }
 4135
 4136    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4137        let text: Arc<str> = text.into();
 4138
 4139        if self.read_only(cx) {
 4140            return;
 4141        }
 4142
 4143        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4144
 4145        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4146        let mut bracket_inserted = false;
 4147        let mut edits = Vec::new();
 4148        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4149        let mut new_selections = Vec::with_capacity(selections.len());
 4150        let mut new_autoclose_regions = Vec::new();
 4151        let snapshot = self.buffer.read(cx).read(cx);
 4152        let mut clear_linked_edit_ranges = false;
 4153
 4154        for (selection, autoclose_region) in
 4155            self.selections_with_autoclose_regions(selections, &snapshot)
 4156        {
 4157            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4158                // Determine if the inserted text matches the opening or closing
 4159                // bracket of any of this language's bracket pairs.
 4160                let mut bracket_pair = None;
 4161                let mut is_bracket_pair_start = false;
 4162                let mut is_bracket_pair_end = false;
 4163                if !text.is_empty() {
 4164                    let mut bracket_pair_matching_end = None;
 4165                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4166                    //  and they are removing the character that triggered IME popup.
 4167                    for (pair, enabled) in scope.brackets() {
 4168                        if !pair.close && !pair.surround {
 4169                            continue;
 4170                        }
 4171
 4172                        if enabled && pair.start.ends_with(text.as_ref()) {
 4173                            let prefix_len = pair.start.len() - text.len();
 4174                            let preceding_text_matches_prefix = prefix_len == 0
 4175                                || (selection.start.column >= (prefix_len as u32)
 4176                                    && snapshot.contains_str_at(
 4177                                        Point::new(
 4178                                            selection.start.row,
 4179                                            selection.start.column - (prefix_len as u32),
 4180                                        ),
 4181                                        &pair.start[..prefix_len],
 4182                                    ));
 4183                            if preceding_text_matches_prefix {
 4184                                bracket_pair = Some(pair.clone());
 4185                                is_bracket_pair_start = true;
 4186                                break;
 4187                            }
 4188                        }
 4189                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4190                        {
 4191                            // take first bracket pair matching end, but don't break in case a later bracket
 4192                            // pair matches start
 4193                            bracket_pair_matching_end = Some(pair.clone());
 4194                        }
 4195                    }
 4196                    if let Some(end) = bracket_pair_matching_end
 4197                        && bracket_pair.is_none()
 4198                    {
 4199                        bracket_pair = Some(end);
 4200                        is_bracket_pair_end = true;
 4201                    }
 4202                }
 4203
 4204                if let Some(bracket_pair) = bracket_pair {
 4205                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4206                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4207                    let auto_surround =
 4208                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4209                    if selection.is_empty() {
 4210                        if is_bracket_pair_start {
 4211                            // If the inserted text is a suffix of an opening bracket and the
 4212                            // selection is preceded by the rest of the opening bracket, then
 4213                            // insert the closing bracket.
 4214                            let following_text_allows_autoclose = snapshot
 4215                                .chars_at(selection.start)
 4216                                .next()
 4217                                .is_none_or(|c| scope.should_autoclose_before(c));
 4218
 4219                            let preceding_text_allows_autoclose = selection.start.column == 0
 4220                                || snapshot
 4221                                    .reversed_chars_at(selection.start)
 4222                                    .next()
 4223                                    .is_none_or(|c| {
 4224                                        bracket_pair.start != bracket_pair.end
 4225                                            || !snapshot
 4226                                                .char_classifier_at(selection.start)
 4227                                                .is_word(c)
 4228                                    });
 4229
 4230                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4231                                && bracket_pair.start.len() == 1
 4232                            {
 4233                                let target = bracket_pair.start.chars().next().unwrap();
 4234                                let current_line_count = snapshot
 4235                                    .reversed_chars_at(selection.start)
 4236                                    .take_while(|&c| c != '\n')
 4237                                    .filter(|&c| c == target)
 4238                                    .count();
 4239                                current_line_count % 2 == 1
 4240                            } else {
 4241                                false
 4242                            };
 4243
 4244                            if autoclose
 4245                                && bracket_pair.close
 4246                                && following_text_allows_autoclose
 4247                                && preceding_text_allows_autoclose
 4248                                && !is_closing_quote
 4249                            {
 4250                                let anchor = snapshot.anchor_before(selection.end);
 4251                                new_selections.push((selection.map(|_| anchor), text.len()));
 4252                                new_autoclose_regions.push((
 4253                                    anchor,
 4254                                    text.len(),
 4255                                    selection.id,
 4256                                    bracket_pair.clone(),
 4257                                ));
 4258                                edits.push((
 4259                                    selection.range(),
 4260                                    format!("{}{}", text, bracket_pair.end).into(),
 4261                                ));
 4262                                bracket_inserted = true;
 4263                                continue;
 4264                            }
 4265                        }
 4266
 4267                        if let Some(region) = autoclose_region {
 4268                            // If the selection is followed by an auto-inserted closing bracket,
 4269                            // then don't insert that closing bracket again; just move the selection
 4270                            // past the closing bracket.
 4271                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4272                                && text.as_ref() == region.pair.end.as_str()
 4273                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4274                            if should_skip {
 4275                                let anchor = snapshot.anchor_after(selection.end);
 4276                                new_selections
 4277                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4278                                continue;
 4279                            }
 4280                        }
 4281
 4282                        let always_treat_brackets_as_autoclosed = snapshot
 4283                            .language_settings_at(selection.start, cx)
 4284                            .always_treat_brackets_as_autoclosed;
 4285                        if always_treat_brackets_as_autoclosed
 4286                            && is_bracket_pair_end
 4287                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4288                        {
 4289                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4290                            // and the inserted text is a closing bracket and the selection is followed
 4291                            // by the closing bracket then move the selection past the closing bracket.
 4292                            let anchor = snapshot.anchor_after(selection.end);
 4293                            new_selections.push((selection.map(|_| anchor), text.len()));
 4294                            continue;
 4295                        }
 4296                    }
 4297                    // If an opening bracket is 1 character long and is typed while
 4298                    // text is selected, then surround that text with the bracket pair.
 4299                    else if auto_surround
 4300                        && bracket_pair.surround
 4301                        && is_bracket_pair_start
 4302                        && bracket_pair.start.chars().count() == 1
 4303                    {
 4304                        edits.push((selection.start..selection.start, text.clone()));
 4305                        edits.push((
 4306                            selection.end..selection.end,
 4307                            bracket_pair.end.as_str().into(),
 4308                        ));
 4309                        bracket_inserted = true;
 4310                        new_selections.push((
 4311                            Selection {
 4312                                id: selection.id,
 4313                                start: snapshot.anchor_after(selection.start),
 4314                                end: snapshot.anchor_before(selection.end),
 4315                                reversed: selection.reversed,
 4316                                goal: selection.goal,
 4317                            },
 4318                            0,
 4319                        ));
 4320                        continue;
 4321                    }
 4322                }
 4323            }
 4324
 4325            if self.auto_replace_emoji_shortcode
 4326                && selection.is_empty()
 4327                && text.as_ref().ends_with(':')
 4328                && let Some(possible_emoji_short_code) =
 4329                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4330                && !possible_emoji_short_code.is_empty()
 4331                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4332            {
 4333                let emoji_shortcode_start = Point::new(
 4334                    selection.start.row,
 4335                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4336                );
 4337
 4338                // Remove shortcode from buffer
 4339                edits.push((
 4340                    emoji_shortcode_start..selection.start,
 4341                    "".to_string().into(),
 4342                ));
 4343                new_selections.push((
 4344                    Selection {
 4345                        id: selection.id,
 4346                        start: snapshot.anchor_after(emoji_shortcode_start),
 4347                        end: snapshot.anchor_before(selection.start),
 4348                        reversed: selection.reversed,
 4349                        goal: selection.goal,
 4350                    },
 4351                    0,
 4352                ));
 4353
 4354                // Insert emoji
 4355                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4356                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4357                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4358
 4359                continue;
 4360            }
 4361
 4362            // If not handling any auto-close operation, then just replace the selected
 4363            // text with the given input and move the selection to the end of the
 4364            // newly inserted text.
 4365            let anchor = snapshot.anchor_after(selection.end);
 4366            if !self.linked_edit_ranges.is_empty() {
 4367                let start_anchor = snapshot.anchor_before(selection.start);
 4368
 4369                let is_word_char = text.chars().next().is_none_or(|char| {
 4370                    let classifier = snapshot
 4371                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4372                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4373                    classifier.is_word(char)
 4374                });
 4375
 4376                if is_word_char {
 4377                    if let Some(ranges) = self
 4378                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4379                    {
 4380                        for (buffer, edits) in ranges {
 4381                            linked_edits
 4382                                .entry(buffer.clone())
 4383                                .or_default()
 4384                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4385                        }
 4386                    }
 4387                } else {
 4388                    clear_linked_edit_ranges = true;
 4389                }
 4390            }
 4391
 4392            new_selections.push((selection.map(|_| anchor), 0));
 4393            edits.push((selection.start..selection.end, text.clone()));
 4394        }
 4395
 4396        drop(snapshot);
 4397
 4398        self.transact(window, cx, |this, window, cx| {
 4399            if clear_linked_edit_ranges {
 4400                this.linked_edit_ranges.clear();
 4401            }
 4402            let initial_buffer_versions =
 4403                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4404
 4405            this.buffer.update(cx, |buffer, cx| {
 4406                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4407            });
 4408            for (buffer, edits) in linked_edits {
 4409                buffer.update(cx, |buffer, cx| {
 4410                    let snapshot = buffer.snapshot();
 4411                    let edits = edits
 4412                        .into_iter()
 4413                        .map(|(range, text)| {
 4414                            use text::ToPoint as TP;
 4415                            let end_point = TP::to_point(&range.end, &snapshot);
 4416                            let start_point = TP::to_point(&range.start, &snapshot);
 4417                            (start_point..end_point, text)
 4418                        })
 4419                        .sorted_by_key(|(range, _)| range.start);
 4420                    buffer.edit(edits, None, cx);
 4421                })
 4422            }
 4423            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4424            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4425            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4426            let new_selections =
 4427                resolve_selections_wrapping_blocks::<usize, _>(new_anchor_selections, &map)
 4428                    .zip(new_selection_deltas)
 4429                    .map(|(selection, delta)| Selection {
 4430                        id: selection.id,
 4431                        start: selection.start + delta,
 4432                        end: selection.end + delta,
 4433                        reversed: selection.reversed,
 4434                        goal: SelectionGoal::None,
 4435                    })
 4436                    .collect::<Vec<_>>();
 4437
 4438            let mut i = 0;
 4439            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4440                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4441                let start = map.buffer_snapshot().anchor_before(position);
 4442                let end = map.buffer_snapshot().anchor_after(position);
 4443                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4444                    match existing_state
 4445                        .range
 4446                        .start
 4447                        .cmp(&start, map.buffer_snapshot())
 4448                    {
 4449                        Ordering::Less => i += 1,
 4450                        Ordering::Greater => break,
 4451                        Ordering::Equal => {
 4452                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4453                                Ordering::Less => i += 1,
 4454                                Ordering::Equal => break,
 4455                                Ordering::Greater => break,
 4456                            }
 4457                        }
 4458                    }
 4459                }
 4460                this.autoclose_regions.insert(
 4461                    i,
 4462                    AutocloseRegion {
 4463                        selection_id,
 4464                        range: start..end,
 4465                        pair,
 4466                    },
 4467                );
 4468            }
 4469
 4470            let had_active_edit_prediction = this.has_active_edit_prediction();
 4471            this.change_selections(
 4472                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4473                window,
 4474                cx,
 4475                |s| s.select(new_selections),
 4476            );
 4477
 4478            if !bracket_inserted
 4479                && let Some(on_type_format_task) =
 4480                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4481            {
 4482                on_type_format_task.detach_and_log_err(cx);
 4483            }
 4484
 4485            let editor_settings = EditorSettings::get_global(cx);
 4486            if bracket_inserted
 4487                && (editor_settings.auto_signature_help
 4488                    || editor_settings.show_signature_help_after_edits)
 4489            {
 4490                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4491            }
 4492
 4493            let trigger_in_words =
 4494                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4495            if this.hard_wrap.is_some() {
 4496                let latest: Range<Point> = this.selections.newest(&map).range();
 4497                if latest.is_empty()
 4498                    && this
 4499                        .buffer()
 4500                        .read(cx)
 4501                        .snapshot(cx)
 4502                        .line_len(MultiBufferRow(latest.start.row))
 4503                        == latest.start.column
 4504                {
 4505                    this.rewrap_impl(
 4506                        RewrapOptions {
 4507                            override_language_settings: true,
 4508                            preserve_existing_whitespace: true,
 4509                        },
 4510                        cx,
 4511                    )
 4512                }
 4513            }
 4514            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4515            refresh_linked_ranges(this, window, cx);
 4516            this.refresh_edit_prediction(true, false, window, cx);
 4517            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4518        });
 4519    }
 4520
 4521    fn find_possible_emoji_shortcode_at_position(
 4522        snapshot: &MultiBufferSnapshot,
 4523        position: Point,
 4524    ) -> Option<String> {
 4525        let mut chars = Vec::new();
 4526        let mut found_colon = false;
 4527        for char in snapshot.reversed_chars_at(position).take(100) {
 4528            // Found a possible emoji shortcode in the middle of the buffer
 4529            if found_colon {
 4530                if char.is_whitespace() {
 4531                    chars.reverse();
 4532                    return Some(chars.iter().collect());
 4533                }
 4534                // If the previous character is not a whitespace, we are in the middle of a word
 4535                // and we only want to complete the shortcode if the word is made up of other emojis
 4536                let mut containing_word = String::new();
 4537                for ch in snapshot
 4538                    .reversed_chars_at(position)
 4539                    .skip(chars.len() + 1)
 4540                    .take(100)
 4541                {
 4542                    if ch.is_whitespace() {
 4543                        break;
 4544                    }
 4545                    containing_word.push(ch);
 4546                }
 4547                let containing_word = containing_word.chars().rev().collect::<String>();
 4548                if util::word_consists_of_emojis(containing_word.as_str()) {
 4549                    chars.reverse();
 4550                    return Some(chars.iter().collect());
 4551                }
 4552            }
 4553
 4554            if char.is_whitespace() || !char.is_ascii() {
 4555                return None;
 4556            }
 4557            if char == ':' {
 4558                found_colon = true;
 4559            } else {
 4560                chars.push(char);
 4561            }
 4562        }
 4563        // Found a possible emoji shortcode at the beginning of the buffer
 4564        chars.reverse();
 4565        Some(chars.iter().collect())
 4566    }
 4567
 4568    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4569        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4570        self.transact(window, cx, |this, window, cx| {
 4571            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4572                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
 4573                let multi_buffer = this.buffer.read(cx);
 4574                let buffer = multi_buffer.snapshot(cx);
 4575                selections
 4576                    .iter()
 4577                    .map(|selection| {
 4578                        let start_point = selection.start.to_point(&buffer);
 4579                        let mut existing_indent =
 4580                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4581                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4582                        let start = selection.start;
 4583                        let end = selection.end;
 4584                        let selection_is_empty = start == end;
 4585                        let language_scope = buffer.language_scope_at(start);
 4586                        let (
 4587                            comment_delimiter,
 4588                            doc_delimiter,
 4589                            insert_extra_newline,
 4590                            indent_on_newline,
 4591                            indent_on_extra_newline,
 4592                        ) = if let Some(language) = &language_scope {
 4593                            let mut insert_extra_newline =
 4594                                insert_extra_newline_brackets(&buffer, start..end, language)
 4595                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4596
 4597                            // Comment extension on newline is allowed only for cursor selections
 4598                            let comment_delimiter = maybe!({
 4599                                if !selection_is_empty {
 4600                                    return None;
 4601                                }
 4602
 4603                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4604                                    return None;
 4605                                }
 4606
 4607                                let delimiters = language.line_comment_prefixes();
 4608                                let max_len_of_delimiter =
 4609                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4610                                let (snapshot, range) =
 4611                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4612
 4613                                let num_of_whitespaces = snapshot
 4614                                    .chars_for_range(range.clone())
 4615                                    .take_while(|c| c.is_whitespace())
 4616                                    .count();
 4617                                let comment_candidate = snapshot
 4618                                    .chars_for_range(range.clone())
 4619                                    .skip(num_of_whitespaces)
 4620                                    .take(max_len_of_delimiter)
 4621                                    .collect::<String>();
 4622                                let (delimiter, trimmed_len) = delimiters
 4623                                    .iter()
 4624                                    .filter_map(|delimiter| {
 4625                                        let prefix = delimiter.trim_end();
 4626                                        if comment_candidate.starts_with(prefix) {
 4627                                            Some((delimiter, prefix.len()))
 4628                                        } else {
 4629                                            None
 4630                                        }
 4631                                    })
 4632                                    .max_by_key(|(_, len)| *len)?;
 4633
 4634                                if let Some(BlockCommentConfig {
 4635                                    start: block_start, ..
 4636                                }) = language.block_comment()
 4637                                {
 4638                                    let block_start_trimmed = block_start.trim_end();
 4639                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4640                                        let line_content = snapshot
 4641                                            .chars_for_range(range)
 4642                                            .skip(num_of_whitespaces)
 4643                                            .take(block_start_trimmed.len())
 4644                                            .collect::<String>();
 4645
 4646                                        if line_content.starts_with(block_start_trimmed) {
 4647                                            return None;
 4648                                        }
 4649                                    }
 4650                                }
 4651
 4652                                let cursor_is_placed_after_comment_marker =
 4653                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4654                                if cursor_is_placed_after_comment_marker {
 4655                                    Some(delimiter.clone())
 4656                                } else {
 4657                                    None
 4658                                }
 4659                            });
 4660
 4661                            let mut indent_on_newline = IndentSize::spaces(0);
 4662                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4663
 4664                            let doc_delimiter = maybe!({
 4665                                if !selection_is_empty {
 4666                                    return None;
 4667                                }
 4668
 4669                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4670                                    return None;
 4671                                }
 4672
 4673                                let BlockCommentConfig {
 4674                                    start: start_tag,
 4675                                    end: end_tag,
 4676                                    prefix: delimiter,
 4677                                    tab_size: len,
 4678                                } = language.documentation_comment()?;
 4679                                let is_within_block_comment = buffer
 4680                                    .language_scope_at(start_point)
 4681                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4682                                if !is_within_block_comment {
 4683                                    return None;
 4684                                }
 4685
 4686                                let (snapshot, range) =
 4687                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4688
 4689                                let num_of_whitespaces = snapshot
 4690                                    .chars_for_range(range.clone())
 4691                                    .take_while(|c| c.is_whitespace())
 4692                                    .count();
 4693
 4694                                // 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.
 4695                                let column = start_point.column;
 4696                                let cursor_is_after_start_tag = {
 4697                                    let start_tag_len = start_tag.len();
 4698                                    let start_tag_line = snapshot
 4699                                        .chars_for_range(range.clone())
 4700                                        .skip(num_of_whitespaces)
 4701                                        .take(start_tag_len)
 4702                                        .collect::<String>();
 4703                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4704                                        num_of_whitespaces + start_tag_len <= column as usize
 4705                                    } else {
 4706                                        false
 4707                                    }
 4708                                };
 4709
 4710                                let cursor_is_after_delimiter = {
 4711                                    let delimiter_trim = delimiter.trim_end();
 4712                                    let delimiter_line = snapshot
 4713                                        .chars_for_range(range.clone())
 4714                                        .skip(num_of_whitespaces)
 4715                                        .take(delimiter_trim.len())
 4716                                        .collect::<String>();
 4717                                    if delimiter_line.starts_with(delimiter_trim) {
 4718                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4719                                    } else {
 4720                                        false
 4721                                    }
 4722                                };
 4723
 4724                                let cursor_is_before_end_tag_if_exists = {
 4725                                    let mut char_position = 0u32;
 4726                                    let mut end_tag_offset = None;
 4727
 4728                                    'outer: for chunk in snapshot.text_for_range(range) {
 4729                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4730                                            let chars_before_match =
 4731                                                chunk[..byte_pos].chars().count() as u32;
 4732                                            end_tag_offset =
 4733                                                Some(char_position + chars_before_match);
 4734                                            break 'outer;
 4735                                        }
 4736                                        char_position += chunk.chars().count() as u32;
 4737                                    }
 4738
 4739                                    if let Some(end_tag_offset) = end_tag_offset {
 4740                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4741                                        if cursor_is_after_start_tag {
 4742                                            if cursor_is_before_end_tag {
 4743                                                insert_extra_newline = true;
 4744                                            }
 4745                                            let cursor_is_at_start_of_end_tag =
 4746                                                column == end_tag_offset;
 4747                                            if cursor_is_at_start_of_end_tag {
 4748                                                indent_on_extra_newline.len = *len;
 4749                                            }
 4750                                        }
 4751                                        cursor_is_before_end_tag
 4752                                    } else {
 4753                                        true
 4754                                    }
 4755                                };
 4756
 4757                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4758                                    && cursor_is_before_end_tag_if_exists
 4759                                {
 4760                                    if cursor_is_after_start_tag {
 4761                                        indent_on_newline.len = *len;
 4762                                    }
 4763                                    Some(delimiter.clone())
 4764                                } else {
 4765                                    None
 4766                                }
 4767                            });
 4768
 4769                            (
 4770                                comment_delimiter,
 4771                                doc_delimiter,
 4772                                insert_extra_newline,
 4773                                indent_on_newline,
 4774                                indent_on_extra_newline,
 4775                            )
 4776                        } else {
 4777                            (
 4778                                None,
 4779                                None,
 4780                                false,
 4781                                IndentSize::default(),
 4782                                IndentSize::default(),
 4783                            )
 4784                        };
 4785
 4786                        let prevent_auto_indent = doc_delimiter.is_some();
 4787                        let delimiter = comment_delimiter.or(doc_delimiter);
 4788
 4789                        let capacity_for_delimiter =
 4790                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4791                        let mut new_text = String::with_capacity(
 4792                            1 + capacity_for_delimiter
 4793                                + existing_indent.len as usize
 4794                                + indent_on_newline.len as usize
 4795                                + indent_on_extra_newline.len as usize,
 4796                        );
 4797                        new_text.push('\n');
 4798                        new_text.extend(existing_indent.chars());
 4799                        new_text.extend(indent_on_newline.chars());
 4800
 4801                        if let Some(delimiter) = &delimiter {
 4802                            new_text.push_str(delimiter);
 4803                        }
 4804
 4805                        if insert_extra_newline {
 4806                            new_text.push('\n');
 4807                            new_text.extend(existing_indent.chars());
 4808                            new_text.extend(indent_on_extra_newline.chars());
 4809                        }
 4810
 4811                        let anchor = buffer.anchor_after(end);
 4812                        let new_selection = selection.map(|_| anchor);
 4813                        (
 4814                            ((start..end, new_text), prevent_auto_indent),
 4815                            (insert_extra_newline, new_selection),
 4816                        )
 4817                    })
 4818                    .unzip()
 4819            };
 4820
 4821            let mut auto_indent_edits = Vec::new();
 4822            let mut edits = Vec::new();
 4823            for (edit, prevent_auto_indent) in edits_with_flags {
 4824                if prevent_auto_indent {
 4825                    edits.push(edit);
 4826                } else {
 4827                    auto_indent_edits.push(edit);
 4828                }
 4829            }
 4830            if !edits.is_empty() {
 4831                this.edit(edits, cx);
 4832            }
 4833            if !auto_indent_edits.is_empty() {
 4834                this.edit_with_autoindent(auto_indent_edits, cx);
 4835            }
 4836
 4837            let buffer = this.buffer.read(cx).snapshot(cx);
 4838            let new_selections = selection_info
 4839                .into_iter()
 4840                .map(|(extra_newline_inserted, new_selection)| {
 4841                    let mut cursor = new_selection.end.to_point(&buffer);
 4842                    if extra_newline_inserted {
 4843                        cursor.row -= 1;
 4844                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4845                    }
 4846                    new_selection.map(|_| cursor)
 4847                })
 4848                .collect();
 4849
 4850            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4851            this.refresh_edit_prediction(true, false, window, cx);
 4852        });
 4853    }
 4854
 4855    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4856        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4857
 4858        let buffer = self.buffer.read(cx);
 4859        let snapshot = buffer.snapshot(cx);
 4860
 4861        let mut edits = Vec::new();
 4862        let mut rows = Vec::new();
 4863
 4864        for (rows_inserted, selection) in self
 4865            .selections
 4866            .all_adjusted(&self.display_snapshot(cx))
 4867            .into_iter()
 4868            .enumerate()
 4869        {
 4870            let cursor = selection.head();
 4871            let row = cursor.row;
 4872
 4873            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4874
 4875            let newline = "\n".to_string();
 4876            edits.push((start_of_line..start_of_line, newline));
 4877
 4878            rows.push(row + rows_inserted as u32);
 4879        }
 4880
 4881        self.transact(window, cx, |editor, window, cx| {
 4882            editor.edit(edits, cx);
 4883
 4884            editor.change_selections(Default::default(), window, cx, |s| {
 4885                let mut index = 0;
 4886                s.move_cursors_with(|map, _, _| {
 4887                    let row = rows[index];
 4888                    index += 1;
 4889
 4890                    let point = Point::new(row, 0);
 4891                    let boundary = map.next_line_boundary(point).1;
 4892                    let clipped = map.clip_point(boundary, Bias::Left);
 4893
 4894                    (clipped, SelectionGoal::None)
 4895                });
 4896            });
 4897
 4898            let mut indent_edits = Vec::new();
 4899            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4900            for row in rows {
 4901                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4902                for (row, indent) in indents {
 4903                    if indent.len == 0 {
 4904                        continue;
 4905                    }
 4906
 4907                    let text = match indent.kind {
 4908                        IndentKind::Space => " ".repeat(indent.len as usize),
 4909                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4910                    };
 4911                    let point = Point::new(row.0, 0);
 4912                    indent_edits.push((point..point, text));
 4913                }
 4914            }
 4915            editor.edit(indent_edits, cx);
 4916        });
 4917    }
 4918
 4919    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4920        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4921
 4922        let buffer = self.buffer.read(cx);
 4923        let snapshot = buffer.snapshot(cx);
 4924
 4925        let mut edits = Vec::new();
 4926        let mut rows = Vec::new();
 4927        let mut rows_inserted = 0;
 4928
 4929        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 4930            let cursor = selection.head();
 4931            let row = cursor.row;
 4932
 4933            let point = Point::new(row + 1, 0);
 4934            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4935
 4936            let newline = "\n".to_string();
 4937            edits.push((start_of_line..start_of_line, newline));
 4938
 4939            rows_inserted += 1;
 4940            rows.push(row + rows_inserted);
 4941        }
 4942
 4943        self.transact(window, cx, |editor, window, cx| {
 4944            editor.edit(edits, cx);
 4945
 4946            editor.change_selections(Default::default(), window, cx, |s| {
 4947                let mut index = 0;
 4948                s.move_cursors_with(|map, _, _| {
 4949                    let row = rows[index];
 4950                    index += 1;
 4951
 4952                    let point = Point::new(row, 0);
 4953                    let boundary = map.next_line_boundary(point).1;
 4954                    let clipped = map.clip_point(boundary, Bias::Left);
 4955
 4956                    (clipped, SelectionGoal::None)
 4957                });
 4958            });
 4959
 4960            let mut indent_edits = Vec::new();
 4961            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4962            for row in rows {
 4963                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4964                for (row, indent) in indents {
 4965                    if indent.len == 0 {
 4966                        continue;
 4967                    }
 4968
 4969                    let text = match indent.kind {
 4970                        IndentKind::Space => " ".repeat(indent.len as usize),
 4971                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4972                    };
 4973                    let point = Point::new(row.0, 0);
 4974                    indent_edits.push((point..point, text));
 4975                }
 4976            }
 4977            editor.edit(indent_edits, cx);
 4978        });
 4979    }
 4980
 4981    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4982        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4983            original_indent_columns: Vec::new(),
 4984        });
 4985        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4986    }
 4987
 4988    fn insert_with_autoindent_mode(
 4989        &mut self,
 4990        text: &str,
 4991        autoindent_mode: Option<AutoindentMode>,
 4992        window: &mut Window,
 4993        cx: &mut Context<Self>,
 4994    ) {
 4995        if self.read_only(cx) {
 4996            return;
 4997        }
 4998
 4999        let text: Arc<str> = text.into();
 5000        self.transact(window, cx, |this, window, cx| {
 5001            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5002            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5003                let anchors = {
 5004                    let snapshot = buffer.read(cx);
 5005                    old_selections
 5006                        .iter()
 5007                        .map(|s| {
 5008                            let anchor = snapshot.anchor_after(s.head());
 5009                            s.map(|_| anchor)
 5010                        })
 5011                        .collect::<Vec<_>>()
 5012                };
 5013                buffer.edit(
 5014                    old_selections
 5015                        .iter()
 5016                        .map(|s| (s.start..s.end, text.clone())),
 5017                    autoindent_mode,
 5018                    cx,
 5019                );
 5020                anchors
 5021            });
 5022
 5023            this.change_selections(Default::default(), window, cx, |s| {
 5024                s.select_anchors(selection_anchors);
 5025            });
 5026
 5027            cx.notify();
 5028        });
 5029    }
 5030
 5031    fn trigger_completion_on_input(
 5032        &mut self,
 5033        text: &str,
 5034        trigger_in_words: bool,
 5035        window: &mut Window,
 5036        cx: &mut Context<Self>,
 5037    ) {
 5038        let completions_source = self
 5039            .context_menu
 5040            .borrow()
 5041            .as_ref()
 5042            .and_then(|menu| match menu {
 5043                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5044                CodeContextMenu::CodeActions(_) => None,
 5045            });
 5046
 5047        match completions_source {
 5048            Some(CompletionsMenuSource::Words { .. }) => {
 5049                self.open_or_update_completions_menu(
 5050                    Some(CompletionsMenuSource::Words {
 5051                        ignore_threshold: false,
 5052                    }),
 5053                    None,
 5054                    window,
 5055                    cx,
 5056                );
 5057            }
 5058            Some(CompletionsMenuSource::Normal)
 5059            | Some(CompletionsMenuSource::SnippetChoices)
 5060            | None
 5061                if self.is_completion_trigger(
 5062                    text,
 5063                    trigger_in_words,
 5064                    completions_source.is_some(),
 5065                    cx,
 5066                ) =>
 5067            {
 5068                self.show_completions(
 5069                    &ShowCompletions {
 5070                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 5071                    },
 5072                    window,
 5073                    cx,
 5074                )
 5075            }
 5076            _ => {
 5077                self.hide_context_menu(window, cx);
 5078            }
 5079        }
 5080    }
 5081
 5082    fn is_completion_trigger(
 5083        &self,
 5084        text: &str,
 5085        trigger_in_words: bool,
 5086        menu_is_open: bool,
 5087        cx: &mut Context<Self>,
 5088    ) -> bool {
 5089        let position = self.selections.newest_anchor().head();
 5090        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 5091            return false;
 5092        };
 5093
 5094        if let Some(completion_provider) = &self.completion_provider {
 5095            completion_provider.is_completion_trigger(
 5096                &buffer,
 5097                position.text_anchor,
 5098                text,
 5099                trigger_in_words,
 5100                menu_is_open,
 5101                cx,
 5102            )
 5103        } else {
 5104            false
 5105        }
 5106    }
 5107
 5108    /// If any empty selections is touching the start of its innermost containing autoclose
 5109    /// region, expand it to select the brackets.
 5110    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5111        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5112        let buffer = self.buffer.read(cx).read(cx);
 5113        let new_selections = self
 5114            .selections_with_autoclose_regions(selections, &buffer)
 5115            .map(|(mut selection, region)| {
 5116                if !selection.is_empty() {
 5117                    return selection;
 5118                }
 5119
 5120                if let Some(region) = region {
 5121                    let mut range = region.range.to_offset(&buffer);
 5122                    if selection.start == range.start && range.start >= region.pair.start.len() {
 5123                        range.start -= region.pair.start.len();
 5124                        if buffer.contains_str_at(range.start, &region.pair.start)
 5125                            && buffer.contains_str_at(range.end, &region.pair.end)
 5126                        {
 5127                            range.end += region.pair.end.len();
 5128                            selection.start = range.start;
 5129                            selection.end = range.end;
 5130
 5131                            return selection;
 5132                        }
 5133                    }
 5134                }
 5135
 5136                let always_treat_brackets_as_autoclosed = buffer
 5137                    .language_settings_at(selection.start, cx)
 5138                    .always_treat_brackets_as_autoclosed;
 5139
 5140                if !always_treat_brackets_as_autoclosed {
 5141                    return selection;
 5142                }
 5143
 5144                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5145                    for (pair, enabled) in scope.brackets() {
 5146                        if !enabled || !pair.close {
 5147                            continue;
 5148                        }
 5149
 5150                        if buffer.contains_str_at(selection.start, &pair.end) {
 5151                            let pair_start_len = pair.start.len();
 5152                            if buffer.contains_str_at(
 5153                                selection.start.saturating_sub(pair_start_len),
 5154                                &pair.start,
 5155                            ) {
 5156                                selection.start -= pair_start_len;
 5157                                selection.end += pair.end.len();
 5158
 5159                                return selection;
 5160                            }
 5161                        }
 5162                    }
 5163                }
 5164
 5165                selection
 5166            })
 5167            .collect();
 5168
 5169        drop(buffer);
 5170        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5171            selections.select(new_selections)
 5172        });
 5173    }
 5174
 5175    /// Iterate the given selections, and for each one, find the smallest surrounding
 5176    /// autoclose region. This uses the ordering of the selections and the autoclose
 5177    /// regions to avoid repeated comparisons.
 5178    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5179        &'a self,
 5180        selections: impl IntoIterator<Item = Selection<D>>,
 5181        buffer: &'a MultiBufferSnapshot,
 5182    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5183        let mut i = 0;
 5184        let mut regions = self.autoclose_regions.as_slice();
 5185        selections.into_iter().map(move |selection| {
 5186            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5187
 5188            let mut enclosing = None;
 5189            while let Some(pair_state) = regions.get(i) {
 5190                if pair_state.range.end.to_offset(buffer) < range.start {
 5191                    regions = &regions[i + 1..];
 5192                    i = 0;
 5193                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5194                    break;
 5195                } else {
 5196                    if pair_state.selection_id == selection.id {
 5197                        enclosing = Some(pair_state);
 5198                    }
 5199                    i += 1;
 5200                }
 5201            }
 5202
 5203            (selection, enclosing)
 5204        })
 5205    }
 5206
 5207    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5208    fn invalidate_autoclose_regions(
 5209        &mut self,
 5210        mut selections: &[Selection<Anchor>],
 5211        buffer: &MultiBufferSnapshot,
 5212    ) {
 5213        self.autoclose_regions.retain(|state| {
 5214            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5215                return false;
 5216            }
 5217
 5218            let mut i = 0;
 5219            while let Some(selection) = selections.get(i) {
 5220                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5221                    selections = &selections[1..];
 5222                    continue;
 5223                }
 5224                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5225                    break;
 5226                }
 5227                if selection.id == state.selection_id {
 5228                    return true;
 5229                } else {
 5230                    i += 1;
 5231                }
 5232            }
 5233            false
 5234        });
 5235    }
 5236
 5237    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5238        let offset = position.to_offset(buffer);
 5239        let (word_range, kind) =
 5240            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5241        if offset > word_range.start && kind == Some(CharKind::Word) {
 5242            Some(
 5243                buffer
 5244                    .text_for_range(word_range.start..offset)
 5245                    .collect::<String>(),
 5246            )
 5247        } else {
 5248            None
 5249        }
 5250    }
 5251
 5252    pub fn visible_excerpts(
 5253        &self,
 5254        cx: &mut Context<Editor>,
 5255    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5256        let Some(project) = self.project() else {
 5257            return HashMap::default();
 5258        };
 5259        let project = project.read(cx);
 5260        let multi_buffer = self.buffer().read(cx);
 5261        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5262        let multi_buffer_visible_start = self
 5263            .scroll_manager
 5264            .anchor()
 5265            .anchor
 5266            .to_point(&multi_buffer_snapshot);
 5267        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5268            multi_buffer_visible_start
 5269                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5270            Bias::Left,
 5271        );
 5272        multi_buffer_snapshot
 5273            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5274            .into_iter()
 5275            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5276            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5277                let buffer_file = project::File::from_dyn(buffer.file())?;
 5278                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5279                let worktree_entry = buffer_worktree
 5280                    .read(cx)
 5281                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5282                if worktree_entry.is_ignored {
 5283                    None
 5284                } else {
 5285                    Some((
 5286                        excerpt_id,
 5287                        (
 5288                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5289                            buffer.version().clone(),
 5290                            excerpt_visible_range,
 5291                        ),
 5292                    ))
 5293                }
 5294            })
 5295            .collect()
 5296    }
 5297
 5298    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5299        TextLayoutDetails {
 5300            text_system: window.text_system().clone(),
 5301            editor_style: self.style.clone().unwrap(),
 5302            rem_size: window.rem_size(),
 5303            scroll_anchor: self.scroll_manager.anchor(),
 5304            visible_rows: self.visible_line_count(),
 5305            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5306        }
 5307    }
 5308
 5309    fn trigger_on_type_formatting(
 5310        &self,
 5311        input: String,
 5312        window: &mut Window,
 5313        cx: &mut Context<Self>,
 5314    ) -> Option<Task<Result<()>>> {
 5315        if input.len() != 1 {
 5316            return None;
 5317        }
 5318
 5319        let project = self.project()?;
 5320        let position = self.selections.newest_anchor().head();
 5321        let (buffer, buffer_position) = self
 5322            .buffer
 5323            .read(cx)
 5324            .text_anchor_for_position(position, cx)?;
 5325
 5326        let settings = language_settings::language_settings(
 5327            buffer
 5328                .read(cx)
 5329                .language_at(buffer_position)
 5330                .map(|l| l.name()),
 5331            buffer.read(cx).file(),
 5332            cx,
 5333        );
 5334        if !settings.use_on_type_format {
 5335            return None;
 5336        }
 5337
 5338        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5339        // hence we do LSP request & edit on host side only — add formats to host's history.
 5340        let push_to_lsp_host_history = true;
 5341        // If this is not the host, append its history with new edits.
 5342        let push_to_client_history = project.read(cx).is_via_collab();
 5343
 5344        let on_type_formatting = project.update(cx, |project, cx| {
 5345            project.on_type_format(
 5346                buffer.clone(),
 5347                buffer_position,
 5348                input,
 5349                push_to_lsp_host_history,
 5350                cx,
 5351            )
 5352        });
 5353        Some(cx.spawn_in(window, async move |editor, cx| {
 5354            if let Some(transaction) = on_type_formatting.await? {
 5355                if push_to_client_history {
 5356                    buffer
 5357                        .update(cx, |buffer, _| {
 5358                            buffer.push_transaction(transaction, Instant::now());
 5359                            buffer.finalize_last_transaction();
 5360                        })
 5361                        .ok();
 5362                }
 5363                editor.update(cx, |editor, cx| {
 5364                    editor.refresh_document_highlights(cx);
 5365                })?;
 5366            }
 5367            Ok(())
 5368        }))
 5369    }
 5370
 5371    pub fn show_word_completions(
 5372        &mut self,
 5373        _: &ShowWordCompletions,
 5374        window: &mut Window,
 5375        cx: &mut Context<Self>,
 5376    ) {
 5377        self.open_or_update_completions_menu(
 5378            Some(CompletionsMenuSource::Words {
 5379                ignore_threshold: true,
 5380            }),
 5381            None,
 5382            window,
 5383            cx,
 5384        );
 5385    }
 5386
 5387    pub fn show_completions(
 5388        &mut self,
 5389        options: &ShowCompletions,
 5390        window: &mut Window,
 5391        cx: &mut Context<Self>,
 5392    ) {
 5393        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5394    }
 5395
 5396    fn open_or_update_completions_menu(
 5397        &mut self,
 5398        requested_source: Option<CompletionsMenuSource>,
 5399        trigger: Option<&str>,
 5400        window: &mut Window,
 5401        cx: &mut Context<Self>,
 5402    ) {
 5403        if self.pending_rename.is_some() {
 5404            return;
 5405        }
 5406
 5407        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5408
 5409        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5410        // inserted and selected. To handle that case, the start of the selection is used so that
 5411        // the menu starts with all choices.
 5412        let position = self
 5413            .selections
 5414            .newest_anchor()
 5415            .start
 5416            .bias_right(&multibuffer_snapshot);
 5417        if position.diff_base_anchor.is_some() {
 5418            return;
 5419        }
 5420        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5421        let Some(buffer) = buffer_position
 5422            .buffer_id
 5423            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5424        else {
 5425            return;
 5426        };
 5427        let buffer_snapshot = buffer.read(cx).snapshot();
 5428
 5429        let query: Option<Arc<String>> =
 5430            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5431                .map(|query| query.into());
 5432
 5433        drop(multibuffer_snapshot);
 5434
 5435        // Hide the current completions menu when query is empty. Without this, cached
 5436        // completions from before the trigger char may be reused (#32774).
 5437        if query.is_none() {
 5438            let menu_is_open = matches!(
 5439                self.context_menu.borrow().as_ref(),
 5440                Some(CodeContextMenu::Completions(_))
 5441            );
 5442            if menu_is_open {
 5443                self.hide_context_menu(window, cx);
 5444            }
 5445        }
 5446
 5447        let mut ignore_word_threshold = false;
 5448        let provider = match requested_source {
 5449            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5450            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5451                ignore_word_threshold = ignore_threshold;
 5452                None
 5453            }
 5454            Some(CompletionsMenuSource::SnippetChoices) => {
 5455                log::error!("bug: SnippetChoices requested_source is not handled");
 5456                None
 5457            }
 5458        };
 5459
 5460        let sort_completions = provider
 5461            .as_ref()
 5462            .is_some_and(|provider| provider.sort_completions());
 5463
 5464        let filter_completions = provider
 5465            .as_ref()
 5466            .is_none_or(|provider| provider.filter_completions());
 5467
 5468        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5469            if filter_completions {
 5470                menu.filter(query.clone(), provider.clone(), window, cx);
 5471            }
 5472            // When `is_incomplete` is false, no need to re-query completions when the current query
 5473            // is a suffix of the initial query.
 5474            if !menu.is_incomplete {
 5475                // If the new query is a suffix of the old query (typing more characters) and
 5476                // the previous result was complete, the existing completions can be filtered.
 5477                //
 5478                // Note that this is always true for snippet completions.
 5479                let query_matches = match (&menu.initial_query, &query) {
 5480                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5481                    (None, _) => true,
 5482                    _ => false,
 5483                };
 5484                if query_matches {
 5485                    let position_matches = if menu.initial_position == position {
 5486                        true
 5487                    } else {
 5488                        let snapshot = self.buffer.read(cx).read(cx);
 5489                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5490                    };
 5491                    if position_matches {
 5492                        return;
 5493                    }
 5494                }
 5495            }
 5496        };
 5497
 5498        let trigger_kind = match trigger {
 5499            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5500                CompletionTriggerKind::TRIGGER_CHARACTER
 5501            }
 5502            _ => CompletionTriggerKind::INVOKED,
 5503        };
 5504        let completion_context = CompletionContext {
 5505            trigger_character: trigger.and_then(|trigger| {
 5506                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5507                    Some(String::from(trigger))
 5508                } else {
 5509                    None
 5510                }
 5511            }),
 5512            trigger_kind,
 5513        };
 5514
 5515        let Anchor {
 5516            excerpt_id: buffer_excerpt_id,
 5517            text_anchor: buffer_position,
 5518            ..
 5519        } = buffer_position;
 5520
 5521        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5522            buffer_snapshot.surrounding_word(buffer_position, None)
 5523        {
 5524            let word_to_exclude = buffer_snapshot
 5525                .text_for_range(word_range.clone())
 5526                .collect::<String>();
 5527            (
 5528                buffer_snapshot.anchor_before(word_range.start)
 5529                    ..buffer_snapshot.anchor_after(buffer_position),
 5530                Some(word_to_exclude),
 5531            )
 5532        } else {
 5533            (buffer_position..buffer_position, None)
 5534        };
 5535
 5536        let language = buffer_snapshot
 5537            .language_at(buffer_position)
 5538            .map(|language| language.name());
 5539
 5540        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5541            .completions
 5542            .clone();
 5543
 5544        let show_completion_documentation = buffer_snapshot
 5545            .settings_at(buffer_position, cx)
 5546            .show_completion_documentation;
 5547
 5548        // The document can be large, so stay in reasonable bounds when searching for words,
 5549        // otherwise completion pop-up might be slow to appear.
 5550        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5551        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5552        let min_word_search = buffer_snapshot.clip_point(
 5553            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5554            Bias::Left,
 5555        );
 5556        let max_word_search = buffer_snapshot.clip_point(
 5557            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5558            Bias::Right,
 5559        );
 5560        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5561            ..buffer_snapshot.point_to_offset(max_word_search);
 5562
 5563        let skip_digits = query
 5564            .as_ref()
 5565            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5566
 5567        let omit_word_completions = !self.word_completions_enabled
 5568            || (!ignore_word_threshold
 5569                && match &query {
 5570                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5571                    None => completion_settings.words_min_length != 0,
 5572                });
 5573
 5574        let (mut words, provider_responses) = match &provider {
 5575            Some(provider) => {
 5576                let provider_responses = provider.completions(
 5577                    buffer_excerpt_id,
 5578                    &buffer,
 5579                    buffer_position,
 5580                    completion_context,
 5581                    window,
 5582                    cx,
 5583                );
 5584
 5585                let words = match (omit_word_completions, completion_settings.words) {
 5586                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5587                        Task::ready(BTreeMap::default())
 5588                    }
 5589                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5590                        .background_spawn(async move {
 5591                            buffer_snapshot.words_in_range(WordsQuery {
 5592                                fuzzy_contents: None,
 5593                                range: word_search_range,
 5594                                skip_digits,
 5595                            })
 5596                        }),
 5597                };
 5598
 5599                (words, provider_responses)
 5600            }
 5601            None => {
 5602                let words = if omit_word_completions {
 5603                    Task::ready(BTreeMap::default())
 5604                } else {
 5605                    cx.background_spawn(async move {
 5606                        buffer_snapshot.words_in_range(WordsQuery {
 5607                            fuzzy_contents: None,
 5608                            range: word_search_range,
 5609                            skip_digits,
 5610                        })
 5611                    })
 5612                };
 5613                (words, Task::ready(Ok(Vec::new())))
 5614            }
 5615        };
 5616
 5617        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5618
 5619        let id = post_inc(&mut self.next_completion_id);
 5620        let task = cx.spawn_in(window, async move |editor, cx| {
 5621            let Ok(()) = editor.update(cx, |this, _| {
 5622                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5623            }) else {
 5624                return;
 5625            };
 5626
 5627            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5628            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5629            let mut completions = Vec::new();
 5630            let mut is_incomplete = false;
 5631            let mut display_options: Option<CompletionDisplayOptions> = None;
 5632            if let Some(provider_responses) = provider_responses.await.log_err()
 5633                && !provider_responses.is_empty()
 5634            {
 5635                for response in provider_responses {
 5636                    completions.extend(response.completions);
 5637                    is_incomplete = is_incomplete || response.is_incomplete;
 5638                    match display_options.as_mut() {
 5639                        None => {
 5640                            display_options = Some(response.display_options);
 5641                        }
 5642                        Some(options) => options.merge(&response.display_options),
 5643                    }
 5644                }
 5645                if completion_settings.words == WordsCompletionMode::Fallback {
 5646                    words = Task::ready(BTreeMap::default());
 5647                }
 5648            }
 5649            let display_options = display_options.unwrap_or_default();
 5650
 5651            let mut words = words.await;
 5652            if let Some(word_to_exclude) = &word_to_exclude {
 5653                words.remove(word_to_exclude);
 5654            }
 5655            for lsp_completion in &completions {
 5656                words.remove(&lsp_completion.new_text);
 5657            }
 5658            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5659                replace_range: word_replace_range.clone(),
 5660                new_text: word.clone(),
 5661                label: CodeLabel::plain(word, None),
 5662                icon_path: None,
 5663                documentation: None,
 5664                source: CompletionSource::BufferWord {
 5665                    word_range,
 5666                    resolved: false,
 5667                },
 5668                insert_text_mode: Some(InsertTextMode::AS_IS),
 5669                confirm: None,
 5670            }));
 5671
 5672            let menu = if completions.is_empty() {
 5673                None
 5674            } else {
 5675                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5676                    let languages = editor
 5677                        .workspace
 5678                        .as_ref()
 5679                        .and_then(|(workspace, _)| workspace.upgrade())
 5680                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5681                    let menu = CompletionsMenu::new(
 5682                        id,
 5683                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5684                        sort_completions,
 5685                        show_completion_documentation,
 5686                        position,
 5687                        query.clone(),
 5688                        is_incomplete,
 5689                        buffer.clone(),
 5690                        completions.into(),
 5691                        display_options,
 5692                        snippet_sort_order,
 5693                        languages,
 5694                        language,
 5695                        cx,
 5696                    );
 5697
 5698                    let query = if filter_completions { query } else { None };
 5699                    let matches_task = if let Some(query) = query {
 5700                        menu.do_async_filtering(query, cx)
 5701                    } else {
 5702                        Task::ready(menu.unfiltered_matches())
 5703                    };
 5704                    (menu, matches_task)
 5705                }) else {
 5706                    return;
 5707                };
 5708
 5709                let matches = matches_task.await;
 5710
 5711                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5712                    // Newer menu already set, so exit.
 5713                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5714                        editor.context_menu.borrow().as_ref()
 5715                        && prev_menu.id > id
 5716                    {
 5717                        return;
 5718                    };
 5719
 5720                    // Only valid to take prev_menu because it the new menu is immediately set
 5721                    // below, or the menu is hidden.
 5722                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5723                        editor.context_menu.borrow_mut().take()
 5724                    {
 5725                        let position_matches =
 5726                            if prev_menu.initial_position == menu.initial_position {
 5727                                true
 5728                            } else {
 5729                                let snapshot = editor.buffer.read(cx).read(cx);
 5730                                prev_menu.initial_position.to_offset(&snapshot)
 5731                                    == menu.initial_position.to_offset(&snapshot)
 5732                            };
 5733                        if position_matches {
 5734                            // Preserve markdown cache before `set_filter_results` because it will
 5735                            // try to populate the documentation cache.
 5736                            menu.preserve_markdown_cache(prev_menu);
 5737                        }
 5738                    };
 5739
 5740                    menu.set_filter_results(matches, provider, window, cx);
 5741                }) else {
 5742                    return;
 5743                };
 5744
 5745                menu.visible().then_some(menu)
 5746            };
 5747
 5748            editor
 5749                .update_in(cx, |editor, window, cx| {
 5750                    if editor.focus_handle.is_focused(window)
 5751                        && let Some(menu) = menu
 5752                    {
 5753                        *editor.context_menu.borrow_mut() =
 5754                            Some(CodeContextMenu::Completions(menu));
 5755
 5756                        crate::hover_popover::hide_hover(editor, cx);
 5757                        if editor.show_edit_predictions_in_menu() {
 5758                            editor.update_visible_edit_prediction(window, cx);
 5759                        } else {
 5760                            editor.discard_edit_prediction(false, cx);
 5761                        }
 5762
 5763                        cx.notify();
 5764                        return;
 5765                    }
 5766
 5767                    if editor.completion_tasks.len() <= 1 {
 5768                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5769                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5770                        // If it was already hidden and we don't show edit predictions in the menu,
 5771                        // we should also show the edit prediction when available.
 5772                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5773                            editor.update_visible_edit_prediction(window, cx);
 5774                        }
 5775                    }
 5776                })
 5777                .ok();
 5778        });
 5779
 5780        self.completion_tasks.push((id, task));
 5781    }
 5782
 5783    #[cfg(feature = "test-support")]
 5784    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5785        let menu = self.context_menu.borrow();
 5786        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5787            let completions = menu.completions.borrow();
 5788            Some(completions.to_vec())
 5789        } else {
 5790            None
 5791        }
 5792    }
 5793
 5794    pub fn with_completions_menu_matching_id<R>(
 5795        &self,
 5796        id: CompletionId,
 5797        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5798    ) -> R {
 5799        let mut context_menu = self.context_menu.borrow_mut();
 5800        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5801            return f(None);
 5802        };
 5803        if completions_menu.id != id {
 5804            return f(None);
 5805        }
 5806        f(Some(completions_menu))
 5807    }
 5808
 5809    pub fn confirm_completion(
 5810        &mut self,
 5811        action: &ConfirmCompletion,
 5812        window: &mut Window,
 5813        cx: &mut Context<Self>,
 5814    ) -> Option<Task<Result<()>>> {
 5815        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5816        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5817    }
 5818
 5819    pub fn confirm_completion_insert(
 5820        &mut self,
 5821        _: &ConfirmCompletionInsert,
 5822        window: &mut Window,
 5823        cx: &mut Context<Self>,
 5824    ) -> Option<Task<Result<()>>> {
 5825        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5826        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5827    }
 5828
 5829    pub fn confirm_completion_replace(
 5830        &mut self,
 5831        _: &ConfirmCompletionReplace,
 5832        window: &mut Window,
 5833        cx: &mut Context<Self>,
 5834    ) -> Option<Task<Result<()>>> {
 5835        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5836        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5837    }
 5838
 5839    pub fn compose_completion(
 5840        &mut self,
 5841        action: &ComposeCompletion,
 5842        window: &mut Window,
 5843        cx: &mut Context<Self>,
 5844    ) -> Option<Task<Result<()>>> {
 5845        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5846        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5847    }
 5848
 5849    fn do_completion(
 5850        &mut self,
 5851        item_ix: Option<usize>,
 5852        intent: CompletionIntent,
 5853        window: &mut Window,
 5854        cx: &mut Context<Editor>,
 5855    ) -> Option<Task<Result<()>>> {
 5856        use language::ToOffset as _;
 5857
 5858        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5859        else {
 5860            return None;
 5861        };
 5862
 5863        let candidate_id = {
 5864            let entries = completions_menu.entries.borrow();
 5865            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5866            if self.show_edit_predictions_in_menu() {
 5867                self.discard_edit_prediction(true, cx);
 5868            }
 5869            mat.candidate_id
 5870        };
 5871
 5872        let completion = completions_menu
 5873            .completions
 5874            .borrow()
 5875            .get(candidate_id)?
 5876            .clone();
 5877        cx.stop_propagation();
 5878
 5879        let buffer_handle = completions_menu.buffer.clone();
 5880
 5881        let CompletionEdit {
 5882            new_text,
 5883            snippet,
 5884            replace_range,
 5885        } = process_completion_for_edit(
 5886            &completion,
 5887            intent,
 5888            &buffer_handle,
 5889            &completions_menu.initial_position.text_anchor,
 5890            cx,
 5891        );
 5892
 5893        let buffer = buffer_handle.read(cx);
 5894        let snapshot = self.buffer.read(cx).snapshot(cx);
 5895        let newest_anchor = self.selections.newest_anchor();
 5896        let replace_range_multibuffer = {
 5897            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5898            excerpt.map_range_from_buffer(replace_range.clone())
 5899        };
 5900        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5901            return None;
 5902        }
 5903
 5904        let old_text = buffer
 5905            .text_for_range(replace_range.clone())
 5906            .collect::<String>();
 5907        let lookbehind = newest_anchor
 5908            .start
 5909            .text_anchor
 5910            .to_offset(buffer)
 5911            .saturating_sub(replace_range.start);
 5912        let lookahead = replace_range
 5913            .end
 5914            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5915        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5916        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5917
 5918        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5919        let mut ranges = Vec::new();
 5920        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5921
 5922        for selection in &selections {
 5923            let range = if selection.id == newest_anchor.id {
 5924                replace_range_multibuffer.clone()
 5925            } else {
 5926                let mut range = selection.range();
 5927
 5928                // if prefix is present, don't duplicate it
 5929                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5930                    range.start = range.start.saturating_sub(lookbehind);
 5931
 5932                    // if suffix is also present, mimic the newest cursor and replace it
 5933                    if selection.id != newest_anchor.id
 5934                        && snapshot.contains_str_at(range.end, suffix)
 5935                    {
 5936                        range.end += lookahead;
 5937                    }
 5938                }
 5939                range
 5940            };
 5941
 5942            ranges.push(range.clone());
 5943
 5944            if !self.linked_edit_ranges.is_empty() {
 5945                let start_anchor = snapshot.anchor_before(range.start);
 5946                let end_anchor = snapshot.anchor_after(range.end);
 5947                if let Some(ranges) = self
 5948                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5949                {
 5950                    for (buffer, edits) in ranges {
 5951                        linked_edits
 5952                            .entry(buffer.clone())
 5953                            .or_default()
 5954                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5955                    }
 5956                }
 5957            }
 5958        }
 5959
 5960        let common_prefix_len = old_text
 5961            .chars()
 5962            .zip(new_text.chars())
 5963            .take_while(|(a, b)| a == b)
 5964            .map(|(a, _)| a.len_utf8())
 5965            .sum::<usize>();
 5966
 5967        cx.emit(EditorEvent::InputHandled {
 5968            utf16_range_to_replace: None,
 5969            text: new_text[common_prefix_len..].into(),
 5970        });
 5971
 5972        self.transact(window, cx, |editor, window, cx| {
 5973            if let Some(mut snippet) = snippet {
 5974                snippet.text = new_text.to_string();
 5975                editor
 5976                    .insert_snippet(&ranges, snippet, window, cx)
 5977                    .log_err();
 5978            } else {
 5979                editor.buffer.update(cx, |multi_buffer, cx| {
 5980                    let auto_indent = match completion.insert_text_mode {
 5981                        Some(InsertTextMode::AS_IS) => None,
 5982                        _ => editor.autoindent_mode.clone(),
 5983                    };
 5984                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5985                    multi_buffer.edit(edits, auto_indent, cx);
 5986                });
 5987            }
 5988            for (buffer, edits) in linked_edits {
 5989                buffer.update(cx, |buffer, cx| {
 5990                    let snapshot = buffer.snapshot();
 5991                    let edits = edits
 5992                        .into_iter()
 5993                        .map(|(range, text)| {
 5994                            use text::ToPoint as TP;
 5995                            let end_point = TP::to_point(&range.end, &snapshot);
 5996                            let start_point = TP::to_point(&range.start, &snapshot);
 5997                            (start_point..end_point, text)
 5998                        })
 5999                        .sorted_by_key(|(range, _)| range.start);
 6000                    buffer.edit(edits, None, cx);
 6001                })
 6002            }
 6003
 6004            editor.refresh_edit_prediction(true, false, window, cx);
 6005        });
 6006        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6007
 6008        let show_new_completions_on_confirm = completion
 6009            .confirm
 6010            .as_ref()
 6011            .is_some_and(|confirm| confirm(intent, window, cx));
 6012        if show_new_completions_on_confirm {
 6013            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6014        }
 6015
 6016        let provider = self.completion_provider.as_ref()?;
 6017        drop(completion);
 6018        let apply_edits = provider.apply_additional_edits_for_completion(
 6019            buffer_handle,
 6020            completions_menu.completions.clone(),
 6021            candidate_id,
 6022            true,
 6023            cx,
 6024        );
 6025
 6026        let editor_settings = EditorSettings::get_global(cx);
 6027        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6028            // After the code completion is finished, users often want to know what signatures are needed.
 6029            // so we should automatically call signature_help
 6030            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6031        }
 6032
 6033        Some(cx.foreground_executor().spawn(async move {
 6034            apply_edits.await?;
 6035            Ok(())
 6036        }))
 6037    }
 6038
 6039    pub fn toggle_code_actions(
 6040        &mut self,
 6041        action: &ToggleCodeActions,
 6042        window: &mut Window,
 6043        cx: &mut Context<Self>,
 6044    ) {
 6045        let quick_launch = action.quick_launch;
 6046        let mut context_menu = self.context_menu.borrow_mut();
 6047        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6048            if code_actions.deployed_from == action.deployed_from {
 6049                // Toggle if we're selecting the same one
 6050                *context_menu = None;
 6051                cx.notify();
 6052                return;
 6053            } else {
 6054                // Otherwise, clear it and start a new one
 6055                *context_menu = None;
 6056                cx.notify();
 6057            }
 6058        }
 6059        drop(context_menu);
 6060        let snapshot = self.snapshot(window, cx);
 6061        let deployed_from = action.deployed_from.clone();
 6062        let action = action.clone();
 6063        self.completion_tasks.clear();
 6064        self.discard_edit_prediction(false, cx);
 6065
 6066        let multibuffer_point = match &action.deployed_from {
 6067            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6068                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6069            }
 6070            _ => self
 6071                .selections
 6072                .newest::<Point>(&snapshot.display_snapshot)
 6073                .head(),
 6074        };
 6075        let Some((buffer, buffer_row)) = snapshot
 6076            .buffer_snapshot()
 6077            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6078            .and_then(|(buffer_snapshot, range)| {
 6079                self.buffer()
 6080                    .read(cx)
 6081                    .buffer(buffer_snapshot.remote_id())
 6082                    .map(|buffer| (buffer, range.start.row))
 6083            })
 6084        else {
 6085            return;
 6086        };
 6087        let buffer_id = buffer.read(cx).remote_id();
 6088        let tasks = self
 6089            .tasks
 6090            .get(&(buffer_id, buffer_row))
 6091            .map(|t| Arc::new(t.to_owned()));
 6092
 6093        if !self.focus_handle.is_focused(window) {
 6094            return;
 6095        }
 6096        let project = self.project.clone();
 6097
 6098        let code_actions_task = match deployed_from {
 6099            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6100            _ => self.code_actions(buffer_row, window, cx),
 6101        };
 6102
 6103        let runnable_task = match deployed_from {
 6104            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6105            _ => {
 6106                let mut task_context_task = Task::ready(None);
 6107                if let Some(tasks) = &tasks
 6108                    && let Some(project) = project
 6109                {
 6110                    task_context_task =
 6111                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6112                }
 6113
 6114                cx.spawn_in(window, {
 6115                    let buffer = buffer.clone();
 6116                    async move |editor, cx| {
 6117                        let task_context = task_context_task.await;
 6118
 6119                        let resolved_tasks =
 6120                            tasks
 6121                                .zip(task_context.clone())
 6122                                .map(|(tasks, task_context)| ResolvedTasks {
 6123                                    templates: tasks.resolve(&task_context).collect(),
 6124                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6125                                        multibuffer_point.row,
 6126                                        tasks.column,
 6127                                    )),
 6128                                });
 6129                        let debug_scenarios = editor
 6130                            .update(cx, |editor, cx| {
 6131                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6132                            })?
 6133                            .await;
 6134                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6135                    }
 6136                })
 6137            }
 6138        };
 6139
 6140        cx.spawn_in(window, async move |editor, cx| {
 6141            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6142            let code_actions = code_actions_task.await;
 6143            let spawn_straight_away = quick_launch
 6144                && resolved_tasks
 6145                    .as_ref()
 6146                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6147                && code_actions
 6148                    .as_ref()
 6149                    .is_none_or(|actions| actions.is_empty())
 6150                && debug_scenarios.is_empty();
 6151
 6152            editor.update_in(cx, |editor, window, cx| {
 6153                crate::hover_popover::hide_hover(editor, cx);
 6154                let actions = CodeActionContents::new(
 6155                    resolved_tasks,
 6156                    code_actions,
 6157                    debug_scenarios,
 6158                    task_context.unwrap_or_default(),
 6159                );
 6160
 6161                // Don't show the menu if there are no actions available
 6162                if actions.is_empty() {
 6163                    cx.notify();
 6164                    return Task::ready(Ok(()));
 6165                }
 6166
 6167                *editor.context_menu.borrow_mut() =
 6168                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6169                        buffer,
 6170                        actions,
 6171                        selected_item: Default::default(),
 6172                        scroll_handle: UniformListScrollHandle::default(),
 6173                        deployed_from,
 6174                    }));
 6175                cx.notify();
 6176                if spawn_straight_away
 6177                    && let Some(task) = editor.confirm_code_action(
 6178                        &ConfirmCodeAction { item_ix: Some(0) },
 6179                        window,
 6180                        cx,
 6181                    )
 6182                {
 6183                    return task;
 6184                }
 6185
 6186                Task::ready(Ok(()))
 6187            })
 6188        })
 6189        .detach_and_log_err(cx);
 6190    }
 6191
 6192    fn debug_scenarios(
 6193        &mut self,
 6194        resolved_tasks: &Option<ResolvedTasks>,
 6195        buffer: &Entity<Buffer>,
 6196        cx: &mut App,
 6197    ) -> Task<Vec<task::DebugScenario>> {
 6198        maybe!({
 6199            let project = self.project()?;
 6200            let dap_store = project.read(cx).dap_store();
 6201            let mut scenarios = vec![];
 6202            let resolved_tasks = resolved_tasks.as_ref()?;
 6203            let buffer = buffer.read(cx);
 6204            let language = buffer.language()?;
 6205            let file = buffer.file();
 6206            let debug_adapter = language_settings(language.name().into(), file, cx)
 6207                .debuggers
 6208                .first()
 6209                .map(SharedString::from)
 6210                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6211
 6212            dap_store.update(cx, |dap_store, cx| {
 6213                for (_, task) in &resolved_tasks.templates {
 6214                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6215                        task.original_task().clone(),
 6216                        debug_adapter.clone().into(),
 6217                        task.display_label().to_owned().into(),
 6218                        cx,
 6219                    );
 6220                    scenarios.push(maybe_scenario);
 6221                }
 6222            });
 6223            Some(cx.background_spawn(async move {
 6224                futures::future::join_all(scenarios)
 6225                    .await
 6226                    .into_iter()
 6227                    .flatten()
 6228                    .collect::<Vec<_>>()
 6229            }))
 6230        })
 6231        .unwrap_or_else(|| Task::ready(vec![]))
 6232    }
 6233
 6234    fn code_actions(
 6235        &mut self,
 6236        buffer_row: u32,
 6237        window: &mut Window,
 6238        cx: &mut Context<Self>,
 6239    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6240        let mut task = self.code_actions_task.take();
 6241        cx.spawn_in(window, async move |editor, cx| {
 6242            while let Some(prev_task) = task {
 6243                prev_task.await.log_err();
 6244                task = editor
 6245                    .update(cx, |this, _| this.code_actions_task.take())
 6246                    .ok()?;
 6247            }
 6248
 6249            editor
 6250                .update(cx, |editor, cx| {
 6251                    editor
 6252                        .available_code_actions
 6253                        .clone()
 6254                        .and_then(|(location, code_actions)| {
 6255                            let snapshot = location.buffer.read(cx).snapshot();
 6256                            let point_range = location.range.to_point(&snapshot);
 6257                            let point_range = point_range.start.row..=point_range.end.row;
 6258                            if point_range.contains(&buffer_row) {
 6259                                Some(code_actions)
 6260                            } else {
 6261                                None
 6262                            }
 6263                        })
 6264                })
 6265                .ok()
 6266                .flatten()
 6267        })
 6268    }
 6269
 6270    pub fn confirm_code_action(
 6271        &mut self,
 6272        action: &ConfirmCodeAction,
 6273        window: &mut Window,
 6274        cx: &mut Context<Self>,
 6275    ) -> Option<Task<Result<()>>> {
 6276        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6277
 6278        let actions_menu =
 6279            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6280                menu
 6281            } else {
 6282                return None;
 6283            };
 6284
 6285        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6286        let action = actions_menu.actions.get(action_ix)?;
 6287        let title = action.label();
 6288        let buffer = actions_menu.buffer;
 6289        let workspace = self.workspace()?;
 6290
 6291        match action {
 6292            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6293                workspace.update(cx, |workspace, cx| {
 6294                    workspace.schedule_resolved_task(
 6295                        task_source_kind,
 6296                        resolved_task,
 6297                        false,
 6298                        window,
 6299                        cx,
 6300                    );
 6301
 6302                    Some(Task::ready(Ok(())))
 6303                })
 6304            }
 6305            CodeActionsItem::CodeAction {
 6306                excerpt_id,
 6307                action,
 6308                provider,
 6309            } => {
 6310                let apply_code_action =
 6311                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6312                let workspace = workspace.downgrade();
 6313                Some(cx.spawn_in(window, async move |editor, cx| {
 6314                    let project_transaction = apply_code_action.await?;
 6315                    Self::open_project_transaction(
 6316                        &editor,
 6317                        workspace,
 6318                        project_transaction,
 6319                        title,
 6320                        cx,
 6321                    )
 6322                    .await
 6323                }))
 6324            }
 6325            CodeActionsItem::DebugScenario(scenario) => {
 6326                let context = actions_menu.actions.context;
 6327
 6328                workspace.update(cx, |workspace, cx| {
 6329                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6330                    workspace.start_debug_session(
 6331                        scenario,
 6332                        context,
 6333                        Some(buffer),
 6334                        None,
 6335                        window,
 6336                        cx,
 6337                    );
 6338                });
 6339                Some(Task::ready(Ok(())))
 6340            }
 6341        }
 6342    }
 6343
 6344    pub async fn open_project_transaction(
 6345        editor: &WeakEntity<Editor>,
 6346        workspace: WeakEntity<Workspace>,
 6347        transaction: ProjectTransaction,
 6348        title: String,
 6349        cx: &mut AsyncWindowContext,
 6350    ) -> Result<()> {
 6351        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6352        cx.update(|_, cx| {
 6353            entries.sort_unstable_by_key(|(buffer, _)| {
 6354                buffer.read(cx).file().map(|f| f.path().clone())
 6355            });
 6356        })?;
 6357        if entries.is_empty() {
 6358            return Ok(());
 6359        }
 6360
 6361        // If the project transaction's edits are all contained within this editor, then
 6362        // avoid opening a new editor to display them.
 6363
 6364        if let [(buffer, transaction)] = &*entries {
 6365            let excerpt = editor.update(cx, |editor, cx| {
 6366                editor
 6367                    .buffer()
 6368                    .read(cx)
 6369                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6370            })?;
 6371            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6372                && excerpted_buffer == *buffer
 6373            {
 6374                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6375                    let excerpt_range = excerpt_range.to_offset(buffer);
 6376                    buffer
 6377                        .edited_ranges_for_transaction::<usize>(transaction)
 6378                        .all(|range| {
 6379                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6380                        })
 6381                })?;
 6382
 6383                if all_edits_within_excerpt {
 6384                    return Ok(());
 6385                }
 6386            }
 6387        }
 6388
 6389        let mut ranges_to_highlight = Vec::new();
 6390        let excerpt_buffer = cx.new(|cx| {
 6391            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6392            for (buffer_handle, transaction) in &entries {
 6393                let edited_ranges = buffer_handle
 6394                    .read(cx)
 6395                    .edited_ranges_for_transaction::<Point>(transaction)
 6396                    .collect::<Vec<_>>();
 6397                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6398                    PathKey::for_buffer(buffer_handle, cx),
 6399                    buffer_handle.clone(),
 6400                    edited_ranges,
 6401                    multibuffer_context_lines(cx),
 6402                    cx,
 6403                );
 6404
 6405                ranges_to_highlight.extend(ranges);
 6406            }
 6407            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6408            multibuffer
 6409        })?;
 6410
 6411        workspace.update_in(cx, |workspace, window, cx| {
 6412            let project = workspace.project().clone();
 6413            let editor =
 6414                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6415            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6416            editor.update(cx, |editor, cx| {
 6417                editor.highlight_background::<Self>(
 6418                    &ranges_to_highlight,
 6419                    |theme| theme.colors().editor_highlighted_line_background,
 6420                    cx,
 6421                );
 6422            });
 6423        })?;
 6424
 6425        Ok(())
 6426    }
 6427
 6428    pub fn clear_code_action_providers(&mut self) {
 6429        self.code_action_providers.clear();
 6430        self.available_code_actions.take();
 6431    }
 6432
 6433    pub fn add_code_action_provider(
 6434        &mut self,
 6435        provider: Rc<dyn CodeActionProvider>,
 6436        window: &mut Window,
 6437        cx: &mut Context<Self>,
 6438    ) {
 6439        if self
 6440            .code_action_providers
 6441            .iter()
 6442            .any(|existing_provider| existing_provider.id() == provider.id())
 6443        {
 6444            return;
 6445        }
 6446
 6447        self.code_action_providers.push(provider);
 6448        self.refresh_code_actions(window, cx);
 6449    }
 6450
 6451    pub fn remove_code_action_provider(
 6452        &mut self,
 6453        id: Arc<str>,
 6454        window: &mut Window,
 6455        cx: &mut Context<Self>,
 6456    ) {
 6457        self.code_action_providers
 6458            .retain(|provider| provider.id() != id);
 6459        self.refresh_code_actions(window, cx);
 6460    }
 6461
 6462    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6463        !self.code_action_providers.is_empty()
 6464            && EditorSettings::get_global(cx).toolbar.code_actions
 6465    }
 6466
 6467    pub fn has_available_code_actions(&self) -> bool {
 6468        self.available_code_actions
 6469            .as_ref()
 6470            .is_some_and(|(_, actions)| !actions.is_empty())
 6471    }
 6472
 6473    fn render_inline_code_actions(
 6474        &self,
 6475        icon_size: ui::IconSize,
 6476        display_row: DisplayRow,
 6477        is_active: bool,
 6478        cx: &mut Context<Self>,
 6479    ) -> AnyElement {
 6480        let show_tooltip = !self.context_menu_visible();
 6481        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6482            .icon_size(icon_size)
 6483            .shape(ui::IconButtonShape::Square)
 6484            .icon_color(ui::Color::Hidden)
 6485            .toggle_state(is_active)
 6486            .when(show_tooltip, |this| {
 6487                this.tooltip({
 6488                    let focus_handle = self.focus_handle.clone();
 6489                    move |_window, cx| {
 6490                        Tooltip::for_action_in(
 6491                            "Toggle Code Actions",
 6492                            &ToggleCodeActions {
 6493                                deployed_from: None,
 6494                                quick_launch: false,
 6495                            },
 6496                            &focus_handle,
 6497                            cx,
 6498                        )
 6499                    }
 6500                })
 6501            })
 6502            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6503                window.focus(&editor.focus_handle(cx));
 6504                editor.toggle_code_actions(
 6505                    &crate::actions::ToggleCodeActions {
 6506                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6507                            display_row,
 6508                        )),
 6509                        quick_launch: false,
 6510                    },
 6511                    window,
 6512                    cx,
 6513                );
 6514            }))
 6515            .into_any_element()
 6516    }
 6517
 6518    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6519        &self.context_menu
 6520    }
 6521
 6522    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6523        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6524            cx.background_executor()
 6525                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6526                .await;
 6527
 6528            let (start_buffer, start, _, end, newest_selection) = this
 6529                .update(cx, |this, cx| {
 6530                    let newest_selection = this.selections.newest_anchor().clone();
 6531                    if newest_selection.head().diff_base_anchor.is_some() {
 6532                        return None;
 6533                    }
 6534                    let display_snapshot = this.display_snapshot(cx);
 6535                    let newest_selection_adjusted =
 6536                        this.selections.newest_adjusted(&display_snapshot);
 6537                    let buffer = this.buffer.read(cx);
 6538
 6539                    let (start_buffer, start) =
 6540                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6541                    let (end_buffer, end) =
 6542                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6543
 6544                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6545                })?
 6546                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6547                .context(
 6548                    "Expected selection to lie in a single buffer when refreshing code actions",
 6549                )?;
 6550            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6551                let providers = this.code_action_providers.clone();
 6552                let tasks = this
 6553                    .code_action_providers
 6554                    .iter()
 6555                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6556                    .collect::<Vec<_>>();
 6557                (providers, tasks)
 6558            })?;
 6559
 6560            let mut actions = Vec::new();
 6561            for (provider, provider_actions) in
 6562                providers.into_iter().zip(future::join_all(tasks).await)
 6563            {
 6564                if let Some(provider_actions) = provider_actions.log_err() {
 6565                    actions.extend(provider_actions.into_iter().map(|action| {
 6566                        AvailableCodeAction {
 6567                            excerpt_id: newest_selection.start.excerpt_id,
 6568                            action,
 6569                            provider: provider.clone(),
 6570                        }
 6571                    }));
 6572                }
 6573            }
 6574
 6575            this.update(cx, |this, cx| {
 6576                this.available_code_actions = if actions.is_empty() {
 6577                    None
 6578                } else {
 6579                    Some((
 6580                        Location {
 6581                            buffer: start_buffer,
 6582                            range: start..end,
 6583                        },
 6584                        actions.into(),
 6585                    ))
 6586                };
 6587                cx.notify();
 6588            })
 6589        }));
 6590    }
 6591
 6592    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6593        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6594            self.show_git_blame_inline = false;
 6595
 6596            self.show_git_blame_inline_delay_task =
 6597                Some(cx.spawn_in(window, async move |this, cx| {
 6598                    cx.background_executor().timer(delay).await;
 6599
 6600                    this.update(cx, |this, cx| {
 6601                        this.show_git_blame_inline = true;
 6602                        cx.notify();
 6603                    })
 6604                    .log_err();
 6605                }));
 6606        }
 6607    }
 6608
 6609    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6610        let snapshot = self.snapshot(window, cx);
 6611        let cursor = self
 6612            .selections
 6613            .newest::<Point>(&snapshot.display_snapshot)
 6614            .head();
 6615        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6616        else {
 6617            return;
 6618        };
 6619
 6620        let Some(blame) = self.blame.as_ref() else {
 6621            return;
 6622        };
 6623
 6624        let row_info = RowInfo {
 6625            buffer_id: Some(buffer.remote_id()),
 6626            buffer_row: Some(point.row),
 6627            ..Default::default()
 6628        };
 6629        let Some((buffer, blame_entry)) = blame
 6630            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6631            .flatten()
 6632        else {
 6633            return;
 6634        };
 6635
 6636        let anchor = self.selections.newest_anchor().head();
 6637        let position = self.to_pixel_point(anchor, &snapshot, window);
 6638        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6639            self.show_blame_popover(
 6640                buffer,
 6641                &blame_entry,
 6642                position + last_bounds.origin,
 6643                true,
 6644                cx,
 6645            );
 6646        };
 6647    }
 6648
 6649    fn show_blame_popover(
 6650        &mut self,
 6651        buffer: BufferId,
 6652        blame_entry: &BlameEntry,
 6653        position: gpui::Point<Pixels>,
 6654        ignore_timeout: bool,
 6655        cx: &mut Context<Self>,
 6656    ) {
 6657        if let Some(state) = &mut self.inline_blame_popover {
 6658            state.hide_task.take();
 6659        } else {
 6660            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6661            let blame_entry = blame_entry.clone();
 6662            let show_task = cx.spawn(async move |editor, cx| {
 6663                if !ignore_timeout {
 6664                    cx.background_executor()
 6665                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6666                        .await;
 6667                }
 6668                editor
 6669                    .update(cx, |editor, cx| {
 6670                        editor.inline_blame_popover_show_task.take();
 6671                        let Some(blame) = editor.blame.as_ref() else {
 6672                            return;
 6673                        };
 6674                        let blame = blame.read(cx);
 6675                        let details = blame.details_for_entry(buffer, &blame_entry);
 6676                        let markdown = cx.new(|cx| {
 6677                            Markdown::new(
 6678                                details
 6679                                    .as_ref()
 6680                                    .map(|message| message.message.clone())
 6681                                    .unwrap_or_default(),
 6682                                None,
 6683                                None,
 6684                                cx,
 6685                            )
 6686                        });
 6687                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6688                            position,
 6689                            hide_task: None,
 6690                            popover_bounds: None,
 6691                            popover_state: InlineBlamePopoverState {
 6692                                scroll_handle: ScrollHandle::new(),
 6693                                commit_message: details,
 6694                                markdown,
 6695                            },
 6696                            keyboard_grace: ignore_timeout,
 6697                        });
 6698                        cx.notify();
 6699                    })
 6700                    .ok();
 6701            });
 6702            self.inline_blame_popover_show_task = Some(show_task);
 6703        }
 6704    }
 6705
 6706    fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6707        self.inline_blame_popover_show_task.take();
 6708        if let Some(state) = &mut self.inline_blame_popover {
 6709            let hide_task = cx.spawn(async move |editor, cx| {
 6710                if !ignore_timeout {
 6711                    cx.background_executor()
 6712                        .timer(std::time::Duration::from_millis(100))
 6713                        .await;
 6714                }
 6715                editor
 6716                    .update(cx, |editor, cx| {
 6717                        editor.inline_blame_popover.take();
 6718                        cx.notify();
 6719                    })
 6720                    .ok();
 6721            });
 6722            state.hide_task = Some(hide_task);
 6723            true
 6724        } else {
 6725            false
 6726        }
 6727    }
 6728
 6729    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6730        if self.pending_rename.is_some() {
 6731            return None;
 6732        }
 6733
 6734        let provider = self.semantics_provider.clone()?;
 6735        let buffer = self.buffer.read(cx);
 6736        let newest_selection = self.selections.newest_anchor().clone();
 6737        let cursor_position = newest_selection.head();
 6738        let (cursor_buffer, cursor_buffer_position) =
 6739            buffer.text_anchor_for_position(cursor_position, cx)?;
 6740        let (tail_buffer, tail_buffer_position) =
 6741            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6742        if cursor_buffer != tail_buffer {
 6743            return None;
 6744        }
 6745
 6746        let snapshot = cursor_buffer.read(cx).snapshot();
 6747        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6748        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6749        if start_word_range != end_word_range {
 6750            self.document_highlights_task.take();
 6751            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6752            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6753            return None;
 6754        }
 6755
 6756        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 6757        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6758            cx.background_executor()
 6759                .timer(Duration::from_millis(debounce))
 6760                .await;
 6761
 6762            let highlights = if let Some(highlights) = cx
 6763                .update(|cx| {
 6764                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6765                })
 6766                .ok()
 6767                .flatten()
 6768            {
 6769                highlights.await.log_err()
 6770            } else {
 6771                None
 6772            };
 6773
 6774            if let Some(highlights) = highlights {
 6775                this.update(cx, |this, cx| {
 6776                    if this.pending_rename.is_some() {
 6777                        return;
 6778                    }
 6779
 6780                    let buffer = this.buffer.read(cx);
 6781                    if buffer
 6782                        .text_anchor_for_position(cursor_position, cx)
 6783                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6784                    {
 6785                        return;
 6786                    }
 6787
 6788                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6789                    let mut write_ranges = Vec::new();
 6790                    let mut read_ranges = Vec::new();
 6791                    for highlight in highlights {
 6792                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6793                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6794                        {
 6795                            let start = highlight
 6796                                .range
 6797                                .start
 6798                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6799                            let end = highlight
 6800                                .range
 6801                                .end
 6802                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6803                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6804                                continue;
 6805                            }
 6806
 6807                            let range =
 6808                                Anchor::range_in_buffer(excerpt_id, buffer_id, *start..*end);
 6809                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6810                                write_ranges.push(range);
 6811                            } else {
 6812                                read_ranges.push(range);
 6813                            }
 6814                        }
 6815                    }
 6816
 6817                    this.highlight_background::<DocumentHighlightRead>(
 6818                        &read_ranges,
 6819                        |theme| theme.colors().editor_document_highlight_read_background,
 6820                        cx,
 6821                    );
 6822                    this.highlight_background::<DocumentHighlightWrite>(
 6823                        &write_ranges,
 6824                        |theme| theme.colors().editor_document_highlight_write_background,
 6825                        cx,
 6826                    );
 6827                    cx.notify();
 6828                })
 6829                .log_err();
 6830            }
 6831        }));
 6832        None
 6833    }
 6834
 6835    fn prepare_highlight_query_from_selection(
 6836        &mut self,
 6837        window: &Window,
 6838        cx: &mut Context<Editor>,
 6839    ) -> Option<(String, Range<Anchor>)> {
 6840        if matches!(self.mode, EditorMode::SingleLine) {
 6841            return None;
 6842        }
 6843        if !EditorSettings::get_global(cx).selection_highlight {
 6844            return None;
 6845        }
 6846        if self.selections.count() != 1 || self.selections.line_mode() {
 6847            return None;
 6848        }
 6849        let snapshot = self.snapshot(window, cx);
 6850        let selection = self.selections.newest::<Point>(&snapshot);
 6851        // If the selection spans multiple rows OR it is empty
 6852        if selection.start.row != selection.end.row
 6853            || selection.start.column == selection.end.column
 6854        {
 6855            return None;
 6856        }
 6857        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 6858        let query = snapshot
 6859            .buffer_snapshot()
 6860            .text_for_range(selection_anchor_range.clone())
 6861            .collect::<String>();
 6862        if query.trim().is_empty() {
 6863            return None;
 6864        }
 6865        Some((query, selection_anchor_range))
 6866    }
 6867
 6868    fn update_selection_occurrence_highlights(
 6869        &mut self,
 6870        query_text: String,
 6871        query_range: Range<Anchor>,
 6872        multi_buffer_range_to_query: Range<Point>,
 6873        use_debounce: bool,
 6874        window: &mut Window,
 6875        cx: &mut Context<Editor>,
 6876    ) -> Task<()> {
 6877        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6878        cx.spawn_in(window, async move |editor, cx| {
 6879            if use_debounce {
 6880                cx.background_executor()
 6881                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6882                    .await;
 6883            }
 6884            let match_task = cx.background_spawn(async move {
 6885                let buffer_ranges = multi_buffer_snapshot
 6886                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6887                    .into_iter()
 6888                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6889                let mut match_ranges = Vec::new();
 6890                let Ok(regex) = project::search::SearchQuery::text(
 6891                    query_text.clone(),
 6892                    false,
 6893                    false,
 6894                    false,
 6895                    Default::default(),
 6896                    Default::default(),
 6897                    false,
 6898                    None,
 6899                ) else {
 6900                    return Vec::default();
 6901                };
 6902                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 6903                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6904                    match_ranges.extend(
 6905                        regex
 6906                            .search(buffer_snapshot, Some(search_range.clone()))
 6907                            .await
 6908                            .into_iter()
 6909                            .filter_map(|match_range| {
 6910                                let match_start = buffer_snapshot
 6911                                    .anchor_after(search_range.start + match_range.start);
 6912                                let match_end = buffer_snapshot
 6913                                    .anchor_before(search_range.start + match_range.end);
 6914                                let match_anchor_range = Anchor::range_in_buffer(
 6915                                    excerpt_id,
 6916                                    buffer_snapshot.remote_id(),
 6917                                    match_start..match_end,
 6918                                );
 6919                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6920                            }),
 6921                    );
 6922                }
 6923                match_ranges
 6924            });
 6925            let match_ranges = match_task.await;
 6926            editor
 6927                .update_in(cx, |editor, _, cx| {
 6928                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6929                    if !match_ranges.is_empty() {
 6930                        editor.highlight_background::<SelectedTextHighlight>(
 6931                            &match_ranges,
 6932                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6933                            cx,
 6934                        )
 6935                    }
 6936                })
 6937                .log_err();
 6938        })
 6939    }
 6940
 6941    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6942        struct NewlineFold;
 6943        let type_id = std::any::TypeId::of::<NewlineFold>();
 6944        if !self.mode.is_single_line() {
 6945            return;
 6946        }
 6947        let snapshot = self.snapshot(window, cx);
 6948        if snapshot.buffer_snapshot().max_point().row == 0 {
 6949            return;
 6950        }
 6951        let task = cx.background_spawn(async move {
 6952            let new_newlines = snapshot
 6953                .buffer_chars_at(0)
 6954                .filter_map(|(c, i)| {
 6955                    if c == '\n' {
 6956                        Some(
 6957                            snapshot.buffer_snapshot().anchor_after(i)
 6958                                ..snapshot.buffer_snapshot().anchor_before(i + 1),
 6959                        )
 6960                    } else {
 6961                        None
 6962                    }
 6963                })
 6964                .collect::<Vec<_>>();
 6965            let existing_newlines = snapshot
 6966                .folds_in_range(0..snapshot.buffer_snapshot().len())
 6967                .filter_map(|fold| {
 6968                    if fold.placeholder.type_tag == Some(type_id) {
 6969                        Some(fold.range.start..fold.range.end)
 6970                    } else {
 6971                        None
 6972                    }
 6973                })
 6974                .collect::<Vec<_>>();
 6975
 6976            (new_newlines, existing_newlines)
 6977        });
 6978        self.folding_newlines = cx.spawn(async move |this, cx| {
 6979            let (new_newlines, existing_newlines) = task.await;
 6980            if new_newlines == existing_newlines {
 6981                return;
 6982            }
 6983            let placeholder = FoldPlaceholder {
 6984                render: Arc::new(move |_, _, cx| {
 6985                    div()
 6986                        .bg(cx.theme().status().hint_background)
 6987                        .border_b_1()
 6988                        .size_full()
 6989                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6990                        .border_color(cx.theme().status().hint)
 6991                        .child("\\n")
 6992                        .into_any()
 6993                }),
 6994                constrain_width: false,
 6995                merge_adjacent: false,
 6996                type_tag: Some(type_id),
 6997            };
 6998            let creases = new_newlines
 6999                .into_iter()
 7000                .map(|range| Crease::simple(range, placeholder.clone()))
 7001                .collect();
 7002            this.update(cx, |this, cx| {
 7003                this.display_map.update(cx, |display_map, cx| {
 7004                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7005                    display_map.fold(creases, cx);
 7006                });
 7007            })
 7008            .ok();
 7009        });
 7010    }
 7011
 7012    fn refresh_selected_text_highlights(
 7013        &mut self,
 7014        on_buffer_edit: bool,
 7015        window: &mut Window,
 7016        cx: &mut Context<Editor>,
 7017    ) {
 7018        let Some((query_text, query_range)) =
 7019            self.prepare_highlight_query_from_selection(window, cx)
 7020        else {
 7021            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7022            self.quick_selection_highlight_task.take();
 7023            self.debounced_selection_highlight_task.take();
 7024            return;
 7025        };
 7026        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7027        if on_buffer_edit
 7028            || self
 7029                .quick_selection_highlight_task
 7030                .as_ref()
 7031                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7032        {
 7033            let multi_buffer_visible_start = self
 7034                .scroll_manager
 7035                .anchor()
 7036                .anchor
 7037                .to_point(&multi_buffer_snapshot);
 7038            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7039                multi_buffer_visible_start
 7040                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7041                Bias::Left,
 7042            );
 7043            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7044            self.quick_selection_highlight_task = Some((
 7045                query_range.clone(),
 7046                self.update_selection_occurrence_highlights(
 7047                    query_text.clone(),
 7048                    query_range.clone(),
 7049                    multi_buffer_visible_range,
 7050                    false,
 7051                    window,
 7052                    cx,
 7053                ),
 7054            ));
 7055        }
 7056        if on_buffer_edit
 7057            || self
 7058                .debounced_selection_highlight_task
 7059                .as_ref()
 7060                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7061        {
 7062            let multi_buffer_start = multi_buffer_snapshot
 7063                .anchor_before(0)
 7064                .to_point(&multi_buffer_snapshot);
 7065            let multi_buffer_end = multi_buffer_snapshot
 7066                .anchor_after(multi_buffer_snapshot.len())
 7067                .to_point(&multi_buffer_snapshot);
 7068            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7069            self.debounced_selection_highlight_task = Some((
 7070                query_range.clone(),
 7071                self.update_selection_occurrence_highlights(
 7072                    query_text,
 7073                    query_range,
 7074                    multi_buffer_full_range,
 7075                    true,
 7076                    window,
 7077                    cx,
 7078                ),
 7079            ));
 7080        }
 7081    }
 7082
 7083    pub fn refresh_edit_prediction(
 7084        &mut self,
 7085        debounce: bool,
 7086        user_requested: bool,
 7087        window: &mut Window,
 7088        cx: &mut Context<Self>,
 7089    ) -> Option<()> {
 7090        if DisableAiSettings::get_global(cx).disable_ai {
 7091            return None;
 7092        }
 7093
 7094        let provider = self.edit_prediction_provider()?;
 7095        let cursor = self.selections.newest_anchor().head();
 7096        let (buffer, cursor_buffer_position) =
 7097            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7098
 7099        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7100            self.discard_edit_prediction(false, cx);
 7101            return None;
 7102        }
 7103
 7104        self.update_visible_edit_prediction(window, cx);
 7105
 7106        if !user_requested
 7107            && (!self.should_show_edit_predictions()
 7108                || !self.is_focused(window)
 7109                || buffer.read(cx).is_empty())
 7110        {
 7111            self.discard_edit_prediction(false, cx);
 7112            return None;
 7113        }
 7114
 7115        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7116        Some(())
 7117    }
 7118
 7119    fn show_edit_predictions_in_menu(&self) -> bool {
 7120        match self.edit_prediction_settings {
 7121            EditPredictionSettings::Disabled => false,
 7122            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7123        }
 7124    }
 7125
 7126    pub fn edit_predictions_enabled(&self) -> bool {
 7127        match self.edit_prediction_settings {
 7128            EditPredictionSettings::Disabled => false,
 7129            EditPredictionSettings::Enabled { .. } => true,
 7130        }
 7131    }
 7132
 7133    fn edit_prediction_requires_modifier(&self) -> bool {
 7134        match self.edit_prediction_settings {
 7135            EditPredictionSettings::Disabled => false,
 7136            EditPredictionSettings::Enabled {
 7137                preview_requires_modifier,
 7138                ..
 7139            } => preview_requires_modifier,
 7140        }
 7141    }
 7142
 7143    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7144        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7145            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7146            self.discard_edit_prediction(false, cx);
 7147        } else {
 7148            let selection = self.selections.newest_anchor();
 7149            let cursor = selection.head();
 7150
 7151            if let Some((buffer, cursor_buffer_position)) =
 7152                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7153            {
 7154                self.edit_prediction_settings =
 7155                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7156            }
 7157        }
 7158    }
 7159
 7160    fn edit_prediction_settings_at_position(
 7161        &self,
 7162        buffer: &Entity<Buffer>,
 7163        buffer_position: language::Anchor,
 7164        cx: &App,
 7165    ) -> EditPredictionSettings {
 7166        if !self.mode.is_full()
 7167            || !self.show_edit_predictions_override.unwrap_or(true)
 7168            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7169        {
 7170            return EditPredictionSettings::Disabled;
 7171        }
 7172
 7173        let buffer = buffer.read(cx);
 7174
 7175        let file = buffer.file();
 7176
 7177        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7178            return EditPredictionSettings::Disabled;
 7179        };
 7180
 7181        let by_provider = matches!(
 7182            self.menu_edit_predictions_policy,
 7183            MenuEditPredictionsPolicy::ByProvider
 7184        );
 7185
 7186        let show_in_menu = by_provider
 7187            && self
 7188                .edit_prediction_provider
 7189                .as_ref()
 7190                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7191
 7192        let preview_requires_modifier =
 7193            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7194
 7195        EditPredictionSettings::Enabled {
 7196            show_in_menu,
 7197            preview_requires_modifier,
 7198        }
 7199    }
 7200
 7201    fn should_show_edit_predictions(&self) -> bool {
 7202        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7203    }
 7204
 7205    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7206        matches!(
 7207            self.edit_prediction_preview,
 7208            EditPredictionPreview::Active { .. }
 7209        )
 7210    }
 7211
 7212    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7213        let cursor = self.selections.newest_anchor().head();
 7214        if let Some((buffer, cursor_position)) =
 7215            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7216        {
 7217            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7218        } else {
 7219            false
 7220        }
 7221    }
 7222
 7223    pub fn supports_minimap(&self, cx: &App) -> bool {
 7224        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7225    }
 7226
 7227    fn edit_predictions_enabled_in_buffer(
 7228        &self,
 7229        buffer: &Entity<Buffer>,
 7230        buffer_position: language::Anchor,
 7231        cx: &App,
 7232    ) -> bool {
 7233        maybe!({
 7234            if self.read_only(cx) {
 7235                return Some(false);
 7236            }
 7237            let provider = self.edit_prediction_provider()?;
 7238            if !provider.is_enabled(buffer, buffer_position, cx) {
 7239                return Some(false);
 7240            }
 7241            let buffer = buffer.read(cx);
 7242            let Some(file) = buffer.file() else {
 7243                return Some(true);
 7244            };
 7245            let settings = all_language_settings(Some(file), cx);
 7246            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7247        })
 7248        .unwrap_or(false)
 7249    }
 7250
 7251    fn cycle_edit_prediction(
 7252        &mut self,
 7253        direction: Direction,
 7254        window: &mut Window,
 7255        cx: &mut Context<Self>,
 7256    ) -> Option<()> {
 7257        let provider = self.edit_prediction_provider()?;
 7258        let cursor = self.selections.newest_anchor().head();
 7259        let (buffer, cursor_buffer_position) =
 7260            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7261        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7262            return None;
 7263        }
 7264
 7265        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7266        self.update_visible_edit_prediction(window, cx);
 7267
 7268        Some(())
 7269    }
 7270
 7271    pub fn show_edit_prediction(
 7272        &mut self,
 7273        _: &ShowEditPrediction,
 7274        window: &mut Window,
 7275        cx: &mut Context<Self>,
 7276    ) {
 7277        if !self.has_active_edit_prediction() {
 7278            self.refresh_edit_prediction(false, true, window, cx);
 7279            return;
 7280        }
 7281
 7282        self.update_visible_edit_prediction(window, cx);
 7283    }
 7284
 7285    pub fn display_cursor_names(
 7286        &mut self,
 7287        _: &DisplayCursorNames,
 7288        window: &mut Window,
 7289        cx: &mut Context<Self>,
 7290    ) {
 7291        self.show_cursor_names(window, cx);
 7292    }
 7293
 7294    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7295        self.show_cursor_names = true;
 7296        cx.notify();
 7297        cx.spawn_in(window, async move |this, cx| {
 7298            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7299            this.update(cx, |this, cx| {
 7300                this.show_cursor_names = false;
 7301                cx.notify()
 7302            })
 7303            .ok()
 7304        })
 7305        .detach();
 7306    }
 7307
 7308    pub fn next_edit_prediction(
 7309        &mut self,
 7310        _: &NextEditPrediction,
 7311        window: &mut Window,
 7312        cx: &mut Context<Self>,
 7313    ) {
 7314        if self.has_active_edit_prediction() {
 7315            self.cycle_edit_prediction(Direction::Next, window, cx);
 7316        } else {
 7317            let is_copilot_disabled = self
 7318                .refresh_edit_prediction(false, true, window, cx)
 7319                .is_none();
 7320            if is_copilot_disabled {
 7321                cx.propagate();
 7322            }
 7323        }
 7324    }
 7325
 7326    pub fn previous_edit_prediction(
 7327        &mut self,
 7328        _: &PreviousEditPrediction,
 7329        window: &mut Window,
 7330        cx: &mut Context<Self>,
 7331    ) {
 7332        if self.has_active_edit_prediction() {
 7333            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7334        } else {
 7335            let is_copilot_disabled = self
 7336                .refresh_edit_prediction(false, true, window, cx)
 7337                .is_none();
 7338            if is_copilot_disabled {
 7339                cx.propagate();
 7340            }
 7341        }
 7342    }
 7343
 7344    pub fn accept_edit_prediction(
 7345        &mut self,
 7346        _: &AcceptEditPrediction,
 7347        window: &mut Window,
 7348        cx: &mut Context<Self>,
 7349    ) {
 7350        if self.show_edit_predictions_in_menu() {
 7351            self.hide_context_menu(window, cx);
 7352        }
 7353
 7354        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7355            return;
 7356        };
 7357
 7358        match &active_edit_prediction.completion {
 7359            EditPrediction::MoveWithin { target, .. } => {
 7360                let target = *target;
 7361
 7362                if let Some(position_map) = &self.last_position_map {
 7363                    if position_map
 7364                        .visible_row_range
 7365                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7366                        || !self.edit_prediction_requires_modifier()
 7367                    {
 7368                        self.unfold_ranges(&[target..target], true, false, cx);
 7369                        // Note that this is also done in vim's handler of the Tab action.
 7370                        self.change_selections(
 7371                            SelectionEffects::scroll(Autoscroll::newest()),
 7372                            window,
 7373                            cx,
 7374                            |selections| {
 7375                                selections.select_anchor_ranges([target..target]);
 7376                            },
 7377                        );
 7378                        self.clear_row_highlights::<EditPredictionPreview>();
 7379
 7380                        self.edit_prediction_preview
 7381                            .set_previous_scroll_position(None);
 7382                    } else {
 7383                        self.edit_prediction_preview
 7384                            .set_previous_scroll_position(Some(
 7385                                position_map.snapshot.scroll_anchor,
 7386                            ));
 7387
 7388                        self.highlight_rows::<EditPredictionPreview>(
 7389                            target..target,
 7390                            cx.theme().colors().editor_highlighted_line_background,
 7391                            RowHighlightOptions {
 7392                                autoscroll: true,
 7393                                ..Default::default()
 7394                            },
 7395                            cx,
 7396                        );
 7397                        self.request_autoscroll(Autoscroll::fit(), cx);
 7398                    }
 7399                }
 7400            }
 7401            EditPrediction::MoveOutside { snapshot, target } => {
 7402                if let Some(workspace) = self.workspace() {
 7403                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7404                        .detach_and_log_err(cx);
 7405                }
 7406            }
 7407            EditPrediction::Edit { edits, .. } => {
 7408                self.report_edit_prediction_event(
 7409                    active_edit_prediction.completion_id.clone(),
 7410                    true,
 7411                    cx,
 7412                );
 7413
 7414                if let Some(provider) = self.edit_prediction_provider() {
 7415                    provider.accept(cx);
 7416                }
 7417
 7418                // Store the transaction ID and selections before applying the edit
 7419                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7420
 7421                let snapshot = self.buffer.read(cx).snapshot(cx);
 7422                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7423
 7424                self.buffer.update(cx, |buffer, cx| {
 7425                    buffer.edit(edits.iter().cloned(), None, cx)
 7426                });
 7427
 7428                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7429                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7430                });
 7431
 7432                let selections = self.selections.disjoint_anchors_arc();
 7433                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7434                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7435                    if has_new_transaction {
 7436                        self.selection_history
 7437                            .insert_transaction(transaction_id_now, selections);
 7438                    }
 7439                }
 7440
 7441                self.update_visible_edit_prediction(window, cx);
 7442                if self.active_edit_prediction.is_none() {
 7443                    self.refresh_edit_prediction(true, true, window, cx);
 7444                }
 7445
 7446                cx.notify();
 7447            }
 7448        }
 7449
 7450        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7451    }
 7452
 7453    pub fn accept_partial_edit_prediction(
 7454        &mut self,
 7455        _: &AcceptPartialEditPrediction,
 7456        window: &mut Window,
 7457        cx: &mut Context<Self>,
 7458    ) {
 7459        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7460            return;
 7461        };
 7462        if self.selections.count() != 1 {
 7463            return;
 7464        }
 7465
 7466        match &active_edit_prediction.completion {
 7467            EditPrediction::MoveWithin { target, .. } => {
 7468                let target = *target;
 7469                self.change_selections(
 7470                    SelectionEffects::scroll(Autoscroll::newest()),
 7471                    window,
 7472                    cx,
 7473                    |selections| {
 7474                        selections.select_anchor_ranges([target..target]);
 7475                    },
 7476                );
 7477            }
 7478            EditPrediction::MoveOutside { snapshot, target } => {
 7479                if let Some(workspace) = self.workspace() {
 7480                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7481                        .detach_and_log_err(cx);
 7482                }
 7483            }
 7484            EditPrediction::Edit { edits, .. } => {
 7485                self.report_edit_prediction_event(
 7486                    active_edit_prediction.completion_id.clone(),
 7487                    true,
 7488                    cx,
 7489                );
 7490
 7491                // Find an insertion that starts at the cursor position.
 7492                let snapshot = self.buffer.read(cx).snapshot(cx);
 7493                let cursor_offset = self
 7494                    .selections
 7495                    .newest::<usize>(&self.display_snapshot(cx))
 7496                    .head();
 7497                let insertion = edits.iter().find_map(|(range, text)| {
 7498                    let range = range.to_offset(&snapshot);
 7499                    if range.is_empty() && range.start == cursor_offset {
 7500                        Some(text)
 7501                    } else {
 7502                        None
 7503                    }
 7504                });
 7505
 7506                if let Some(text) = insertion {
 7507                    let mut partial_completion = text
 7508                        .chars()
 7509                        .by_ref()
 7510                        .take_while(|c| c.is_alphabetic())
 7511                        .collect::<String>();
 7512                    if partial_completion.is_empty() {
 7513                        partial_completion = text
 7514                            .chars()
 7515                            .by_ref()
 7516                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7517                            .collect::<String>();
 7518                    }
 7519
 7520                    cx.emit(EditorEvent::InputHandled {
 7521                        utf16_range_to_replace: None,
 7522                        text: partial_completion.clone().into(),
 7523                    });
 7524
 7525                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7526
 7527                    self.refresh_edit_prediction(true, true, window, cx);
 7528                    cx.notify();
 7529                } else {
 7530                    self.accept_edit_prediction(&Default::default(), window, cx);
 7531                }
 7532            }
 7533        }
 7534    }
 7535
 7536    fn discard_edit_prediction(
 7537        &mut self,
 7538        should_report_edit_prediction_event: bool,
 7539        cx: &mut Context<Self>,
 7540    ) -> bool {
 7541        if should_report_edit_prediction_event {
 7542            let completion_id = self
 7543                .active_edit_prediction
 7544                .as_ref()
 7545                .and_then(|active_completion| active_completion.completion_id.clone());
 7546
 7547            self.report_edit_prediction_event(completion_id, false, cx);
 7548        }
 7549
 7550        if let Some(provider) = self.edit_prediction_provider() {
 7551            provider.discard(cx);
 7552        }
 7553
 7554        self.take_active_edit_prediction(cx)
 7555    }
 7556
 7557    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7558        let Some(provider) = self.edit_prediction_provider() else {
 7559            return;
 7560        };
 7561
 7562        let Some((_, buffer, _)) = self
 7563            .buffer
 7564            .read(cx)
 7565            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7566        else {
 7567            return;
 7568        };
 7569
 7570        let extension = buffer
 7571            .read(cx)
 7572            .file()
 7573            .and_then(|file| Some(file.path().extension()?.to_string()));
 7574
 7575        let event_type = match accepted {
 7576            true => "Edit Prediction Accepted",
 7577            false => "Edit Prediction Discarded",
 7578        };
 7579        telemetry::event!(
 7580            event_type,
 7581            provider = provider.name(),
 7582            prediction_id = id,
 7583            suggestion_accepted = accepted,
 7584            file_extension = extension,
 7585        );
 7586    }
 7587
 7588    fn open_editor_at_anchor(
 7589        snapshot: &language::BufferSnapshot,
 7590        target: language::Anchor,
 7591        workspace: &Entity<Workspace>,
 7592        window: &mut Window,
 7593        cx: &mut App,
 7594    ) -> Task<Result<()>> {
 7595        workspace.update(cx, |workspace, cx| {
 7596            let path = snapshot.file().map(|file| file.full_path(cx));
 7597            let Some(path) =
 7598                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7599            else {
 7600                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7601            };
 7602            let target = text::ToPoint::to_point(&target, snapshot);
 7603            let item = workspace.open_path(path, None, true, window, cx);
 7604            window.spawn(cx, async move |cx| {
 7605                let Some(editor) = item.await?.downcast::<Editor>() else {
 7606                    return Ok(());
 7607                };
 7608                editor
 7609                    .update_in(cx, |editor, window, cx| {
 7610                        editor.go_to_singleton_buffer_point(target, window, cx);
 7611                    })
 7612                    .ok();
 7613                anyhow::Ok(())
 7614            })
 7615        })
 7616    }
 7617
 7618    pub fn has_active_edit_prediction(&self) -> bool {
 7619        self.active_edit_prediction.is_some()
 7620    }
 7621
 7622    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7623        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7624            return false;
 7625        };
 7626
 7627        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7628        self.clear_highlights::<EditPredictionHighlight>(cx);
 7629        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7630        true
 7631    }
 7632
 7633    /// Returns true when we're displaying the edit prediction popover below the cursor
 7634    /// like we are not previewing and the LSP autocomplete menu is visible
 7635    /// or we are in `when_holding_modifier` mode.
 7636    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7637        if self.edit_prediction_preview_is_active()
 7638            || !self.show_edit_predictions_in_menu()
 7639            || !self.edit_predictions_enabled()
 7640        {
 7641            return false;
 7642        }
 7643
 7644        if self.has_visible_completions_menu() {
 7645            return true;
 7646        }
 7647
 7648        has_completion && self.edit_prediction_requires_modifier()
 7649    }
 7650
 7651    fn handle_modifiers_changed(
 7652        &mut self,
 7653        modifiers: Modifiers,
 7654        position_map: &PositionMap,
 7655        window: &mut Window,
 7656        cx: &mut Context<Self>,
 7657    ) {
 7658        // Ensure that the edit prediction preview is updated, even when not
 7659        // enabled, if there's an active edit prediction preview.
 7660        if self.show_edit_predictions_in_menu()
 7661            || matches!(
 7662                self.edit_prediction_preview,
 7663                EditPredictionPreview::Active { .. }
 7664            )
 7665        {
 7666            self.update_edit_prediction_preview(&modifiers, window, cx);
 7667        }
 7668
 7669        self.update_selection_mode(&modifiers, position_map, window, cx);
 7670
 7671        let mouse_position = window.mouse_position();
 7672        if !position_map.text_hitbox.is_hovered(window) {
 7673            return;
 7674        }
 7675
 7676        self.update_hovered_link(
 7677            position_map.point_for_position(mouse_position),
 7678            &position_map.snapshot,
 7679            modifiers,
 7680            window,
 7681            cx,
 7682        )
 7683    }
 7684
 7685    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7686        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7687            MultiCursorModifier::Alt => modifiers.secondary(),
 7688            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7689        }
 7690    }
 7691
 7692    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7693        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7694            MultiCursorModifier::Alt => modifiers.alt,
 7695            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7696        }
 7697    }
 7698
 7699    fn columnar_selection_mode(
 7700        modifiers: &Modifiers,
 7701        cx: &mut Context<Self>,
 7702    ) -> Option<ColumnarMode> {
 7703        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7704            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 7705                Some(ColumnarMode::FromMouse)
 7706            } else if Self::is_alt_pressed(modifiers, cx) {
 7707                Some(ColumnarMode::FromSelection)
 7708            } else {
 7709                None
 7710            }
 7711        } else {
 7712            None
 7713        }
 7714    }
 7715
 7716    fn update_selection_mode(
 7717        &mut self,
 7718        modifiers: &Modifiers,
 7719        position_map: &PositionMap,
 7720        window: &mut Window,
 7721        cx: &mut Context<Self>,
 7722    ) {
 7723        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7724            return;
 7725        };
 7726        if self.selections.pending_anchor().is_none() {
 7727            return;
 7728        }
 7729
 7730        let mouse_position = window.mouse_position();
 7731        let point_for_position = position_map.point_for_position(mouse_position);
 7732        let position = point_for_position.previous_valid;
 7733
 7734        self.select(
 7735            SelectPhase::BeginColumnar {
 7736                position,
 7737                reset: false,
 7738                mode,
 7739                goal_column: point_for_position.exact_unclipped.column(),
 7740            },
 7741            window,
 7742            cx,
 7743        );
 7744    }
 7745
 7746    fn update_edit_prediction_preview(
 7747        &mut self,
 7748        modifiers: &Modifiers,
 7749        window: &mut Window,
 7750        cx: &mut Context<Self>,
 7751    ) {
 7752        let mut modifiers_held = false;
 7753        if let Some(accept_keystroke) = self
 7754            .accept_edit_prediction_keybind(false, window, cx)
 7755            .keystroke()
 7756        {
 7757            modifiers_held = modifiers_held
 7758                || (accept_keystroke.modifiers() == modifiers
 7759                    && accept_keystroke.modifiers().modified());
 7760        };
 7761        if let Some(accept_partial_keystroke) = self
 7762            .accept_edit_prediction_keybind(true, window, cx)
 7763            .keystroke()
 7764        {
 7765            modifiers_held = modifiers_held
 7766                || (accept_partial_keystroke.modifiers() == modifiers
 7767                    && accept_partial_keystroke.modifiers().modified());
 7768        }
 7769
 7770        if modifiers_held {
 7771            if matches!(
 7772                self.edit_prediction_preview,
 7773                EditPredictionPreview::Inactive { .. }
 7774            ) {
 7775                self.edit_prediction_preview = EditPredictionPreview::Active {
 7776                    previous_scroll_position: None,
 7777                    since: Instant::now(),
 7778                };
 7779
 7780                self.update_visible_edit_prediction(window, cx);
 7781                cx.notify();
 7782            }
 7783        } else if let EditPredictionPreview::Active {
 7784            previous_scroll_position,
 7785            since,
 7786        } = self.edit_prediction_preview
 7787        {
 7788            if let (Some(previous_scroll_position), Some(position_map)) =
 7789                (previous_scroll_position, self.last_position_map.as_ref())
 7790            {
 7791                self.set_scroll_position(
 7792                    previous_scroll_position
 7793                        .scroll_position(&position_map.snapshot.display_snapshot),
 7794                    window,
 7795                    cx,
 7796                );
 7797            }
 7798
 7799            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7800                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7801            };
 7802            self.clear_row_highlights::<EditPredictionPreview>();
 7803            self.update_visible_edit_prediction(window, cx);
 7804            cx.notify();
 7805        }
 7806    }
 7807
 7808    fn update_visible_edit_prediction(
 7809        &mut self,
 7810        _window: &mut Window,
 7811        cx: &mut Context<Self>,
 7812    ) -> Option<()> {
 7813        if DisableAiSettings::get_global(cx).disable_ai {
 7814            return None;
 7815        }
 7816
 7817        if self.ime_transaction.is_some() {
 7818            self.discard_edit_prediction(false, cx);
 7819            return None;
 7820        }
 7821
 7822        let selection = self.selections.newest_anchor();
 7823        let cursor = selection.head();
 7824        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7825        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7826        let excerpt_id = cursor.excerpt_id;
 7827
 7828        let show_in_menu = self.show_edit_predictions_in_menu();
 7829        let completions_menu_has_precedence = !show_in_menu
 7830            && (self.context_menu.borrow().is_some()
 7831                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7832
 7833        if completions_menu_has_precedence
 7834            || !offset_selection.is_empty()
 7835            || self
 7836                .active_edit_prediction
 7837                .as_ref()
 7838                .is_some_and(|completion| {
 7839                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7840                        return false;
 7841                    };
 7842                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7843                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7844                    !invalidation_range.contains(&offset_selection.head())
 7845                })
 7846        {
 7847            self.discard_edit_prediction(false, cx);
 7848            return None;
 7849        }
 7850
 7851        self.take_active_edit_prediction(cx);
 7852        let Some(provider) = self.edit_prediction_provider() else {
 7853            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7854            return None;
 7855        };
 7856
 7857        let (buffer, cursor_buffer_position) =
 7858            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7859
 7860        self.edit_prediction_settings =
 7861            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7862
 7863        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7864
 7865        if self.edit_prediction_indent_conflict {
 7866            let cursor_point = cursor.to_point(&multibuffer);
 7867
 7868            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7869
 7870            if let Some((_, indent)) = indents.iter().next()
 7871                && indent.len == cursor_point.column
 7872            {
 7873                self.edit_prediction_indent_conflict = false;
 7874            }
 7875        }
 7876
 7877        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7878
 7879        let (completion_id, edits, edit_preview) = match edit_prediction {
 7880            edit_prediction::EditPrediction::Local {
 7881                id,
 7882                edits,
 7883                edit_preview,
 7884            } => (id, edits, edit_preview),
 7885            edit_prediction::EditPrediction::Jump {
 7886                id,
 7887                snapshot,
 7888                target,
 7889            } => {
 7890                self.stale_edit_prediction_in_menu = None;
 7891                self.active_edit_prediction = Some(EditPredictionState {
 7892                    inlay_ids: vec![],
 7893                    completion: EditPrediction::MoveOutside { snapshot, target },
 7894                    completion_id: id,
 7895                    invalidation_range: None,
 7896                });
 7897                cx.notify();
 7898                return Some(());
 7899            }
 7900        };
 7901
 7902        let edits = edits
 7903            .into_iter()
 7904            .flat_map(|(range, new_text)| {
 7905                Some((
 7906                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 7907                    new_text,
 7908                ))
 7909            })
 7910            .collect::<Vec<_>>();
 7911        if edits.is_empty() {
 7912            return None;
 7913        }
 7914
 7915        let first_edit_start = edits.first().unwrap().0.start;
 7916        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7917        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7918
 7919        let last_edit_end = edits.last().unwrap().0.end;
 7920        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7921        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7922
 7923        let cursor_row = cursor.to_point(&multibuffer).row;
 7924
 7925        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7926
 7927        let mut inlay_ids = Vec::new();
 7928        let invalidation_row_range;
 7929        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7930            Some(cursor_row..edit_end_row)
 7931        } else if cursor_row > edit_end_row {
 7932            Some(edit_start_row..cursor_row)
 7933        } else {
 7934            None
 7935        };
 7936        let supports_jump = self
 7937            .edit_prediction_provider
 7938            .as_ref()
 7939            .map(|provider| provider.provider.supports_jump_to_edit())
 7940            .unwrap_or(true);
 7941
 7942        let is_move = supports_jump
 7943            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7944        let completion = if is_move {
 7945            invalidation_row_range =
 7946                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7947            let target = first_edit_start;
 7948            EditPrediction::MoveWithin { target, snapshot }
 7949        } else {
 7950            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7951                && !self.edit_predictions_hidden_for_vim_mode;
 7952
 7953            if show_completions_in_buffer {
 7954                if edits
 7955                    .iter()
 7956                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7957                {
 7958                    let mut inlays = Vec::new();
 7959                    for (range, new_text) in &edits {
 7960                        let inlay = Inlay::edit_prediction(
 7961                            post_inc(&mut self.next_inlay_id),
 7962                            range.start,
 7963                            new_text.as_ref(),
 7964                        );
 7965                        inlay_ids.push(inlay.id);
 7966                        inlays.push(inlay);
 7967                    }
 7968
 7969                    self.splice_inlays(&[], inlays, cx);
 7970                } else {
 7971                    let background_color = cx.theme().status().deleted_background;
 7972                    self.highlight_text::<EditPredictionHighlight>(
 7973                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7974                        HighlightStyle {
 7975                            background_color: Some(background_color),
 7976                            ..Default::default()
 7977                        },
 7978                        cx,
 7979                    );
 7980                }
 7981            }
 7982
 7983            invalidation_row_range = edit_start_row..edit_end_row;
 7984
 7985            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7986                if provider.show_tab_accept_marker() {
 7987                    EditDisplayMode::TabAccept
 7988                } else {
 7989                    EditDisplayMode::Inline
 7990                }
 7991            } else {
 7992                EditDisplayMode::DiffPopover
 7993            };
 7994
 7995            EditPrediction::Edit {
 7996                edits,
 7997                edit_preview,
 7998                display_mode,
 7999                snapshot,
 8000            }
 8001        };
 8002
 8003        let invalidation_range = multibuffer
 8004            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8005            ..multibuffer.anchor_after(Point::new(
 8006                invalidation_row_range.end,
 8007                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8008            ));
 8009
 8010        self.stale_edit_prediction_in_menu = None;
 8011        self.active_edit_prediction = Some(EditPredictionState {
 8012            inlay_ids,
 8013            completion,
 8014            completion_id,
 8015            invalidation_range: Some(invalidation_range),
 8016        });
 8017
 8018        cx.notify();
 8019
 8020        Some(())
 8021    }
 8022
 8023    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8024        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8025    }
 8026
 8027    fn clear_tasks(&mut self) {
 8028        self.tasks.clear()
 8029    }
 8030
 8031    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8032        if self.tasks.insert(key, value).is_some() {
 8033            // This case should hopefully be rare, but just in case...
 8034            log::error!(
 8035                "multiple different run targets found on a single line, only the last target will be rendered"
 8036            )
 8037        }
 8038    }
 8039
 8040    /// Get all display points of breakpoints that will be rendered within editor
 8041    ///
 8042    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8043    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8044    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8045    fn active_breakpoints(
 8046        &self,
 8047        range: Range<DisplayRow>,
 8048        window: &mut Window,
 8049        cx: &mut Context<Self>,
 8050    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8051        let mut breakpoint_display_points = HashMap::default();
 8052
 8053        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8054            return breakpoint_display_points;
 8055        };
 8056
 8057        let snapshot = self.snapshot(window, cx);
 8058
 8059        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8060        let Some(project) = self.project() else {
 8061            return breakpoint_display_points;
 8062        };
 8063
 8064        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8065            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8066
 8067        for (buffer_snapshot, range, excerpt_id) in
 8068            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8069        {
 8070            let Some(buffer) = project
 8071                .read(cx)
 8072                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8073            else {
 8074                continue;
 8075            };
 8076            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8077                &buffer,
 8078                Some(
 8079                    buffer_snapshot.anchor_before(range.start)
 8080                        ..buffer_snapshot.anchor_after(range.end),
 8081                ),
 8082                buffer_snapshot,
 8083                cx,
 8084            );
 8085            for (breakpoint, state) in breakpoints {
 8086                let multi_buffer_anchor =
 8087                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8088                let position = multi_buffer_anchor
 8089                    .to_point(&multi_buffer_snapshot)
 8090                    .to_display_point(&snapshot);
 8091
 8092                breakpoint_display_points.insert(
 8093                    position.row(),
 8094                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8095                );
 8096            }
 8097        }
 8098
 8099        breakpoint_display_points
 8100    }
 8101
 8102    fn breakpoint_context_menu(
 8103        &self,
 8104        anchor: Anchor,
 8105        window: &mut Window,
 8106        cx: &mut Context<Self>,
 8107    ) -> Entity<ui::ContextMenu> {
 8108        let weak_editor = cx.weak_entity();
 8109        let focus_handle = self.focus_handle(cx);
 8110
 8111        let row = self
 8112            .buffer
 8113            .read(cx)
 8114            .snapshot(cx)
 8115            .summary_for_anchor::<Point>(&anchor)
 8116            .row;
 8117
 8118        let breakpoint = self
 8119            .breakpoint_at_row(row, window, cx)
 8120            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8121
 8122        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8123            "Edit Log Breakpoint"
 8124        } else {
 8125            "Set Log Breakpoint"
 8126        };
 8127
 8128        let condition_breakpoint_msg = if breakpoint
 8129            .as_ref()
 8130            .is_some_and(|bp| bp.1.condition.is_some())
 8131        {
 8132            "Edit Condition Breakpoint"
 8133        } else {
 8134            "Set Condition Breakpoint"
 8135        };
 8136
 8137        let hit_condition_breakpoint_msg = if breakpoint
 8138            .as_ref()
 8139            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8140        {
 8141            "Edit Hit Condition Breakpoint"
 8142        } else {
 8143            "Set Hit Condition Breakpoint"
 8144        };
 8145
 8146        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8147            "Unset Breakpoint"
 8148        } else {
 8149            "Set Breakpoint"
 8150        };
 8151
 8152        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8153
 8154        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8155            BreakpointState::Enabled => Some("Disable"),
 8156            BreakpointState::Disabled => Some("Enable"),
 8157        });
 8158
 8159        let (anchor, breakpoint) =
 8160            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8161
 8162        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8163            menu.on_blur_subscription(Subscription::new(|| {}))
 8164                .context(focus_handle)
 8165                .when(run_to_cursor, |this| {
 8166                    let weak_editor = weak_editor.clone();
 8167                    this.entry("Run to cursor", None, move |window, cx| {
 8168                        weak_editor
 8169                            .update(cx, |editor, cx| {
 8170                                editor.change_selections(
 8171                                    SelectionEffects::no_scroll(),
 8172                                    window,
 8173                                    cx,
 8174                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8175                                );
 8176                            })
 8177                            .ok();
 8178
 8179                        window.dispatch_action(Box::new(RunToCursor), cx);
 8180                    })
 8181                    .separator()
 8182                })
 8183                .when_some(toggle_state_msg, |this, msg| {
 8184                    this.entry(msg, None, {
 8185                        let weak_editor = weak_editor.clone();
 8186                        let breakpoint = breakpoint.clone();
 8187                        move |_window, cx| {
 8188                            weak_editor
 8189                                .update(cx, |this, cx| {
 8190                                    this.edit_breakpoint_at_anchor(
 8191                                        anchor,
 8192                                        breakpoint.as_ref().clone(),
 8193                                        BreakpointEditAction::InvertState,
 8194                                        cx,
 8195                                    );
 8196                                })
 8197                                .log_err();
 8198                        }
 8199                    })
 8200                })
 8201                .entry(set_breakpoint_msg, None, {
 8202                    let weak_editor = weak_editor.clone();
 8203                    let breakpoint = breakpoint.clone();
 8204                    move |_window, cx| {
 8205                        weak_editor
 8206                            .update(cx, |this, cx| {
 8207                                this.edit_breakpoint_at_anchor(
 8208                                    anchor,
 8209                                    breakpoint.as_ref().clone(),
 8210                                    BreakpointEditAction::Toggle,
 8211                                    cx,
 8212                                );
 8213                            })
 8214                            .log_err();
 8215                    }
 8216                })
 8217                .entry(log_breakpoint_msg, None, {
 8218                    let breakpoint = breakpoint.clone();
 8219                    let weak_editor = weak_editor.clone();
 8220                    move |window, cx| {
 8221                        weak_editor
 8222                            .update(cx, |this, cx| {
 8223                                this.add_edit_breakpoint_block(
 8224                                    anchor,
 8225                                    breakpoint.as_ref(),
 8226                                    BreakpointPromptEditAction::Log,
 8227                                    window,
 8228                                    cx,
 8229                                );
 8230                            })
 8231                            .log_err();
 8232                    }
 8233                })
 8234                .entry(condition_breakpoint_msg, None, {
 8235                    let breakpoint = breakpoint.clone();
 8236                    let weak_editor = weak_editor.clone();
 8237                    move |window, cx| {
 8238                        weak_editor
 8239                            .update(cx, |this, cx| {
 8240                                this.add_edit_breakpoint_block(
 8241                                    anchor,
 8242                                    breakpoint.as_ref(),
 8243                                    BreakpointPromptEditAction::Condition,
 8244                                    window,
 8245                                    cx,
 8246                                );
 8247                            })
 8248                            .log_err();
 8249                    }
 8250                })
 8251                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8252                    weak_editor
 8253                        .update(cx, |this, cx| {
 8254                            this.add_edit_breakpoint_block(
 8255                                anchor,
 8256                                breakpoint.as_ref(),
 8257                                BreakpointPromptEditAction::HitCondition,
 8258                                window,
 8259                                cx,
 8260                            );
 8261                        })
 8262                        .log_err();
 8263                })
 8264        })
 8265    }
 8266
 8267    fn render_breakpoint(
 8268        &self,
 8269        position: Anchor,
 8270        row: DisplayRow,
 8271        breakpoint: &Breakpoint,
 8272        state: Option<BreakpointSessionState>,
 8273        cx: &mut Context<Self>,
 8274    ) -> IconButton {
 8275        let is_rejected = state.is_some_and(|s| !s.verified);
 8276        // Is it a breakpoint that shows up when hovering over gutter?
 8277        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8278            (false, false),
 8279            |PhantomBreakpointIndicator {
 8280                 is_active,
 8281                 display_row,
 8282                 collides_with_existing_breakpoint,
 8283             }| {
 8284                (
 8285                    is_active && display_row == row,
 8286                    collides_with_existing_breakpoint,
 8287                )
 8288            },
 8289        );
 8290
 8291        let (color, icon) = {
 8292            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8293                (false, false) => ui::IconName::DebugBreakpoint,
 8294                (true, false) => ui::IconName::DebugLogBreakpoint,
 8295                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8296                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8297            };
 8298
 8299            let color = if is_phantom {
 8300                Color::Hint
 8301            } else if is_rejected {
 8302                Color::Disabled
 8303            } else {
 8304                Color::Debugger
 8305            };
 8306
 8307            (color, icon)
 8308        };
 8309
 8310        let breakpoint = Arc::from(breakpoint.clone());
 8311
 8312        let alt_as_text = gpui::Keystroke {
 8313            modifiers: Modifiers::secondary_key(),
 8314            ..Default::default()
 8315        };
 8316        let primary_action_text = if breakpoint.is_disabled() {
 8317            "Enable breakpoint"
 8318        } else if is_phantom && !collides_with_existing {
 8319            "Set breakpoint"
 8320        } else {
 8321            "Unset breakpoint"
 8322        };
 8323        let focus_handle = self.focus_handle.clone();
 8324
 8325        let meta = if is_rejected {
 8326            SharedString::from("No executable code is associated with this line.")
 8327        } else if collides_with_existing && !breakpoint.is_disabled() {
 8328            SharedString::from(format!(
 8329                "{alt_as_text}-click to disable,\nright-click for more options."
 8330            ))
 8331        } else {
 8332            SharedString::from("Right-click for more options.")
 8333        };
 8334        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8335            .icon_size(IconSize::XSmall)
 8336            .size(ui::ButtonSize::None)
 8337            .when(is_rejected, |this| {
 8338                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8339            })
 8340            .icon_color(color)
 8341            .style(ButtonStyle::Transparent)
 8342            .on_click(cx.listener({
 8343                move |editor, event: &ClickEvent, window, cx| {
 8344                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8345                        BreakpointEditAction::InvertState
 8346                    } else {
 8347                        BreakpointEditAction::Toggle
 8348                    };
 8349
 8350                    window.focus(&editor.focus_handle(cx));
 8351                    editor.edit_breakpoint_at_anchor(
 8352                        position,
 8353                        breakpoint.as_ref().clone(),
 8354                        edit_action,
 8355                        cx,
 8356                    );
 8357                }
 8358            }))
 8359            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8360                editor.set_breakpoint_context_menu(
 8361                    row,
 8362                    Some(position),
 8363                    event.position(),
 8364                    window,
 8365                    cx,
 8366                );
 8367            }))
 8368            .tooltip(move |_window, cx| {
 8369                Tooltip::with_meta_in(
 8370                    primary_action_text,
 8371                    Some(&ToggleBreakpoint),
 8372                    meta.clone(),
 8373                    &focus_handle,
 8374                    cx,
 8375                )
 8376            })
 8377    }
 8378
 8379    fn build_tasks_context(
 8380        project: &Entity<Project>,
 8381        buffer: &Entity<Buffer>,
 8382        buffer_row: u32,
 8383        tasks: &Arc<RunnableTasks>,
 8384        cx: &mut Context<Self>,
 8385    ) -> Task<Option<task::TaskContext>> {
 8386        let position = Point::new(buffer_row, tasks.column);
 8387        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8388        let location = Location {
 8389            buffer: buffer.clone(),
 8390            range: range_start..range_start,
 8391        };
 8392        // Fill in the environmental variables from the tree-sitter captures
 8393        let mut captured_task_variables = TaskVariables::default();
 8394        for (capture_name, value) in tasks.extra_variables.clone() {
 8395            captured_task_variables.insert(
 8396                task::VariableName::Custom(capture_name.into()),
 8397                value.clone(),
 8398            );
 8399        }
 8400        project.update(cx, |project, cx| {
 8401            project.task_store().update(cx, |task_store, cx| {
 8402                task_store.task_context_for_location(captured_task_variables, location, cx)
 8403            })
 8404        })
 8405    }
 8406
 8407    pub fn spawn_nearest_task(
 8408        &mut self,
 8409        action: &SpawnNearestTask,
 8410        window: &mut Window,
 8411        cx: &mut Context<Self>,
 8412    ) {
 8413        let Some((workspace, _)) = self.workspace.clone() else {
 8414            return;
 8415        };
 8416        let Some(project) = self.project.clone() else {
 8417            return;
 8418        };
 8419
 8420        // Try to find a closest, enclosing node using tree-sitter that has a task
 8421        let Some((buffer, buffer_row, tasks)) = self
 8422            .find_enclosing_node_task(cx)
 8423            // Or find the task that's closest in row-distance.
 8424            .or_else(|| self.find_closest_task(cx))
 8425        else {
 8426            return;
 8427        };
 8428
 8429        let reveal_strategy = action.reveal;
 8430        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8431        cx.spawn_in(window, async move |_, cx| {
 8432            let context = task_context.await?;
 8433            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8434
 8435            let resolved = &mut resolved_task.resolved;
 8436            resolved.reveal = reveal_strategy;
 8437
 8438            workspace
 8439                .update_in(cx, |workspace, window, cx| {
 8440                    workspace.schedule_resolved_task(
 8441                        task_source_kind,
 8442                        resolved_task,
 8443                        false,
 8444                        window,
 8445                        cx,
 8446                    );
 8447                })
 8448                .ok()
 8449        })
 8450        .detach();
 8451    }
 8452
 8453    fn find_closest_task(
 8454        &mut self,
 8455        cx: &mut Context<Self>,
 8456    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8457        let cursor_row = self
 8458            .selections
 8459            .newest_adjusted(&self.display_snapshot(cx))
 8460            .head()
 8461            .row;
 8462
 8463        let ((buffer_id, row), tasks) = self
 8464            .tasks
 8465            .iter()
 8466            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8467
 8468        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8469        let tasks = Arc::new(tasks.to_owned());
 8470        Some((buffer, *row, tasks))
 8471    }
 8472
 8473    fn find_enclosing_node_task(
 8474        &mut self,
 8475        cx: &mut Context<Self>,
 8476    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8477        let snapshot = self.buffer.read(cx).snapshot(cx);
 8478        let offset = self
 8479            .selections
 8480            .newest::<usize>(&self.display_snapshot(cx))
 8481            .head();
 8482        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8483        let buffer_id = excerpt.buffer().remote_id();
 8484
 8485        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8486        let mut cursor = layer.node().walk();
 8487
 8488        while cursor.goto_first_child_for_byte(offset).is_some() {
 8489            if cursor.node().end_byte() == offset {
 8490                cursor.goto_next_sibling();
 8491            }
 8492        }
 8493
 8494        // Ascend to the smallest ancestor that contains the range and has a task.
 8495        loop {
 8496            let node = cursor.node();
 8497            let node_range = node.byte_range();
 8498            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8499
 8500            // Check if this node contains our offset
 8501            if node_range.start <= offset && node_range.end >= offset {
 8502                // If it contains offset, check for task
 8503                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8504                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8505                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8506                }
 8507            }
 8508
 8509            if !cursor.goto_parent() {
 8510                break;
 8511            }
 8512        }
 8513        None
 8514    }
 8515
 8516    fn render_run_indicator(
 8517        &self,
 8518        _style: &EditorStyle,
 8519        is_active: bool,
 8520        row: DisplayRow,
 8521        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8522        cx: &mut Context<Self>,
 8523    ) -> IconButton {
 8524        let color = Color::Muted;
 8525        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8526
 8527        IconButton::new(
 8528            ("run_indicator", row.0 as usize),
 8529            ui::IconName::PlayOutlined,
 8530        )
 8531        .shape(ui::IconButtonShape::Square)
 8532        .icon_size(IconSize::XSmall)
 8533        .icon_color(color)
 8534        .toggle_state(is_active)
 8535        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8536            let quick_launch = match e {
 8537                ClickEvent::Keyboard(_) => true,
 8538                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8539            };
 8540
 8541            window.focus(&editor.focus_handle(cx));
 8542            editor.toggle_code_actions(
 8543                &ToggleCodeActions {
 8544                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8545                    quick_launch,
 8546                },
 8547                window,
 8548                cx,
 8549            );
 8550        }))
 8551        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8552            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8553        }))
 8554    }
 8555
 8556    pub fn context_menu_visible(&self) -> bool {
 8557        !self.edit_prediction_preview_is_active()
 8558            && self
 8559                .context_menu
 8560                .borrow()
 8561                .as_ref()
 8562                .is_some_and(|menu| menu.visible())
 8563    }
 8564
 8565    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8566        self.context_menu
 8567            .borrow()
 8568            .as_ref()
 8569            .map(|menu| menu.origin())
 8570    }
 8571
 8572    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8573        self.context_menu_options = Some(options);
 8574    }
 8575
 8576    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8577    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8578
 8579    fn render_edit_prediction_popover(
 8580        &mut self,
 8581        text_bounds: &Bounds<Pixels>,
 8582        content_origin: gpui::Point<Pixels>,
 8583        right_margin: Pixels,
 8584        editor_snapshot: &EditorSnapshot,
 8585        visible_row_range: Range<DisplayRow>,
 8586        scroll_top: ScrollOffset,
 8587        scroll_bottom: ScrollOffset,
 8588        line_layouts: &[LineWithInvisibles],
 8589        line_height: Pixels,
 8590        scroll_position: gpui::Point<ScrollOffset>,
 8591        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8592        newest_selection_head: Option<DisplayPoint>,
 8593        editor_width: Pixels,
 8594        style: &EditorStyle,
 8595        window: &mut Window,
 8596        cx: &mut App,
 8597    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8598        if self.mode().is_minimap() {
 8599            return None;
 8600        }
 8601        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8602
 8603        if self.edit_prediction_visible_in_cursor_popover(true) {
 8604            return None;
 8605        }
 8606
 8607        match &active_edit_prediction.completion {
 8608            EditPrediction::MoveWithin { target, .. } => {
 8609                let target_display_point = target.to_display_point(editor_snapshot);
 8610
 8611                if self.edit_prediction_requires_modifier() {
 8612                    if !self.edit_prediction_preview_is_active() {
 8613                        return None;
 8614                    }
 8615
 8616                    self.render_edit_prediction_modifier_jump_popover(
 8617                        text_bounds,
 8618                        content_origin,
 8619                        visible_row_range,
 8620                        line_layouts,
 8621                        line_height,
 8622                        scroll_pixel_position,
 8623                        newest_selection_head,
 8624                        target_display_point,
 8625                        window,
 8626                        cx,
 8627                    )
 8628                } else {
 8629                    self.render_edit_prediction_eager_jump_popover(
 8630                        text_bounds,
 8631                        content_origin,
 8632                        editor_snapshot,
 8633                        visible_row_range,
 8634                        scroll_top,
 8635                        scroll_bottom,
 8636                        line_height,
 8637                        scroll_pixel_position,
 8638                        target_display_point,
 8639                        editor_width,
 8640                        window,
 8641                        cx,
 8642                    )
 8643                }
 8644            }
 8645            EditPrediction::Edit {
 8646                display_mode: EditDisplayMode::Inline,
 8647                ..
 8648            } => None,
 8649            EditPrediction::Edit {
 8650                display_mode: EditDisplayMode::TabAccept,
 8651                edits,
 8652                ..
 8653            } => {
 8654                let range = &edits.first()?.0;
 8655                let target_display_point = range.end.to_display_point(editor_snapshot);
 8656
 8657                self.render_edit_prediction_end_of_line_popover(
 8658                    "Accept",
 8659                    editor_snapshot,
 8660                    visible_row_range,
 8661                    target_display_point,
 8662                    line_height,
 8663                    scroll_pixel_position,
 8664                    content_origin,
 8665                    editor_width,
 8666                    window,
 8667                    cx,
 8668                )
 8669            }
 8670            EditPrediction::Edit {
 8671                edits,
 8672                edit_preview,
 8673                display_mode: EditDisplayMode::DiffPopover,
 8674                snapshot,
 8675            } => self.render_edit_prediction_diff_popover(
 8676                text_bounds,
 8677                content_origin,
 8678                right_margin,
 8679                editor_snapshot,
 8680                visible_row_range,
 8681                line_layouts,
 8682                line_height,
 8683                scroll_position,
 8684                scroll_pixel_position,
 8685                newest_selection_head,
 8686                editor_width,
 8687                style,
 8688                edits,
 8689                edit_preview,
 8690                snapshot,
 8691                window,
 8692                cx,
 8693            ),
 8694            EditPrediction::MoveOutside { snapshot, .. } => {
 8695                let file_name = snapshot
 8696                    .file()
 8697                    .map(|file| file.file_name(cx))
 8698                    .unwrap_or("untitled");
 8699                let mut element = self
 8700                    .render_edit_prediction_line_popover(
 8701                        format!("Jump to {file_name}"),
 8702                        Some(IconName::ZedPredict),
 8703                        window,
 8704                        cx,
 8705                    )
 8706                    .into_any();
 8707
 8708                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8709                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8710                let origin_y = text_bounds.size.height - size.height - px(30.);
 8711                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8712                element.prepaint_at(origin, window, cx);
 8713
 8714                Some((element, origin))
 8715            }
 8716        }
 8717    }
 8718
 8719    fn render_edit_prediction_modifier_jump_popover(
 8720        &mut self,
 8721        text_bounds: &Bounds<Pixels>,
 8722        content_origin: gpui::Point<Pixels>,
 8723        visible_row_range: Range<DisplayRow>,
 8724        line_layouts: &[LineWithInvisibles],
 8725        line_height: Pixels,
 8726        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8727        newest_selection_head: Option<DisplayPoint>,
 8728        target_display_point: DisplayPoint,
 8729        window: &mut Window,
 8730        cx: &mut App,
 8731    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8732        let scrolled_content_origin =
 8733            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8734
 8735        const SCROLL_PADDING_Y: Pixels = px(12.);
 8736
 8737        if target_display_point.row() < visible_row_range.start {
 8738            return self.render_edit_prediction_scroll_popover(
 8739                |_| SCROLL_PADDING_Y,
 8740                IconName::ArrowUp,
 8741                visible_row_range,
 8742                line_layouts,
 8743                newest_selection_head,
 8744                scrolled_content_origin,
 8745                window,
 8746                cx,
 8747            );
 8748        } else if target_display_point.row() >= visible_row_range.end {
 8749            return self.render_edit_prediction_scroll_popover(
 8750                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8751                IconName::ArrowDown,
 8752                visible_row_range,
 8753                line_layouts,
 8754                newest_selection_head,
 8755                scrolled_content_origin,
 8756                window,
 8757                cx,
 8758            );
 8759        }
 8760
 8761        const POLE_WIDTH: Pixels = px(2.);
 8762
 8763        let line_layout =
 8764            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8765        let target_column = target_display_point.column() as usize;
 8766
 8767        let target_x = line_layout.x_for_index(target_column);
 8768        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8769            - scroll_pixel_position.y;
 8770
 8771        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8772
 8773        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8774        border_color.l += 0.001;
 8775
 8776        let mut element = v_flex()
 8777            .items_end()
 8778            .when(flag_on_right, |el| el.items_start())
 8779            .child(if flag_on_right {
 8780                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8781                    .rounded_bl(px(0.))
 8782                    .rounded_tl(px(0.))
 8783                    .border_l_2()
 8784                    .border_color(border_color)
 8785            } else {
 8786                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8787                    .rounded_br(px(0.))
 8788                    .rounded_tr(px(0.))
 8789                    .border_r_2()
 8790                    .border_color(border_color)
 8791            })
 8792            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8793            .into_any();
 8794
 8795        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8796
 8797        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8798            - point(
 8799                if flag_on_right {
 8800                    POLE_WIDTH
 8801                } else {
 8802                    size.width - POLE_WIDTH
 8803                },
 8804                size.height - line_height,
 8805            );
 8806
 8807        origin.x = origin.x.max(content_origin.x);
 8808
 8809        element.prepaint_at(origin, window, cx);
 8810
 8811        Some((element, origin))
 8812    }
 8813
 8814    fn render_edit_prediction_scroll_popover(
 8815        &mut self,
 8816        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8817        scroll_icon: IconName,
 8818        visible_row_range: Range<DisplayRow>,
 8819        line_layouts: &[LineWithInvisibles],
 8820        newest_selection_head: Option<DisplayPoint>,
 8821        scrolled_content_origin: gpui::Point<Pixels>,
 8822        window: &mut Window,
 8823        cx: &mut App,
 8824    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8825        let mut element = self
 8826            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8827            .into_any();
 8828
 8829        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8830
 8831        let cursor = newest_selection_head?;
 8832        let cursor_row_layout =
 8833            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8834        let cursor_column = cursor.column() as usize;
 8835
 8836        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8837
 8838        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8839
 8840        element.prepaint_at(origin, window, cx);
 8841        Some((element, origin))
 8842    }
 8843
 8844    fn render_edit_prediction_eager_jump_popover(
 8845        &mut self,
 8846        text_bounds: &Bounds<Pixels>,
 8847        content_origin: gpui::Point<Pixels>,
 8848        editor_snapshot: &EditorSnapshot,
 8849        visible_row_range: Range<DisplayRow>,
 8850        scroll_top: ScrollOffset,
 8851        scroll_bottom: ScrollOffset,
 8852        line_height: Pixels,
 8853        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8854        target_display_point: DisplayPoint,
 8855        editor_width: Pixels,
 8856        window: &mut Window,
 8857        cx: &mut App,
 8858    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8859        if target_display_point.row().as_f64() < scroll_top {
 8860            let mut element = self
 8861                .render_edit_prediction_line_popover(
 8862                    "Jump to Edit",
 8863                    Some(IconName::ArrowUp),
 8864                    window,
 8865                    cx,
 8866                )
 8867                .into_any();
 8868
 8869            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8870            let offset = point(
 8871                (text_bounds.size.width - size.width) / 2.,
 8872                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8873            );
 8874
 8875            let origin = text_bounds.origin + offset;
 8876            element.prepaint_at(origin, window, cx);
 8877            Some((element, origin))
 8878        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 8879            let mut element = self
 8880                .render_edit_prediction_line_popover(
 8881                    "Jump to Edit",
 8882                    Some(IconName::ArrowDown),
 8883                    window,
 8884                    cx,
 8885                )
 8886                .into_any();
 8887
 8888            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8889            let offset = point(
 8890                (text_bounds.size.width - size.width) / 2.,
 8891                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8892            );
 8893
 8894            let origin = text_bounds.origin + offset;
 8895            element.prepaint_at(origin, window, cx);
 8896            Some((element, origin))
 8897        } else {
 8898            self.render_edit_prediction_end_of_line_popover(
 8899                "Jump to Edit",
 8900                editor_snapshot,
 8901                visible_row_range,
 8902                target_display_point,
 8903                line_height,
 8904                scroll_pixel_position,
 8905                content_origin,
 8906                editor_width,
 8907                window,
 8908                cx,
 8909            )
 8910        }
 8911    }
 8912
 8913    fn render_edit_prediction_end_of_line_popover(
 8914        self: &mut Editor,
 8915        label: &'static str,
 8916        editor_snapshot: &EditorSnapshot,
 8917        visible_row_range: Range<DisplayRow>,
 8918        target_display_point: DisplayPoint,
 8919        line_height: Pixels,
 8920        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8921        content_origin: gpui::Point<Pixels>,
 8922        editor_width: Pixels,
 8923        window: &mut Window,
 8924        cx: &mut App,
 8925    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8926        let target_line_end = DisplayPoint::new(
 8927            target_display_point.row(),
 8928            editor_snapshot.line_len(target_display_point.row()),
 8929        );
 8930
 8931        let mut element = self
 8932            .render_edit_prediction_line_popover(label, None, window, cx)
 8933            .into_any();
 8934
 8935        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8936
 8937        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8938
 8939        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 8940        let mut origin = start_point
 8941            + line_origin
 8942            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8943        origin.x = origin.x.max(content_origin.x);
 8944
 8945        let max_x = content_origin.x + editor_width - size.width;
 8946
 8947        if origin.x > max_x {
 8948            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8949
 8950            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8951                origin.y += offset;
 8952                IconName::ArrowUp
 8953            } else {
 8954                origin.y -= offset;
 8955                IconName::ArrowDown
 8956            };
 8957
 8958            element = self
 8959                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 8960                .into_any();
 8961
 8962            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8963
 8964            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8965        }
 8966
 8967        element.prepaint_at(origin, window, cx);
 8968        Some((element, origin))
 8969    }
 8970
 8971    fn render_edit_prediction_diff_popover(
 8972        self: &Editor,
 8973        text_bounds: &Bounds<Pixels>,
 8974        content_origin: gpui::Point<Pixels>,
 8975        right_margin: Pixels,
 8976        editor_snapshot: &EditorSnapshot,
 8977        visible_row_range: Range<DisplayRow>,
 8978        line_layouts: &[LineWithInvisibles],
 8979        line_height: Pixels,
 8980        scroll_position: gpui::Point<ScrollOffset>,
 8981        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8982        newest_selection_head: Option<DisplayPoint>,
 8983        editor_width: Pixels,
 8984        style: &EditorStyle,
 8985        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 8986        edit_preview: &Option<language::EditPreview>,
 8987        snapshot: &language::BufferSnapshot,
 8988        window: &mut Window,
 8989        cx: &mut App,
 8990    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8991        let edit_start = edits
 8992            .first()
 8993            .unwrap()
 8994            .0
 8995            .start
 8996            .to_display_point(editor_snapshot);
 8997        let edit_end = edits
 8998            .last()
 8999            .unwrap()
 9000            .0
 9001            .end
 9002            .to_display_point(editor_snapshot);
 9003
 9004        let is_visible = visible_row_range.contains(&edit_start.row())
 9005            || visible_row_range.contains(&edit_end.row());
 9006        if !is_visible {
 9007            return None;
 9008        }
 9009
 9010        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9011            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9012        } else {
 9013            // Fallback for providers without edit_preview
 9014            crate::edit_prediction_fallback_text(edits, cx)
 9015        };
 9016
 9017        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9018        let line_count = highlighted_edits.text.lines().count();
 9019
 9020        const BORDER_WIDTH: Pixels = px(1.);
 9021
 9022        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9023        let has_keybind = keybind.is_some();
 9024
 9025        let mut element = h_flex()
 9026            .items_start()
 9027            .child(
 9028                h_flex()
 9029                    .bg(cx.theme().colors().editor_background)
 9030                    .border(BORDER_WIDTH)
 9031                    .shadow_xs()
 9032                    .border_color(cx.theme().colors().border)
 9033                    .rounded_l_lg()
 9034                    .when(line_count > 1, |el| el.rounded_br_lg())
 9035                    .pr_1()
 9036                    .child(styled_text),
 9037            )
 9038            .child(
 9039                h_flex()
 9040                    .h(line_height + BORDER_WIDTH * 2.)
 9041                    .px_1p5()
 9042                    .gap_1()
 9043                    // Workaround: For some reason, there's a gap if we don't do this
 9044                    .ml(-BORDER_WIDTH)
 9045                    .shadow(vec![gpui::BoxShadow {
 9046                        color: gpui::black().opacity(0.05),
 9047                        offset: point(px(1.), px(1.)),
 9048                        blur_radius: px(2.),
 9049                        spread_radius: px(0.),
 9050                    }])
 9051                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9052                    .border(BORDER_WIDTH)
 9053                    .border_color(cx.theme().colors().border)
 9054                    .rounded_r_lg()
 9055                    .id("edit_prediction_diff_popover_keybind")
 9056                    .when(!has_keybind, |el| {
 9057                        let status_colors = cx.theme().status();
 9058
 9059                        el.bg(status_colors.error_background)
 9060                            .border_color(status_colors.error.opacity(0.6))
 9061                            .child(Icon::new(IconName::Info).color(Color::Error))
 9062                            .cursor_default()
 9063                            .hoverable_tooltip(move |_window, cx| {
 9064                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9065                            })
 9066                    })
 9067                    .children(keybind),
 9068            )
 9069            .into_any();
 9070
 9071        let longest_row =
 9072            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9073        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9074            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9075        } else {
 9076            layout_line(
 9077                longest_row,
 9078                editor_snapshot,
 9079                style,
 9080                editor_width,
 9081                |_| false,
 9082                window,
 9083                cx,
 9084            )
 9085            .width
 9086        };
 9087
 9088        let viewport_bounds =
 9089            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9090                right: -right_margin,
 9091                ..Default::default()
 9092            });
 9093
 9094        let x_after_longest = Pixels::from(
 9095            ScrollPixelOffset::from(
 9096                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9097            ) - scroll_pixel_position.x,
 9098        );
 9099
 9100        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9101
 9102        // Fully visible if it can be displayed within the window (allow overlapping other
 9103        // panes). However, this is only allowed if the popover starts within text_bounds.
 9104        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9105            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9106
 9107        let mut origin = if can_position_to_the_right {
 9108            point(
 9109                x_after_longest,
 9110                text_bounds.origin.y
 9111                    + Pixels::from(
 9112                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9113                            - scroll_pixel_position.y,
 9114                    ),
 9115            )
 9116        } else {
 9117            let cursor_row = newest_selection_head.map(|head| head.row());
 9118            let above_edit = edit_start
 9119                .row()
 9120                .0
 9121                .checked_sub(line_count as u32)
 9122                .map(DisplayRow);
 9123            let below_edit = Some(edit_end.row() + 1);
 9124            let above_cursor =
 9125                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9126            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9127
 9128            // Place the edit popover adjacent to the edit if there is a location
 9129            // available that is onscreen and does not obscure the cursor. Otherwise,
 9130            // place it adjacent to the cursor.
 9131            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9132                .into_iter()
 9133                .flatten()
 9134                .find(|&start_row| {
 9135                    let end_row = start_row + line_count as u32;
 9136                    visible_row_range.contains(&start_row)
 9137                        && visible_row_range.contains(&end_row)
 9138                        && cursor_row
 9139                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9140                })?;
 9141
 9142            content_origin
 9143                + point(
 9144                    Pixels::from(-scroll_pixel_position.x),
 9145                    Pixels::from(
 9146                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9147                    ),
 9148                )
 9149        };
 9150
 9151        origin.x -= BORDER_WIDTH;
 9152
 9153        window.defer_draw(element, origin, 1);
 9154
 9155        // Do not return an element, since it will already be drawn due to defer_draw.
 9156        None
 9157    }
 9158
 9159    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9160        px(30.)
 9161    }
 9162
 9163    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9164        if self.read_only(cx) {
 9165            cx.theme().players().read_only()
 9166        } else {
 9167            self.style.as_ref().unwrap().local_player
 9168        }
 9169    }
 9170
 9171    fn render_edit_prediction_accept_keybind(
 9172        &self,
 9173        window: &mut Window,
 9174        cx: &mut App,
 9175    ) -> Option<AnyElement> {
 9176        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9177        let accept_keystroke = accept_binding.keystroke()?;
 9178
 9179        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9180
 9181        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9182            Color::Accent
 9183        } else {
 9184            Color::Muted
 9185        };
 9186
 9187        h_flex()
 9188            .px_0p5()
 9189            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9190            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9191            .text_size(TextSize::XSmall.rems(cx))
 9192            .child(h_flex().children(ui::render_modifiers(
 9193                accept_keystroke.modifiers(),
 9194                PlatformStyle::platform(),
 9195                Some(modifiers_color),
 9196                Some(IconSize::XSmall.rems().into()),
 9197                true,
 9198            )))
 9199            .when(is_platform_style_mac, |parent| {
 9200                parent.child(accept_keystroke.key().to_string())
 9201            })
 9202            .when(!is_platform_style_mac, |parent| {
 9203                parent.child(
 9204                    Key::new(
 9205                        util::capitalize(accept_keystroke.key()),
 9206                        Some(Color::Default),
 9207                    )
 9208                    .size(Some(IconSize::XSmall.rems().into())),
 9209                )
 9210            })
 9211            .into_any()
 9212            .into()
 9213    }
 9214
 9215    fn render_edit_prediction_line_popover(
 9216        &self,
 9217        label: impl Into<SharedString>,
 9218        icon: Option<IconName>,
 9219        window: &mut Window,
 9220        cx: &mut App,
 9221    ) -> Stateful<Div> {
 9222        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9223
 9224        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9225        let has_keybind = keybind.is_some();
 9226
 9227        h_flex()
 9228            .id("ep-line-popover")
 9229            .py_0p5()
 9230            .pl_1()
 9231            .pr(padding_right)
 9232            .gap_1()
 9233            .rounded_md()
 9234            .border_1()
 9235            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9236            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9237            .shadow_xs()
 9238            .when(!has_keybind, |el| {
 9239                let status_colors = cx.theme().status();
 9240
 9241                el.bg(status_colors.error_background)
 9242                    .border_color(status_colors.error.opacity(0.6))
 9243                    .pl_2()
 9244                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9245                    .cursor_default()
 9246                    .hoverable_tooltip(move |_window, cx| {
 9247                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9248                    })
 9249            })
 9250            .children(keybind)
 9251            .child(
 9252                Label::new(label)
 9253                    .size(LabelSize::Small)
 9254                    .when(!has_keybind, |el| {
 9255                        el.color(cx.theme().status().error.into()).strikethrough()
 9256                    }),
 9257            )
 9258            .when(!has_keybind, |el| {
 9259                el.child(
 9260                    h_flex().ml_1().child(
 9261                        Icon::new(IconName::Info)
 9262                            .size(IconSize::Small)
 9263                            .color(cx.theme().status().error.into()),
 9264                    ),
 9265                )
 9266            })
 9267            .when_some(icon, |element, icon| {
 9268                element.child(
 9269                    div()
 9270                        .mt(px(1.5))
 9271                        .child(Icon::new(icon).size(IconSize::Small)),
 9272                )
 9273            })
 9274    }
 9275
 9276    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9277        let accent_color = cx.theme().colors().text_accent;
 9278        let editor_bg_color = cx.theme().colors().editor_background;
 9279        editor_bg_color.blend(accent_color.opacity(0.1))
 9280    }
 9281
 9282    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9283        let accent_color = cx.theme().colors().text_accent;
 9284        let editor_bg_color = cx.theme().colors().editor_background;
 9285        editor_bg_color.blend(accent_color.opacity(0.6))
 9286    }
 9287    fn get_prediction_provider_icon_name(
 9288        provider: &Option<RegisteredEditPredictionProvider>,
 9289    ) -> IconName {
 9290        match provider {
 9291            Some(provider) => match provider.provider.name() {
 9292                "copilot" => IconName::Copilot,
 9293                "supermaven" => IconName::Supermaven,
 9294                _ => IconName::ZedPredict,
 9295            },
 9296            None => IconName::ZedPredict,
 9297        }
 9298    }
 9299
 9300    fn render_edit_prediction_cursor_popover(
 9301        &self,
 9302        min_width: Pixels,
 9303        max_width: Pixels,
 9304        cursor_point: Point,
 9305        style: &EditorStyle,
 9306        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9307        _window: &Window,
 9308        cx: &mut Context<Editor>,
 9309    ) -> Option<AnyElement> {
 9310        let provider = self.edit_prediction_provider.as_ref()?;
 9311        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9312
 9313        let is_refreshing = provider.provider.is_refreshing(cx);
 9314
 9315        fn pending_completion_container(icon: IconName) -> Div {
 9316            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9317        }
 9318
 9319        let completion = match &self.active_edit_prediction {
 9320            Some(prediction) => {
 9321                if !self.has_visible_completions_menu() {
 9322                    const RADIUS: Pixels = px(6.);
 9323                    const BORDER_WIDTH: Pixels = px(1.);
 9324
 9325                    return Some(
 9326                        h_flex()
 9327                            .elevation_2(cx)
 9328                            .border(BORDER_WIDTH)
 9329                            .border_color(cx.theme().colors().border)
 9330                            .when(accept_keystroke.is_none(), |el| {
 9331                                el.border_color(cx.theme().status().error)
 9332                            })
 9333                            .rounded(RADIUS)
 9334                            .rounded_tl(px(0.))
 9335                            .overflow_hidden()
 9336                            .child(div().px_1p5().child(match &prediction.completion {
 9337                                EditPrediction::MoveWithin { target, snapshot } => {
 9338                                    use text::ToPoint as _;
 9339                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9340                                    {
 9341                                        Icon::new(IconName::ZedPredictDown)
 9342                                    } else {
 9343                                        Icon::new(IconName::ZedPredictUp)
 9344                                    }
 9345                                }
 9346                                EditPrediction::MoveOutside { .. } => {
 9347                                    // TODO [zeta2] custom icon for external jump?
 9348                                    Icon::new(provider_icon)
 9349                                }
 9350                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9351                            }))
 9352                            .child(
 9353                                h_flex()
 9354                                    .gap_1()
 9355                                    .py_1()
 9356                                    .px_2()
 9357                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9358                                    .border_l_1()
 9359                                    .border_color(cx.theme().colors().border)
 9360                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9361                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9362                                        el.child(
 9363                                            Label::new("Hold")
 9364                                                .size(LabelSize::Small)
 9365                                                .when(accept_keystroke.is_none(), |el| {
 9366                                                    el.strikethrough()
 9367                                                })
 9368                                                .line_height_style(LineHeightStyle::UiLabel),
 9369                                        )
 9370                                    })
 9371                                    .id("edit_prediction_cursor_popover_keybind")
 9372                                    .when(accept_keystroke.is_none(), |el| {
 9373                                        let status_colors = cx.theme().status();
 9374
 9375                                        el.bg(status_colors.error_background)
 9376                                            .border_color(status_colors.error.opacity(0.6))
 9377                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9378                                            .cursor_default()
 9379                                            .hoverable_tooltip(move |_window, cx| {
 9380                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9381                                                    .into()
 9382                                            })
 9383                                    })
 9384                                    .when_some(
 9385                                        accept_keystroke.as_ref(),
 9386                                        |el, accept_keystroke| {
 9387                                            el.child(h_flex().children(ui::render_modifiers(
 9388                                                accept_keystroke.modifiers(),
 9389                                                PlatformStyle::platform(),
 9390                                                Some(Color::Default),
 9391                                                Some(IconSize::XSmall.rems().into()),
 9392                                                false,
 9393                                            )))
 9394                                        },
 9395                                    ),
 9396                            )
 9397                            .into_any(),
 9398                    );
 9399                }
 9400
 9401                self.render_edit_prediction_cursor_popover_preview(
 9402                    prediction,
 9403                    cursor_point,
 9404                    style,
 9405                    cx,
 9406                )?
 9407            }
 9408
 9409            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9410                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9411                    stale_completion,
 9412                    cursor_point,
 9413                    style,
 9414                    cx,
 9415                )?,
 9416
 9417                None => pending_completion_container(provider_icon)
 9418                    .child(Label::new("...").size(LabelSize::Small)),
 9419            },
 9420
 9421            None => pending_completion_container(provider_icon)
 9422                .child(Label::new("...").size(LabelSize::Small)),
 9423        };
 9424
 9425        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9426            completion
 9427                .with_animation(
 9428                    "loading-completion",
 9429                    Animation::new(Duration::from_secs(2))
 9430                        .repeat()
 9431                        .with_easing(pulsating_between(0.4, 0.8)),
 9432                    |label, delta| label.opacity(delta),
 9433                )
 9434                .into_any_element()
 9435        } else {
 9436            completion.into_any_element()
 9437        };
 9438
 9439        let has_completion = self.active_edit_prediction.is_some();
 9440
 9441        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9442        Some(
 9443            h_flex()
 9444                .min_w(min_width)
 9445                .max_w(max_width)
 9446                .flex_1()
 9447                .elevation_2(cx)
 9448                .border_color(cx.theme().colors().border)
 9449                .child(
 9450                    div()
 9451                        .flex_1()
 9452                        .py_1()
 9453                        .px_2()
 9454                        .overflow_hidden()
 9455                        .child(completion),
 9456                )
 9457                .when_some(accept_keystroke, |el, accept_keystroke| {
 9458                    if !accept_keystroke.modifiers().modified() {
 9459                        return el;
 9460                    }
 9461
 9462                    el.child(
 9463                        h_flex()
 9464                            .h_full()
 9465                            .border_l_1()
 9466                            .rounded_r_lg()
 9467                            .border_color(cx.theme().colors().border)
 9468                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9469                            .gap_1()
 9470                            .py_1()
 9471                            .px_2()
 9472                            .child(
 9473                                h_flex()
 9474                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9475                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9476                                    .child(h_flex().children(ui::render_modifiers(
 9477                                        accept_keystroke.modifiers(),
 9478                                        PlatformStyle::platform(),
 9479                                        Some(if !has_completion {
 9480                                            Color::Muted
 9481                                        } else {
 9482                                            Color::Default
 9483                                        }),
 9484                                        None,
 9485                                        false,
 9486                                    ))),
 9487                            )
 9488                            .child(Label::new("Preview").into_any_element())
 9489                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9490                    )
 9491                })
 9492                .into_any(),
 9493        )
 9494    }
 9495
 9496    fn render_edit_prediction_cursor_popover_preview(
 9497        &self,
 9498        completion: &EditPredictionState,
 9499        cursor_point: Point,
 9500        style: &EditorStyle,
 9501        cx: &mut Context<Editor>,
 9502    ) -> Option<Div> {
 9503        use text::ToPoint as _;
 9504
 9505        fn render_relative_row_jump(
 9506            prefix: impl Into<String>,
 9507            current_row: u32,
 9508            target_row: u32,
 9509        ) -> Div {
 9510            let (row_diff, arrow) = if target_row < current_row {
 9511                (current_row - target_row, IconName::ArrowUp)
 9512            } else {
 9513                (target_row - current_row, IconName::ArrowDown)
 9514            };
 9515
 9516            h_flex()
 9517                .child(
 9518                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9519                        .color(Color::Muted)
 9520                        .size(LabelSize::Small),
 9521                )
 9522                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9523        }
 9524
 9525        let supports_jump = self
 9526            .edit_prediction_provider
 9527            .as_ref()
 9528            .map(|provider| provider.provider.supports_jump_to_edit())
 9529            .unwrap_or(true);
 9530
 9531        match &completion.completion {
 9532            EditPrediction::MoveWithin {
 9533                target, snapshot, ..
 9534            } => {
 9535                if !supports_jump {
 9536                    return None;
 9537                }
 9538
 9539                Some(
 9540                    h_flex()
 9541                        .px_2()
 9542                        .gap_2()
 9543                        .flex_1()
 9544                        .child(
 9545                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9546                                Icon::new(IconName::ZedPredictDown)
 9547                            } else {
 9548                                Icon::new(IconName::ZedPredictUp)
 9549                            },
 9550                        )
 9551                        .child(Label::new("Jump to Edit")),
 9552                )
 9553            }
 9554            EditPrediction::MoveOutside { snapshot, .. } => {
 9555                let file_name = snapshot
 9556                    .file()
 9557                    .map(|file| file.file_name(cx))
 9558                    .unwrap_or("untitled");
 9559                Some(
 9560                    h_flex()
 9561                        .px_2()
 9562                        .gap_2()
 9563                        .flex_1()
 9564                        .child(Icon::new(IconName::ZedPredict))
 9565                        .child(Label::new(format!("Jump to {file_name}"))),
 9566                )
 9567            }
 9568            EditPrediction::Edit {
 9569                edits,
 9570                edit_preview,
 9571                snapshot,
 9572                display_mode: _,
 9573            } => {
 9574                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9575
 9576                let (highlighted_edits, has_more_lines) =
 9577                    if let Some(edit_preview) = edit_preview.as_ref() {
 9578                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9579                            .first_line_preview()
 9580                    } else {
 9581                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9582                    };
 9583
 9584                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9585                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9586
 9587                let preview = h_flex()
 9588                    .gap_1()
 9589                    .min_w_16()
 9590                    .child(styled_text)
 9591                    .when(has_more_lines, |parent| parent.child(""));
 9592
 9593                let left = if supports_jump && first_edit_row != cursor_point.row {
 9594                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9595                        .into_any_element()
 9596                } else {
 9597                    let icon_name =
 9598                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9599                    Icon::new(icon_name).into_any_element()
 9600                };
 9601
 9602                Some(
 9603                    h_flex()
 9604                        .h_full()
 9605                        .flex_1()
 9606                        .gap_2()
 9607                        .pr_1()
 9608                        .overflow_x_hidden()
 9609                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9610                        .child(left)
 9611                        .child(preview),
 9612                )
 9613            }
 9614        }
 9615    }
 9616
 9617    pub fn render_context_menu(
 9618        &self,
 9619        style: &EditorStyle,
 9620        max_height_in_lines: u32,
 9621        window: &mut Window,
 9622        cx: &mut Context<Editor>,
 9623    ) -> Option<AnyElement> {
 9624        let menu = self.context_menu.borrow();
 9625        let menu = menu.as_ref()?;
 9626        if !menu.visible() {
 9627            return None;
 9628        };
 9629        Some(menu.render(style, max_height_in_lines, window, cx))
 9630    }
 9631
 9632    fn render_context_menu_aside(
 9633        &mut self,
 9634        max_size: Size<Pixels>,
 9635        window: &mut Window,
 9636        cx: &mut Context<Editor>,
 9637    ) -> Option<AnyElement> {
 9638        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9639            if menu.visible() {
 9640                menu.render_aside(max_size, window, cx)
 9641            } else {
 9642                None
 9643            }
 9644        })
 9645    }
 9646
 9647    fn hide_context_menu(
 9648        &mut self,
 9649        window: &mut Window,
 9650        cx: &mut Context<Self>,
 9651    ) -> Option<CodeContextMenu> {
 9652        cx.notify();
 9653        self.completion_tasks.clear();
 9654        let context_menu = self.context_menu.borrow_mut().take();
 9655        self.stale_edit_prediction_in_menu.take();
 9656        self.update_visible_edit_prediction(window, cx);
 9657        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9658            && let Some(completion_provider) = &self.completion_provider
 9659        {
 9660            completion_provider.selection_changed(None, window, cx);
 9661        }
 9662        context_menu
 9663    }
 9664
 9665    fn show_snippet_choices(
 9666        &mut self,
 9667        choices: &Vec<String>,
 9668        selection: Range<Anchor>,
 9669        cx: &mut Context<Self>,
 9670    ) {
 9671        let Some((_, buffer, _)) = self
 9672            .buffer()
 9673            .read(cx)
 9674            .excerpt_containing(selection.start, cx)
 9675        else {
 9676            return;
 9677        };
 9678        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9679        else {
 9680            return;
 9681        };
 9682        if buffer != end_buffer {
 9683            log::error!("expected anchor range to have matching buffer IDs");
 9684            return;
 9685        }
 9686
 9687        let id = post_inc(&mut self.next_completion_id);
 9688        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9689        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9690            CompletionsMenu::new_snippet_choices(
 9691                id,
 9692                true,
 9693                choices,
 9694                selection,
 9695                buffer,
 9696                snippet_sort_order,
 9697            ),
 9698        ));
 9699    }
 9700
 9701    pub fn insert_snippet(
 9702        &mut self,
 9703        insertion_ranges: &[Range<usize>],
 9704        snippet: Snippet,
 9705        window: &mut Window,
 9706        cx: &mut Context<Self>,
 9707    ) -> Result<()> {
 9708        struct Tabstop<T> {
 9709            is_end_tabstop: bool,
 9710            ranges: Vec<Range<T>>,
 9711            choices: Option<Vec<String>>,
 9712        }
 9713
 9714        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9715            let snippet_text: Arc<str> = snippet.text.clone().into();
 9716            let edits = insertion_ranges
 9717                .iter()
 9718                .cloned()
 9719                .map(|range| (range, snippet_text.clone()));
 9720            let autoindent_mode = AutoindentMode::Block {
 9721                original_indent_columns: Vec::new(),
 9722            };
 9723            buffer.edit(edits, Some(autoindent_mode), cx);
 9724
 9725            let snapshot = &*buffer.read(cx);
 9726            let snippet = &snippet;
 9727            snippet
 9728                .tabstops
 9729                .iter()
 9730                .map(|tabstop| {
 9731                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9732                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9733                    });
 9734                    let mut tabstop_ranges = tabstop
 9735                        .ranges
 9736                        .iter()
 9737                        .flat_map(|tabstop_range| {
 9738                            let mut delta = 0_isize;
 9739                            insertion_ranges.iter().map(move |insertion_range| {
 9740                                let insertion_start = insertion_range.start as isize + delta;
 9741                                delta +=
 9742                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9743
 9744                                let start = ((insertion_start + tabstop_range.start) as usize)
 9745                                    .min(snapshot.len());
 9746                                let end = ((insertion_start + tabstop_range.end) as usize)
 9747                                    .min(snapshot.len());
 9748                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9749                            })
 9750                        })
 9751                        .collect::<Vec<_>>();
 9752                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9753
 9754                    Tabstop {
 9755                        is_end_tabstop,
 9756                        ranges: tabstop_ranges,
 9757                        choices: tabstop.choices.clone(),
 9758                    }
 9759                })
 9760                .collect::<Vec<_>>()
 9761        });
 9762        if let Some(tabstop) = tabstops.first() {
 9763            self.change_selections(Default::default(), window, cx, |s| {
 9764                // Reverse order so that the first range is the newest created selection.
 9765                // Completions will use it and autoscroll will prioritize it.
 9766                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9767            });
 9768
 9769            if let Some(choices) = &tabstop.choices
 9770                && let Some(selection) = tabstop.ranges.first()
 9771            {
 9772                self.show_snippet_choices(choices, selection.clone(), cx)
 9773            }
 9774
 9775            // If we're already at the last tabstop and it's at the end of the snippet,
 9776            // we're done, we don't need to keep the state around.
 9777            if !tabstop.is_end_tabstop {
 9778                let choices = tabstops
 9779                    .iter()
 9780                    .map(|tabstop| tabstop.choices.clone())
 9781                    .collect();
 9782
 9783                let ranges = tabstops
 9784                    .into_iter()
 9785                    .map(|tabstop| tabstop.ranges)
 9786                    .collect::<Vec<_>>();
 9787
 9788                self.snippet_stack.push(SnippetState {
 9789                    active_index: 0,
 9790                    ranges,
 9791                    choices,
 9792                });
 9793            }
 9794
 9795            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9796            if self.autoclose_regions.is_empty() {
 9797                let snapshot = self.buffer.read(cx).snapshot(cx);
 9798                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
 9799                    let selection_head = selection.head();
 9800                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9801                        continue;
 9802                    };
 9803
 9804                    let mut bracket_pair = None;
 9805                    let max_lookup_length = scope
 9806                        .brackets()
 9807                        .map(|(pair, _)| {
 9808                            pair.start
 9809                                .as_str()
 9810                                .chars()
 9811                                .count()
 9812                                .max(pair.end.as_str().chars().count())
 9813                        })
 9814                        .max();
 9815                    if let Some(max_lookup_length) = max_lookup_length {
 9816                        let next_text = snapshot
 9817                            .chars_at(selection_head)
 9818                            .take(max_lookup_length)
 9819                            .collect::<String>();
 9820                        let prev_text = snapshot
 9821                            .reversed_chars_at(selection_head)
 9822                            .take(max_lookup_length)
 9823                            .collect::<String>();
 9824
 9825                        for (pair, enabled) in scope.brackets() {
 9826                            if enabled
 9827                                && pair.close
 9828                                && prev_text.starts_with(pair.start.as_str())
 9829                                && next_text.starts_with(pair.end.as_str())
 9830                            {
 9831                                bracket_pair = Some(pair.clone());
 9832                                break;
 9833                            }
 9834                        }
 9835                    }
 9836
 9837                    if let Some(pair) = bracket_pair {
 9838                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9839                        let autoclose_enabled =
 9840                            self.use_autoclose && snapshot_settings.use_autoclose;
 9841                        if autoclose_enabled {
 9842                            let start = snapshot.anchor_after(selection_head);
 9843                            let end = snapshot.anchor_after(selection_head);
 9844                            self.autoclose_regions.push(AutocloseRegion {
 9845                                selection_id: selection.id,
 9846                                range: start..end,
 9847                                pair,
 9848                            });
 9849                        }
 9850                    }
 9851                }
 9852            }
 9853        }
 9854        Ok(())
 9855    }
 9856
 9857    pub fn move_to_next_snippet_tabstop(
 9858        &mut self,
 9859        window: &mut Window,
 9860        cx: &mut Context<Self>,
 9861    ) -> bool {
 9862        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9863    }
 9864
 9865    pub fn move_to_prev_snippet_tabstop(
 9866        &mut self,
 9867        window: &mut Window,
 9868        cx: &mut Context<Self>,
 9869    ) -> bool {
 9870        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9871    }
 9872
 9873    pub fn move_to_snippet_tabstop(
 9874        &mut self,
 9875        bias: Bias,
 9876        window: &mut Window,
 9877        cx: &mut Context<Self>,
 9878    ) -> bool {
 9879        if let Some(mut snippet) = self.snippet_stack.pop() {
 9880            match bias {
 9881                Bias::Left => {
 9882                    if snippet.active_index > 0 {
 9883                        snippet.active_index -= 1;
 9884                    } else {
 9885                        self.snippet_stack.push(snippet);
 9886                        return false;
 9887                    }
 9888                }
 9889                Bias::Right => {
 9890                    if snippet.active_index + 1 < snippet.ranges.len() {
 9891                        snippet.active_index += 1;
 9892                    } else {
 9893                        self.snippet_stack.push(snippet);
 9894                        return false;
 9895                    }
 9896                }
 9897            }
 9898            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9899                self.change_selections(Default::default(), window, cx, |s| {
 9900                    // Reverse order so that the first range is the newest created selection.
 9901                    // Completions will use it and autoscroll will prioritize it.
 9902                    s.select_ranges(current_ranges.iter().rev().cloned())
 9903                });
 9904
 9905                if let Some(choices) = &snippet.choices[snippet.active_index]
 9906                    && let Some(selection) = current_ranges.first()
 9907                {
 9908                    self.show_snippet_choices(choices, selection.clone(), cx);
 9909                }
 9910
 9911                // If snippet state is not at the last tabstop, push it back on the stack
 9912                if snippet.active_index + 1 < snippet.ranges.len() {
 9913                    self.snippet_stack.push(snippet);
 9914                }
 9915                return true;
 9916            }
 9917        }
 9918
 9919        false
 9920    }
 9921
 9922    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9923        self.transact(window, cx, |this, window, cx| {
 9924            this.select_all(&SelectAll, window, cx);
 9925            this.insert("", window, cx);
 9926        });
 9927    }
 9928
 9929    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9930        if self.read_only(cx) {
 9931            return;
 9932        }
 9933        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9934        self.transact(window, cx, |this, window, cx| {
 9935            this.select_autoclose_pair(window, cx);
 9936
 9937            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9938
 9939            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9940            if !this.linked_edit_ranges.is_empty() {
 9941                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
 9942                let snapshot = this.buffer.read(cx).snapshot(cx);
 9943
 9944                for selection in selections.iter() {
 9945                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9946                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9947                    if selection_start.buffer_id != selection_end.buffer_id {
 9948                        continue;
 9949                    }
 9950                    if let Some(ranges) =
 9951                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9952                    {
 9953                        for (buffer, entries) in ranges {
 9954                            linked_ranges.entry(buffer).or_default().extend(entries);
 9955                        }
 9956                    }
 9957                }
 9958            }
 9959
 9960            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
 9961            for selection in &mut selections {
 9962                if selection.is_empty() {
 9963                    let old_head = selection.head();
 9964                    let mut new_head =
 9965                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9966                            .to_point(&display_map);
 9967                    if let Some((buffer, line_buffer_range)) = display_map
 9968                        .buffer_snapshot()
 9969                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9970                    {
 9971                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9972                        let indent_len = match indent_size.kind {
 9973                            IndentKind::Space => {
 9974                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9975                            }
 9976                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9977                        };
 9978                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9979                            let indent_len = indent_len.get();
 9980                            new_head = cmp::min(
 9981                                new_head,
 9982                                MultiBufferPoint::new(
 9983                                    old_head.row,
 9984                                    ((old_head.column - 1) / indent_len) * indent_len,
 9985                                ),
 9986                            );
 9987                        }
 9988                    }
 9989
 9990                    selection.set_head(new_head, SelectionGoal::None);
 9991                }
 9992            }
 9993
 9994            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9995            this.insert("", window, cx);
 9996            let empty_str: Arc<str> = Arc::from("");
 9997            for (buffer, edits) in linked_ranges {
 9998                let snapshot = buffer.read(cx).snapshot();
 9999                use text::ToPoint as TP;
10000
10001                let edits = edits
10002                    .into_iter()
10003                    .map(|range| {
10004                        let end_point = TP::to_point(&range.end, &snapshot);
10005                        let mut start_point = TP::to_point(&range.start, &snapshot);
10006
10007                        if end_point == start_point {
10008                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10009                                .saturating_sub(1);
10010                            start_point =
10011                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10012                        };
10013
10014                        (start_point..end_point, empty_str.clone())
10015                    })
10016                    .sorted_by_key(|(range, _)| range.start)
10017                    .collect::<Vec<_>>();
10018                buffer.update(cx, |this, cx| {
10019                    this.edit(edits, None, cx);
10020                })
10021            }
10022            this.refresh_edit_prediction(true, false, window, cx);
10023            refresh_linked_ranges(this, window, cx);
10024        });
10025    }
10026
10027    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10028        if self.read_only(cx) {
10029            return;
10030        }
10031        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10032        self.transact(window, cx, |this, window, cx| {
10033            this.change_selections(Default::default(), window, cx, |s| {
10034                s.move_with(|map, selection| {
10035                    if selection.is_empty() {
10036                        let cursor = movement::right(map, selection.head());
10037                        selection.end = cursor;
10038                        selection.reversed = true;
10039                        selection.goal = SelectionGoal::None;
10040                    }
10041                })
10042            });
10043            this.insert("", window, cx);
10044            this.refresh_edit_prediction(true, false, window, cx);
10045        });
10046    }
10047
10048    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10049        if self.mode.is_single_line() {
10050            cx.propagate();
10051            return;
10052        }
10053
10054        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10055        if self.move_to_prev_snippet_tabstop(window, cx) {
10056            return;
10057        }
10058        self.outdent(&Outdent, window, cx);
10059    }
10060
10061    pub fn next_snippet_tabstop(
10062        &mut self,
10063        _: &NextSnippetTabstop,
10064        window: &mut Window,
10065        cx: &mut Context<Self>,
10066    ) {
10067        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10068            cx.propagate();
10069            return;
10070        }
10071
10072        if self.move_to_next_snippet_tabstop(window, cx) {
10073            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10074            return;
10075        }
10076        cx.propagate();
10077    }
10078
10079    pub fn previous_snippet_tabstop(
10080        &mut self,
10081        _: &PreviousSnippetTabstop,
10082        window: &mut Window,
10083        cx: &mut Context<Self>,
10084    ) {
10085        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10086            cx.propagate();
10087            return;
10088        }
10089
10090        if self.move_to_prev_snippet_tabstop(window, cx) {
10091            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10092            return;
10093        }
10094        cx.propagate();
10095    }
10096
10097    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10098        if self.mode.is_single_line() {
10099            cx.propagate();
10100            return;
10101        }
10102
10103        if self.move_to_next_snippet_tabstop(window, cx) {
10104            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10105            return;
10106        }
10107        if self.read_only(cx) {
10108            return;
10109        }
10110        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10111        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10112        let buffer = self.buffer.read(cx);
10113        let snapshot = buffer.snapshot(cx);
10114        let rows_iter = selections.iter().map(|s| s.head().row);
10115        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10116
10117        let has_some_cursor_in_whitespace = selections
10118            .iter()
10119            .filter(|selection| selection.is_empty())
10120            .any(|selection| {
10121                let cursor = selection.head();
10122                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10123                cursor.column < current_indent.len
10124            });
10125
10126        let mut edits = Vec::new();
10127        let mut prev_edited_row = 0;
10128        let mut row_delta = 0;
10129        for selection in &mut selections {
10130            if selection.start.row != prev_edited_row {
10131                row_delta = 0;
10132            }
10133            prev_edited_row = selection.end.row;
10134
10135            // If the selection is non-empty, then increase the indentation of the selected lines.
10136            if !selection.is_empty() {
10137                row_delta =
10138                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10139                continue;
10140            }
10141
10142            let cursor = selection.head();
10143            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10144            if let Some(suggested_indent) =
10145                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10146            {
10147                // Don't do anything if already at suggested indent
10148                // and there is any other cursor which is not
10149                if has_some_cursor_in_whitespace
10150                    && cursor.column == current_indent.len
10151                    && current_indent.len == suggested_indent.len
10152                {
10153                    continue;
10154                }
10155
10156                // Adjust line and move cursor to suggested indent
10157                // if cursor is not at suggested indent
10158                if cursor.column < suggested_indent.len
10159                    && cursor.column <= current_indent.len
10160                    && current_indent.len <= suggested_indent.len
10161                {
10162                    selection.start = Point::new(cursor.row, suggested_indent.len);
10163                    selection.end = selection.start;
10164                    if row_delta == 0 {
10165                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10166                            cursor.row,
10167                            current_indent,
10168                            suggested_indent,
10169                        ));
10170                        row_delta = suggested_indent.len - current_indent.len;
10171                    }
10172                    continue;
10173                }
10174
10175                // If current indent is more than suggested indent
10176                // only move cursor to current indent and skip indent
10177                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10178                    selection.start = Point::new(cursor.row, current_indent.len);
10179                    selection.end = selection.start;
10180                    continue;
10181                }
10182            }
10183
10184            // Otherwise, insert a hard or soft tab.
10185            let settings = buffer.language_settings_at(cursor, cx);
10186            let tab_size = if settings.hard_tabs {
10187                IndentSize::tab()
10188            } else {
10189                let tab_size = settings.tab_size.get();
10190                let indent_remainder = snapshot
10191                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10192                    .flat_map(str::chars)
10193                    .fold(row_delta % tab_size, |counter: u32, c| {
10194                        if c == '\t' {
10195                            0
10196                        } else {
10197                            (counter + 1) % tab_size
10198                        }
10199                    });
10200
10201                let chars_to_next_tab_stop = tab_size - indent_remainder;
10202                IndentSize::spaces(chars_to_next_tab_stop)
10203            };
10204            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10205            selection.end = selection.start;
10206            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10207            row_delta += tab_size.len;
10208        }
10209
10210        self.transact(window, cx, |this, window, cx| {
10211            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10212            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10213            this.refresh_edit_prediction(true, false, window, cx);
10214        });
10215    }
10216
10217    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10218        if self.read_only(cx) {
10219            return;
10220        }
10221        if self.mode.is_single_line() {
10222            cx.propagate();
10223            return;
10224        }
10225
10226        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10227        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10228        let mut prev_edited_row = 0;
10229        let mut row_delta = 0;
10230        let mut edits = Vec::new();
10231        let buffer = self.buffer.read(cx);
10232        let snapshot = buffer.snapshot(cx);
10233        for selection in &mut selections {
10234            if selection.start.row != prev_edited_row {
10235                row_delta = 0;
10236            }
10237            prev_edited_row = selection.end.row;
10238
10239            row_delta =
10240                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10241        }
10242
10243        self.transact(window, cx, |this, window, cx| {
10244            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10245            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10246        });
10247    }
10248
10249    fn indent_selection(
10250        buffer: &MultiBuffer,
10251        snapshot: &MultiBufferSnapshot,
10252        selection: &mut Selection<Point>,
10253        edits: &mut Vec<(Range<Point>, String)>,
10254        delta_for_start_row: u32,
10255        cx: &App,
10256    ) -> u32 {
10257        let settings = buffer.language_settings_at(selection.start, cx);
10258        let tab_size = settings.tab_size.get();
10259        let indent_kind = if settings.hard_tabs {
10260            IndentKind::Tab
10261        } else {
10262            IndentKind::Space
10263        };
10264        let mut start_row = selection.start.row;
10265        let mut end_row = selection.end.row + 1;
10266
10267        // If a selection ends at the beginning of a line, don't indent
10268        // that last line.
10269        if selection.end.column == 0 && selection.end.row > selection.start.row {
10270            end_row -= 1;
10271        }
10272
10273        // Avoid re-indenting a row that has already been indented by a
10274        // previous selection, but still update this selection's column
10275        // to reflect that indentation.
10276        if delta_for_start_row > 0 {
10277            start_row += 1;
10278            selection.start.column += delta_for_start_row;
10279            if selection.end.row == selection.start.row {
10280                selection.end.column += delta_for_start_row;
10281            }
10282        }
10283
10284        let mut delta_for_end_row = 0;
10285        let has_multiple_rows = start_row + 1 != end_row;
10286        for row in start_row..end_row {
10287            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10288            let indent_delta = match (current_indent.kind, indent_kind) {
10289                (IndentKind::Space, IndentKind::Space) => {
10290                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10291                    IndentSize::spaces(columns_to_next_tab_stop)
10292                }
10293                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10294                (_, IndentKind::Tab) => IndentSize::tab(),
10295            };
10296
10297            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10298                0
10299            } else {
10300                selection.start.column
10301            };
10302            let row_start = Point::new(row, start);
10303            edits.push((
10304                row_start..row_start,
10305                indent_delta.chars().collect::<String>(),
10306            ));
10307
10308            // Update this selection's endpoints to reflect the indentation.
10309            if row == selection.start.row {
10310                selection.start.column += indent_delta.len;
10311            }
10312            if row == selection.end.row {
10313                selection.end.column += indent_delta.len;
10314                delta_for_end_row = indent_delta.len;
10315            }
10316        }
10317
10318        if selection.start.row == selection.end.row {
10319            delta_for_start_row + delta_for_end_row
10320        } else {
10321            delta_for_end_row
10322        }
10323    }
10324
10325    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10326        if self.read_only(cx) {
10327            return;
10328        }
10329        if self.mode.is_single_line() {
10330            cx.propagate();
10331            return;
10332        }
10333
10334        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10335        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10336        let selections = self.selections.all::<Point>(&display_map);
10337        let mut deletion_ranges = Vec::new();
10338        let mut last_outdent = None;
10339        {
10340            let buffer = self.buffer.read(cx);
10341            let snapshot = buffer.snapshot(cx);
10342            for selection in &selections {
10343                let settings = buffer.language_settings_at(selection.start, cx);
10344                let tab_size = settings.tab_size.get();
10345                let mut rows = selection.spanned_rows(false, &display_map);
10346
10347                // Avoid re-outdenting a row that has already been outdented by a
10348                // previous selection.
10349                if let Some(last_row) = last_outdent
10350                    && last_row == rows.start
10351                {
10352                    rows.start = rows.start.next_row();
10353                }
10354                let has_multiple_rows = rows.len() > 1;
10355                for row in rows.iter_rows() {
10356                    let indent_size = snapshot.indent_size_for_line(row);
10357                    if indent_size.len > 0 {
10358                        let deletion_len = match indent_size.kind {
10359                            IndentKind::Space => {
10360                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10361                                if columns_to_prev_tab_stop == 0 {
10362                                    tab_size
10363                                } else {
10364                                    columns_to_prev_tab_stop
10365                                }
10366                            }
10367                            IndentKind::Tab => 1,
10368                        };
10369                        let start = if has_multiple_rows
10370                            || deletion_len > selection.start.column
10371                            || indent_size.len < selection.start.column
10372                        {
10373                            0
10374                        } else {
10375                            selection.start.column - deletion_len
10376                        };
10377                        deletion_ranges.push(
10378                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10379                        );
10380                        last_outdent = Some(row);
10381                    }
10382                }
10383            }
10384        }
10385
10386        self.transact(window, cx, |this, window, cx| {
10387            this.buffer.update(cx, |buffer, cx| {
10388                let empty_str: Arc<str> = Arc::default();
10389                buffer.edit(
10390                    deletion_ranges
10391                        .into_iter()
10392                        .map(|range| (range, empty_str.clone())),
10393                    None,
10394                    cx,
10395                );
10396            });
10397            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10398            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10399        });
10400    }
10401
10402    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10403        if self.read_only(cx) {
10404            return;
10405        }
10406        if self.mode.is_single_line() {
10407            cx.propagate();
10408            return;
10409        }
10410
10411        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10412        let selections = self
10413            .selections
10414            .all::<usize>(&self.display_snapshot(cx))
10415            .into_iter()
10416            .map(|s| s.range());
10417
10418        self.transact(window, cx, |this, window, cx| {
10419            this.buffer.update(cx, |buffer, cx| {
10420                buffer.autoindent_ranges(selections, cx);
10421            });
10422            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10423            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10424        });
10425    }
10426
10427    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10428        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10429        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10430        let selections = self.selections.all::<Point>(&display_map);
10431
10432        let mut new_cursors = Vec::new();
10433        let mut edit_ranges = Vec::new();
10434        let mut selections = selections.iter().peekable();
10435        while let Some(selection) = selections.next() {
10436            let mut rows = selection.spanned_rows(false, &display_map);
10437
10438            // Accumulate contiguous regions of rows that we want to delete.
10439            while let Some(next_selection) = selections.peek() {
10440                let next_rows = next_selection.spanned_rows(false, &display_map);
10441                if next_rows.start <= rows.end {
10442                    rows.end = next_rows.end;
10443                    selections.next().unwrap();
10444                } else {
10445                    break;
10446                }
10447            }
10448
10449            let buffer = display_map.buffer_snapshot();
10450            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10451            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10452                // If there's a line after the range, delete the \n from the end of the row range
10453                (
10454                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10455                    rows.end,
10456                )
10457            } else {
10458                // If there isn't a line after the range, delete the \n from the line before the
10459                // start of the row range
10460                edit_start = edit_start.saturating_sub(1);
10461                (buffer.len(), rows.start.previous_row())
10462            };
10463
10464            let text_layout_details = self.text_layout_details(window);
10465            let x = display_map.x_for_display_point(
10466                selection.head().to_display_point(&display_map),
10467                &text_layout_details,
10468            );
10469            let row = Point::new(target_row.0, 0)
10470                .to_display_point(&display_map)
10471                .row();
10472            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10473
10474            new_cursors.push((
10475                selection.id,
10476                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10477                SelectionGoal::None,
10478            ));
10479            edit_ranges.push(edit_start..edit_end);
10480        }
10481
10482        self.transact(window, cx, |this, window, cx| {
10483            let buffer = this.buffer.update(cx, |buffer, cx| {
10484                let empty_str: Arc<str> = Arc::default();
10485                buffer.edit(
10486                    edit_ranges
10487                        .into_iter()
10488                        .map(|range| (range, empty_str.clone())),
10489                    None,
10490                    cx,
10491                );
10492                buffer.snapshot(cx)
10493            });
10494            let new_selections = new_cursors
10495                .into_iter()
10496                .map(|(id, cursor, goal)| {
10497                    let cursor = cursor.to_point(&buffer);
10498                    Selection {
10499                        id,
10500                        start: cursor,
10501                        end: cursor,
10502                        reversed: false,
10503                        goal,
10504                    }
10505                })
10506                .collect();
10507
10508            this.change_selections(Default::default(), window, cx, |s| {
10509                s.select(new_selections);
10510            });
10511        });
10512    }
10513
10514    pub fn join_lines_impl(
10515        &mut self,
10516        insert_whitespace: bool,
10517        window: &mut Window,
10518        cx: &mut Context<Self>,
10519    ) {
10520        if self.read_only(cx) {
10521            return;
10522        }
10523        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10524        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10525            let start = MultiBufferRow(selection.start.row);
10526            // Treat single line selections as if they include the next line. Otherwise this action
10527            // would do nothing for single line selections individual cursors.
10528            let end = if selection.start.row == selection.end.row {
10529                MultiBufferRow(selection.start.row + 1)
10530            } else {
10531                MultiBufferRow(selection.end.row)
10532            };
10533
10534            if let Some(last_row_range) = row_ranges.last_mut()
10535                && start <= last_row_range.end
10536            {
10537                last_row_range.end = end;
10538                continue;
10539            }
10540            row_ranges.push(start..end);
10541        }
10542
10543        let snapshot = self.buffer.read(cx).snapshot(cx);
10544        let mut cursor_positions = Vec::new();
10545        for row_range in &row_ranges {
10546            let anchor = snapshot.anchor_before(Point::new(
10547                row_range.end.previous_row().0,
10548                snapshot.line_len(row_range.end.previous_row()),
10549            ));
10550            cursor_positions.push(anchor..anchor);
10551        }
10552
10553        self.transact(window, cx, |this, window, cx| {
10554            for row_range in row_ranges.into_iter().rev() {
10555                for row in row_range.iter_rows().rev() {
10556                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10557                    let next_line_row = row.next_row();
10558                    let indent = snapshot.indent_size_for_line(next_line_row);
10559                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10560
10561                    let replace =
10562                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10563                            " "
10564                        } else {
10565                            ""
10566                        };
10567
10568                    this.buffer.update(cx, |buffer, cx| {
10569                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10570                    });
10571                }
10572            }
10573
10574            this.change_selections(Default::default(), window, cx, |s| {
10575                s.select_anchor_ranges(cursor_positions)
10576            });
10577        });
10578    }
10579
10580    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10581        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10582        self.join_lines_impl(true, window, cx);
10583    }
10584
10585    pub fn sort_lines_case_sensitive(
10586        &mut self,
10587        _: &SortLinesCaseSensitive,
10588        window: &mut Window,
10589        cx: &mut Context<Self>,
10590    ) {
10591        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10592    }
10593
10594    pub fn sort_lines_by_length(
10595        &mut self,
10596        _: &SortLinesByLength,
10597        window: &mut Window,
10598        cx: &mut Context<Self>,
10599    ) {
10600        self.manipulate_immutable_lines(window, cx, |lines| {
10601            lines.sort_by_key(|&line| line.chars().count())
10602        })
10603    }
10604
10605    pub fn sort_lines_case_insensitive(
10606        &mut self,
10607        _: &SortLinesCaseInsensitive,
10608        window: &mut Window,
10609        cx: &mut Context<Self>,
10610    ) {
10611        self.manipulate_immutable_lines(window, cx, |lines| {
10612            lines.sort_by_key(|line| line.to_lowercase())
10613        })
10614    }
10615
10616    pub fn unique_lines_case_insensitive(
10617        &mut self,
10618        _: &UniqueLinesCaseInsensitive,
10619        window: &mut Window,
10620        cx: &mut Context<Self>,
10621    ) {
10622        self.manipulate_immutable_lines(window, cx, |lines| {
10623            let mut seen = HashSet::default();
10624            lines.retain(|line| seen.insert(line.to_lowercase()));
10625        })
10626    }
10627
10628    pub fn unique_lines_case_sensitive(
10629        &mut self,
10630        _: &UniqueLinesCaseSensitive,
10631        window: &mut Window,
10632        cx: &mut Context<Self>,
10633    ) {
10634        self.manipulate_immutable_lines(window, cx, |lines| {
10635            let mut seen = HashSet::default();
10636            lines.retain(|line| seen.insert(*line));
10637        })
10638    }
10639
10640    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10641        let snapshot = self.buffer.read(cx).snapshot(cx);
10642        for selection in self.selections.disjoint_anchors_arc().iter() {
10643            if snapshot
10644                .language_at(selection.start)
10645                .and_then(|lang| lang.config().wrap_characters.as_ref())
10646                .is_some()
10647            {
10648                return true;
10649            }
10650        }
10651        false
10652    }
10653
10654    fn wrap_selections_in_tag(
10655        &mut self,
10656        _: &WrapSelectionsInTag,
10657        window: &mut Window,
10658        cx: &mut Context<Self>,
10659    ) {
10660        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10661
10662        let snapshot = self.buffer.read(cx).snapshot(cx);
10663
10664        let mut edits = Vec::new();
10665        let mut boundaries = Vec::new();
10666
10667        for selection in self
10668            .selections
10669            .all_adjusted(&self.display_snapshot(cx))
10670            .iter()
10671        {
10672            let Some(wrap_config) = snapshot
10673                .language_at(selection.start)
10674                .and_then(|lang| lang.config().wrap_characters.clone())
10675            else {
10676                continue;
10677            };
10678
10679            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10680            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10681
10682            let start_before = snapshot.anchor_before(selection.start);
10683            let end_after = snapshot.anchor_after(selection.end);
10684
10685            edits.push((start_before..start_before, open_tag));
10686            edits.push((end_after..end_after, close_tag));
10687
10688            boundaries.push((
10689                start_before,
10690                end_after,
10691                wrap_config.start_prefix.len(),
10692                wrap_config.end_suffix.len(),
10693            ));
10694        }
10695
10696        if edits.is_empty() {
10697            return;
10698        }
10699
10700        self.transact(window, cx, |this, window, cx| {
10701            let buffer = this.buffer.update(cx, |buffer, cx| {
10702                buffer.edit(edits, None, cx);
10703                buffer.snapshot(cx)
10704            });
10705
10706            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10707            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10708                boundaries.into_iter()
10709            {
10710                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10711                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10712                new_selections.push(open_offset..open_offset);
10713                new_selections.push(close_offset..close_offset);
10714            }
10715
10716            this.change_selections(Default::default(), window, cx, |s| {
10717                s.select_ranges(new_selections);
10718            });
10719
10720            this.request_autoscroll(Autoscroll::fit(), cx);
10721        });
10722    }
10723
10724    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10725        let Some(project) = self.project.clone() else {
10726            return;
10727        };
10728        self.reload(project, window, cx)
10729            .detach_and_notify_err(window, cx);
10730    }
10731
10732    pub fn restore_file(
10733        &mut self,
10734        _: &::git::RestoreFile,
10735        window: &mut Window,
10736        cx: &mut Context<Self>,
10737    ) {
10738        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10739        let mut buffer_ids = HashSet::default();
10740        let snapshot = self.buffer().read(cx).snapshot(cx);
10741        for selection in self.selections.all::<usize>(&self.display_snapshot(cx)) {
10742            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10743        }
10744
10745        let buffer = self.buffer().read(cx);
10746        let ranges = buffer_ids
10747            .into_iter()
10748            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10749            .collect::<Vec<_>>();
10750
10751        self.restore_hunks_in_ranges(ranges, window, cx);
10752    }
10753
10754    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10755        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10756        let selections = self
10757            .selections
10758            .all(&self.display_snapshot(cx))
10759            .into_iter()
10760            .map(|s| s.range())
10761            .collect();
10762        self.restore_hunks_in_ranges(selections, window, cx);
10763    }
10764
10765    pub fn restore_hunks_in_ranges(
10766        &mut self,
10767        ranges: Vec<Range<Point>>,
10768        window: &mut Window,
10769        cx: &mut Context<Editor>,
10770    ) {
10771        let mut revert_changes = HashMap::default();
10772        let chunk_by = self
10773            .snapshot(window, cx)
10774            .hunks_for_ranges(ranges)
10775            .into_iter()
10776            .chunk_by(|hunk| hunk.buffer_id);
10777        for (buffer_id, hunks) in &chunk_by {
10778            let hunks = hunks.collect::<Vec<_>>();
10779            for hunk in &hunks {
10780                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10781            }
10782            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10783        }
10784        drop(chunk_by);
10785        if !revert_changes.is_empty() {
10786            self.transact(window, cx, |editor, window, cx| {
10787                editor.restore(revert_changes, window, cx);
10788            });
10789        }
10790    }
10791
10792    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
10793        if let Some(status) = self
10794            .addons
10795            .iter()
10796            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
10797        {
10798            return Some(status);
10799        }
10800        self.project
10801            .as_ref()?
10802            .read(cx)
10803            .status_for_buffer_id(buffer_id, cx)
10804    }
10805
10806    pub fn open_active_item_in_terminal(
10807        &mut self,
10808        _: &OpenInTerminal,
10809        window: &mut Window,
10810        cx: &mut Context<Self>,
10811    ) {
10812        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10813            let project_path = buffer.read(cx).project_path(cx)?;
10814            let project = self.project()?.read(cx);
10815            let entry = project.entry_for_path(&project_path, cx)?;
10816            let parent = match &entry.canonical_path {
10817                Some(canonical_path) => canonical_path.to_path_buf(),
10818                None => project.absolute_path(&project_path, cx)?,
10819            }
10820            .parent()?
10821            .to_path_buf();
10822            Some(parent)
10823        }) {
10824            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10825        }
10826    }
10827
10828    fn set_breakpoint_context_menu(
10829        &mut self,
10830        display_row: DisplayRow,
10831        position: Option<Anchor>,
10832        clicked_point: gpui::Point<Pixels>,
10833        window: &mut Window,
10834        cx: &mut Context<Self>,
10835    ) {
10836        let source = self
10837            .buffer
10838            .read(cx)
10839            .snapshot(cx)
10840            .anchor_before(Point::new(display_row.0, 0u32));
10841
10842        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10843
10844        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10845            self,
10846            source,
10847            clicked_point,
10848            context_menu,
10849            window,
10850            cx,
10851        );
10852    }
10853
10854    fn add_edit_breakpoint_block(
10855        &mut self,
10856        anchor: Anchor,
10857        breakpoint: &Breakpoint,
10858        edit_action: BreakpointPromptEditAction,
10859        window: &mut Window,
10860        cx: &mut Context<Self>,
10861    ) {
10862        let weak_editor = cx.weak_entity();
10863        let bp_prompt = cx.new(|cx| {
10864            BreakpointPromptEditor::new(
10865                weak_editor,
10866                anchor,
10867                breakpoint.clone(),
10868                edit_action,
10869                window,
10870                cx,
10871            )
10872        });
10873
10874        let height = bp_prompt.update(cx, |this, cx| {
10875            this.prompt
10876                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10877        });
10878        let cloned_prompt = bp_prompt.clone();
10879        let blocks = vec![BlockProperties {
10880            style: BlockStyle::Sticky,
10881            placement: BlockPlacement::Above(anchor),
10882            height: Some(height),
10883            render: Arc::new(move |cx| {
10884                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10885                cloned_prompt.clone().into_any_element()
10886            }),
10887            priority: 0,
10888        }];
10889
10890        let focus_handle = bp_prompt.focus_handle(cx);
10891        window.focus(&focus_handle);
10892
10893        let block_ids = self.insert_blocks(blocks, None, cx);
10894        bp_prompt.update(cx, |prompt, _| {
10895            prompt.add_block_ids(block_ids);
10896        });
10897    }
10898
10899    pub(crate) fn breakpoint_at_row(
10900        &self,
10901        row: u32,
10902        window: &mut Window,
10903        cx: &mut Context<Self>,
10904    ) -> Option<(Anchor, Breakpoint)> {
10905        let snapshot = self.snapshot(window, cx);
10906        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
10907
10908        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10909    }
10910
10911    pub(crate) fn breakpoint_at_anchor(
10912        &self,
10913        breakpoint_position: Anchor,
10914        snapshot: &EditorSnapshot,
10915        cx: &mut Context<Self>,
10916    ) -> Option<(Anchor, Breakpoint)> {
10917        let buffer = self
10918            .buffer
10919            .read(cx)
10920            .buffer_for_anchor(breakpoint_position, cx)?;
10921
10922        let enclosing_excerpt = breakpoint_position.excerpt_id;
10923        let buffer_snapshot = buffer.read(cx).snapshot();
10924
10925        let row = buffer_snapshot
10926            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10927            .row;
10928
10929        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
10930        let anchor_end = snapshot
10931            .buffer_snapshot()
10932            .anchor_after(Point::new(row, line_len));
10933
10934        self.breakpoint_store
10935            .as_ref()?
10936            .read_with(cx, |breakpoint_store, cx| {
10937                breakpoint_store
10938                    .breakpoints(
10939                        &buffer,
10940                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10941                        &buffer_snapshot,
10942                        cx,
10943                    )
10944                    .next()
10945                    .and_then(|(bp, _)| {
10946                        let breakpoint_row = buffer_snapshot
10947                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10948                            .row;
10949
10950                        if breakpoint_row == row {
10951                            snapshot
10952                                .buffer_snapshot()
10953                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10954                                .map(|position| (position, bp.bp.clone()))
10955                        } else {
10956                            None
10957                        }
10958                    })
10959            })
10960    }
10961
10962    pub fn edit_log_breakpoint(
10963        &mut self,
10964        _: &EditLogBreakpoint,
10965        window: &mut Window,
10966        cx: &mut Context<Self>,
10967    ) {
10968        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10969            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10970                message: None,
10971                state: BreakpointState::Enabled,
10972                condition: None,
10973                hit_condition: None,
10974            });
10975
10976            self.add_edit_breakpoint_block(
10977                anchor,
10978                &breakpoint,
10979                BreakpointPromptEditAction::Log,
10980                window,
10981                cx,
10982            );
10983        }
10984    }
10985
10986    fn breakpoints_at_cursors(
10987        &self,
10988        window: &mut Window,
10989        cx: &mut Context<Self>,
10990    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10991        let snapshot = self.snapshot(window, cx);
10992        let cursors = self
10993            .selections
10994            .disjoint_anchors_arc()
10995            .iter()
10996            .map(|selection| {
10997                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
10998
10999                let breakpoint_position = self
11000                    .breakpoint_at_row(cursor_position.row, window, cx)
11001                    .map(|bp| bp.0)
11002                    .unwrap_or_else(|| {
11003                        snapshot
11004                            .display_snapshot
11005                            .buffer_snapshot()
11006                            .anchor_after(Point::new(cursor_position.row, 0))
11007                    });
11008
11009                let breakpoint = self
11010                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11011                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11012
11013                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11014            })
11015            // 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.
11016            .collect::<HashMap<Anchor, _>>();
11017
11018        cursors.into_iter().collect()
11019    }
11020
11021    pub fn enable_breakpoint(
11022        &mut self,
11023        _: &crate::actions::EnableBreakpoint,
11024        window: &mut Window,
11025        cx: &mut Context<Self>,
11026    ) {
11027        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11028            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11029                continue;
11030            };
11031            self.edit_breakpoint_at_anchor(
11032                anchor,
11033                breakpoint,
11034                BreakpointEditAction::InvertState,
11035                cx,
11036            );
11037        }
11038    }
11039
11040    pub fn disable_breakpoint(
11041        &mut self,
11042        _: &crate::actions::DisableBreakpoint,
11043        window: &mut Window,
11044        cx: &mut Context<Self>,
11045    ) {
11046        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11047            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11048                continue;
11049            };
11050            self.edit_breakpoint_at_anchor(
11051                anchor,
11052                breakpoint,
11053                BreakpointEditAction::InvertState,
11054                cx,
11055            );
11056        }
11057    }
11058
11059    pub fn toggle_breakpoint(
11060        &mut self,
11061        _: &crate::actions::ToggleBreakpoint,
11062        window: &mut Window,
11063        cx: &mut Context<Self>,
11064    ) {
11065        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11066            if let Some(breakpoint) = breakpoint {
11067                self.edit_breakpoint_at_anchor(
11068                    anchor,
11069                    breakpoint,
11070                    BreakpointEditAction::Toggle,
11071                    cx,
11072                );
11073            } else {
11074                self.edit_breakpoint_at_anchor(
11075                    anchor,
11076                    Breakpoint::new_standard(),
11077                    BreakpointEditAction::Toggle,
11078                    cx,
11079                );
11080            }
11081        }
11082    }
11083
11084    pub fn edit_breakpoint_at_anchor(
11085        &mut self,
11086        breakpoint_position: Anchor,
11087        breakpoint: Breakpoint,
11088        edit_action: BreakpointEditAction,
11089        cx: &mut Context<Self>,
11090    ) {
11091        let Some(breakpoint_store) = &self.breakpoint_store else {
11092            return;
11093        };
11094
11095        let Some(buffer) = self
11096            .buffer
11097            .read(cx)
11098            .buffer_for_anchor(breakpoint_position, cx)
11099        else {
11100            return;
11101        };
11102
11103        breakpoint_store.update(cx, |breakpoint_store, cx| {
11104            breakpoint_store.toggle_breakpoint(
11105                buffer,
11106                BreakpointWithPosition {
11107                    position: breakpoint_position.text_anchor,
11108                    bp: breakpoint,
11109                },
11110                edit_action,
11111                cx,
11112            );
11113        });
11114
11115        cx.notify();
11116    }
11117
11118    #[cfg(any(test, feature = "test-support"))]
11119    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11120        self.breakpoint_store.clone()
11121    }
11122
11123    pub fn prepare_restore_change(
11124        &self,
11125        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11126        hunk: &MultiBufferDiffHunk,
11127        cx: &mut App,
11128    ) -> Option<()> {
11129        if hunk.is_created_file() {
11130            return None;
11131        }
11132        let buffer = self.buffer.read(cx);
11133        let diff = buffer.diff_for(hunk.buffer_id)?;
11134        let buffer = buffer.buffer(hunk.buffer_id)?;
11135        let buffer = buffer.read(cx);
11136        let original_text = diff
11137            .read(cx)
11138            .base_text()
11139            .as_rope()
11140            .slice(hunk.diff_base_byte_range.clone());
11141        let buffer_snapshot = buffer.snapshot();
11142        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11143        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11144            probe
11145                .0
11146                .start
11147                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11148                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11149        }) {
11150            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11151            Some(())
11152        } else {
11153            None
11154        }
11155    }
11156
11157    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11158        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11159    }
11160
11161    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11162        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11163    }
11164
11165    fn manipulate_lines<M>(
11166        &mut self,
11167        window: &mut Window,
11168        cx: &mut Context<Self>,
11169        mut manipulate: M,
11170    ) where
11171        M: FnMut(&str) -> LineManipulationResult,
11172    {
11173        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11174
11175        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11176        let buffer = self.buffer.read(cx).snapshot(cx);
11177
11178        let mut edits = Vec::new();
11179
11180        let selections = self.selections.all::<Point>(&display_map);
11181        let mut selections = selections.iter().peekable();
11182        let mut contiguous_row_selections = Vec::new();
11183        let mut new_selections = Vec::new();
11184        let mut added_lines = 0;
11185        let mut removed_lines = 0;
11186
11187        while let Some(selection) = selections.next() {
11188            let (start_row, end_row) = consume_contiguous_rows(
11189                &mut contiguous_row_selections,
11190                selection,
11191                &display_map,
11192                &mut selections,
11193            );
11194
11195            let start_point = Point::new(start_row.0, 0);
11196            let end_point = Point::new(
11197                end_row.previous_row().0,
11198                buffer.line_len(end_row.previous_row()),
11199            );
11200            let text = buffer
11201                .text_for_range(start_point..end_point)
11202                .collect::<String>();
11203
11204            let LineManipulationResult {
11205                new_text,
11206                line_count_before,
11207                line_count_after,
11208            } = manipulate(&text);
11209
11210            edits.push((start_point..end_point, new_text));
11211
11212            // Selections must change based on added and removed line count
11213            let start_row =
11214                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11215            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11216            new_selections.push(Selection {
11217                id: selection.id,
11218                start: start_row,
11219                end: end_row,
11220                goal: SelectionGoal::None,
11221                reversed: selection.reversed,
11222            });
11223
11224            if line_count_after > line_count_before {
11225                added_lines += line_count_after - line_count_before;
11226            } else if line_count_before > line_count_after {
11227                removed_lines += line_count_before - line_count_after;
11228            }
11229        }
11230
11231        self.transact(window, cx, |this, window, cx| {
11232            let buffer = this.buffer.update(cx, |buffer, cx| {
11233                buffer.edit(edits, None, cx);
11234                buffer.snapshot(cx)
11235            });
11236
11237            // Recalculate offsets on newly edited buffer
11238            let new_selections = new_selections
11239                .iter()
11240                .map(|s| {
11241                    let start_point = Point::new(s.start.0, 0);
11242                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11243                    Selection {
11244                        id: s.id,
11245                        start: buffer.point_to_offset(start_point),
11246                        end: buffer.point_to_offset(end_point),
11247                        goal: s.goal,
11248                        reversed: s.reversed,
11249                    }
11250                })
11251                .collect();
11252
11253            this.change_selections(Default::default(), window, cx, |s| {
11254                s.select(new_selections);
11255            });
11256
11257            this.request_autoscroll(Autoscroll::fit(), cx);
11258        });
11259    }
11260
11261    fn manipulate_immutable_lines<Fn>(
11262        &mut self,
11263        window: &mut Window,
11264        cx: &mut Context<Self>,
11265        mut callback: Fn,
11266    ) where
11267        Fn: FnMut(&mut Vec<&str>),
11268    {
11269        self.manipulate_lines(window, cx, |text| {
11270            let mut lines: Vec<&str> = text.split('\n').collect();
11271            let line_count_before = lines.len();
11272
11273            callback(&mut lines);
11274
11275            LineManipulationResult {
11276                new_text: lines.join("\n"),
11277                line_count_before,
11278                line_count_after: lines.len(),
11279            }
11280        });
11281    }
11282
11283    fn manipulate_mutable_lines<Fn>(
11284        &mut self,
11285        window: &mut Window,
11286        cx: &mut Context<Self>,
11287        mut callback: Fn,
11288    ) where
11289        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11290    {
11291        self.manipulate_lines(window, cx, |text| {
11292            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11293            let line_count_before = lines.len();
11294
11295            callback(&mut lines);
11296
11297            LineManipulationResult {
11298                new_text: lines.join("\n"),
11299                line_count_before,
11300                line_count_after: lines.len(),
11301            }
11302        });
11303    }
11304
11305    pub fn convert_indentation_to_spaces(
11306        &mut self,
11307        _: &ConvertIndentationToSpaces,
11308        window: &mut Window,
11309        cx: &mut Context<Self>,
11310    ) {
11311        let settings = self.buffer.read(cx).language_settings(cx);
11312        let tab_size = settings.tab_size.get() as usize;
11313
11314        self.manipulate_mutable_lines(window, cx, |lines| {
11315            // Allocates a reasonably sized scratch buffer once for the whole loop
11316            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11317            // Avoids recomputing spaces that could be inserted many times
11318            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11319                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11320                .collect();
11321
11322            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11323                let mut chars = line.as_ref().chars();
11324                let mut col = 0;
11325                let mut changed = false;
11326
11327                for ch in chars.by_ref() {
11328                    match ch {
11329                        ' ' => {
11330                            reindented_line.push(' ');
11331                            col += 1;
11332                        }
11333                        '\t' => {
11334                            // \t are converted to spaces depending on the current column
11335                            let spaces_len = tab_size - (col % tab_size);
11336                            reindented_line.extend(&space_cache[spaces_len - 1]);
11337                            col += spaces_len;
11338                            changed = true;
11339                        }
11340                        _ => {
11341                            // If we dont append before break, the character is consumed
11342                            reindented_line.push(ch);
11343                            break;
11344                        }
11345                    }
11346                }
11347
11348                if !changed {
11349                    reindented_line.clear();
11350                    continue;
11351                }
11352                // Append the rest of the line and replace old reference with new one
11353                reindented_line.extend(chars);
11354                *line = Cow::Owned(reindented_line.clone());
11355                reindented_line.clear();
11356            }
11357        });
11358    }
11359
11360    pub fn convert_indentation_to_tabs(
11361        &mut self,
11362        _: &ConvertIndentationToTabs,
11363        window: &mut Window,
11364        cx: &mut Context<Self>,
11365    ) {
11366        let settings = self.buffer.read(cx).language_settings(cx);
11367        let tab_size = settings.tab_size.get() as usize;
11368
11369        self.manipulate_mutable_lines(window, cx, |lines| {
11370            // Allocates a reasonably sized buffer once for the whole loop
11371            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11372            // Avoids recomputing spaces that could be inserted many times
11373            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11374                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11375                .collect();
11376
11377            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11378                let mut chars = line.chars();
11379                let mut spaces_count = 0;
11380                let mut first_non_indent_char = None;
11381                let mut changed = false;
11382
11383                for ch in chars.by_ref() {
11384                    match ch {
11385                        ' ' => {
11386                            // Keep track of spaces. Append \t when we reach tab_size
11387                            spaces_count += 1;
11388                            changed = true;
11389                            if spaces_count == tab_size {
11390                                reindented_line.push('\t');
11391                                spaces_count = 0;
11392                            }
11393                        }
11394                        '\t' => {
11395                            reindented_line.push('\t');
11396                            spaces_count = 0;
11397                        }
11398                        _ => {
11399                            // Dont append it yet, we might have remaining spaces
11400                            first_non_indent_char = Some(ch);
11401                            break;
11402                        }
11403                    }
11404                }
11405
11406                if !changed {
11407                    reindented_line.clear();
11408                    continue;
11409                }
11410                // Remaining spaces that didn't make a full tab stop
11411                if spaces_count > 0 {
11412                    reindented_line.extend(&space_cache[spaces_count - 1]);
11413                }
11414                // If we consume an extra character that was not indentation, add it back
11415                if let Some(extra_char) = first_non_indent_char {
11416                    reindented_line.push(extra_char);
11417                }
11418                // Append the rest of the line and replace old reference with new one
11419                reindented_line.extend(chars);
11420                *line = Cow::Owned(reindented_line.clone());
11421                reindented_line.clear();
11422            }
11423        });
11424    }
11425
11426    pub fn convert_to_upper_case(
11427        &mut self,
11428        _: &ConvertToUpperCase,
11429        window: &mut Window,
11430        cx: &mut Context<Self>,
11431    ) {
11432        self.manipulate_text(window, cx, |text| text.to_uppercase())
11433    }
11434
11435    pub fn convert_to_lower_case(
11436        &mut self,
11437        _: &ConvertToLowerCase,
11438        window: &mut Window,
11439        cx: &mut Context<Self>,
11440    ) {
11441        self.manipulate_text(window, cx, |text| text.to_lowercase())
11442    }
11443
11444    pub fn convert_to_title_case(
11445        &mut self,
11446        _: &ConvertToTitleCase,
11447        window: &mut Window,
11448        cx: &mut Context<Self>,
11449    ) {
11450        self.manipulate_text(window, cx, |text| {
11451            text.split('\n')
11452                .map(|line| line.to_case(Case::Title))
11453                .join("\n")
11454        })
11455    }
11456
11457    pub fn convert_to_snake_case(
11458        &mut self,
11459        _: &ConvertToSnakeCase,
11460        window: &mut Window,
11461        cx: &mut Context<Self>,
11462    ) {
11463        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11464    }
11465
11466    pub fn convert_to_kebab_case(
11467        &mut self,
11468        _: &ConvertToKebabCase,
11469        window: &mut Window,
11470        cx: &mut Context<Self>,
11471    ) {
11472        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11473    }
11474
11475    pub fn convert_to_upper_camel_case(
11476        &mut self,
11477        _: &ConvertToUpperCamelCase,
11478        window: &mut Window,
11479        cx: &mut Context<Self>,
11480    ) {
11481        self.manipulate_text(window, cx, |text| {
11482            text.split('\n')
11483                .map(|line| line.to_case(Case::UpperCamel))
11484                .join("\n")
11485        })
11486    }
11487
11488    pub fn convert_to_lower_camel_case(
11489        &mut self,
11490        _: &ConvertToLowerCamelCase,
11491        window: &mut Window,
11492        cx: &mut Context<Self>,
11493    ) {
11494        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11495    }
11496
11497    pub fn convert_to_opposite_case(
11498        &mut self,
11499        _: &ConvertToOppositeCase,
11500        window: &mut Window,
11501        cx: &mut Context<Self>,
11502    ) {
11503        self.manipulate_text(window, cx, |text| {
11504            text.chars()
11505                .fold(String::with_capacity(text.len()), |mut t, c| {
11506                    if c.is_uppercase() {
11507                        t.extend(c.to_lowercase());
11508                    } else {
11509                        t.extend(c.to_uppercase());
11510                    }
11511                    t
11512                })
11513        })
11514    }
11515
11516    pub fn convert_to_sentence_case(
11517        &mut self,
11518        _: &ConvertToSentenceCase,
11519        window: &mut Window,
11520        cx: &mut Context<Self>,
11521    ) {
11522        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11523    }
11524
11525    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11526        self.manipulate_text(window, cx, |text| {
11527            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11528            if has_upper_case_characters {
11529                text.to_lowercase()
11530            } else {
11531                text.to_uppercase()
11532            }
11533        })
11534    }
11535
11536    pub fn convert_to_rot13(
11537        &mut self,
11538        _: &ConvertToRot13,
11539        window: &mut Window,
11540        cx: &mut Context<Self>,
11541    ) {
11542        self.manipulate_text(window, cx, |text| {
11543            text.chars()
11544                .map(|c| match c {
11545                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11546                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11547                    _ => c,
11548                })
11549                .collect()
11550        })
11551    }
11552
11553    pub fn convert_to_rot47(
11554        &mut self,
11555        _: &ConvertToRot47,
11556        window: &mut Window,
11557        cx: &mut Context<Self>,
11558    ) {
11559        self.manipulate_text(window, cx, |text| {
11560            text.chars()
11561                .map(|c| {
11562                    let code_point = c as u32;
11563                    if code_point >= 33 && code_point <= 126 {
11564                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11565                    }
11566                    c
11567                })
11568                .collect()
11569        })
11570    }
11571
11572    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11573    where
11574        Fn: FnMut(&str) -> String,
11575    {
11576        let buffer = self.buffer.read(cx).snapshot(cx);
11577
11578        let mut new_selections = Vec::new();
11579        let mut edits = Vec::new();
11580        let mut selection_adjustment = 0i32;
11581
11582        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
11583            let selection_is_empty = selection.is_empty();
11584
11585            let (start, end) = if selection_is_empty {
11586                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11587                (word_range.start, word_range.end)
11588            } else {
11589                (
11590                    buffer.point_to_offset(selection.start),
11591                    buffer.point_to_offset(selection.end),
11592                )
11593            };
11594
11595            let text = buffer.text_for_range(start..end).collect::<String>();
11596            let old_length = text.len() as i32;
11597            let text = callback(&text);
11598
11599            new_selections.push(Selection {
11600                start: (start as i32 - selection_adjustment) as usize,
11601                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11602                goal: SelectionGoal::None,
11603                id: selection.id,
11604                reversed: selection.reversed,
11605            });
11606
11607            selection_adjustment += old_length - text.len() as i32;
11608
11609            edits.push((start..end, text));
11610        }
11611
11612        self.transact(window, cx, |this, window, cx| {
11613            this.buffer.update(cx, |buffer, cx| {
11614                buffer.edit(edits, None, cx);
11615            });
11616
11617            this.change_selections(Default::default(), window, cx, |s| {
11618                s.select(new_selections);
11619            });
11620
11621            this.request_autoscroll(Autoscroll::fit(), cx);
11622        });
11623    }
11624
11625    pub fn move_selection_on_drop(
11626        &mut self,
11627        selection: &Selection<Anchor>,
11628        target: DisplayPoint,
11629        is_cut: bool,
11630        window: &mut Window,
11631        cx: &mut Context<Self>,
11632    ) {
11633        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11634        let buffer = display_map.buffer_snapshot();
11635        let mut edits = Vec::new();
11636        let insert_point = display_map
11637            .clip_point(target, Bias::Left)
11638            .to_point(&display_map);
11639        let text = buffer
11640            .text_for_range(selection.start..selection.end)
11641            .collect::<String>();
11642        if is_cut {
11643            edits.push(((selection.start..selection.end), String::new()));
11644        }
11645        let insert_anchor = buffer.anchor_before(insert_point);
11646        edits.push(((insert_anchor..insert_anchor), text));
11647        let last_edit_start = insert_anchor.bias_left(buffer);
11648        let last_edit_end = insert_anchor.bias_right(buffer);
11649        self.transact(window, cx, |this, window, cx| {
11650            this.buffer.update(cx, |buffer, cx| {
11651                buffer.edit(edits, None, cx);
11652            });
11653            this.change_selections(Default::default(), window, cx, |s| {
11654                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11655            });
11656        });
11657    }
11658
11659    pub fn clear_selection_drag_state(&mut self) {
11660        self.selection_drag_state = SelectionDragState::None;
11661    }
11662
11663    pub fn duplicate(
11664        &mut self,
11665        upwards: bool,
11666        whole_lines: bool,
11667        window: &mut Window,
11668        cx: &mut Context<Self>,
11669    ) {
11670        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11671
11672        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11673        let buffer = display_map.buffer_snapshot();
11674        let selections = self.selections.all::<Point>(&display_map);
11675
11676        let mut edits = Vec::new();
11677        let mut selections_iter = selections.iter().peekable();
11678        while let Some(selection) = selections_iter.next() {
11679            let mut rows = selection.spanned_rows(false, &display_map);
11680            // duplicate line-wise
11681            if whole_lines || selection.start == selection.end {
11682                // Avoid duplicating the same lines twice.
11683                while let Some(next_selection) = selections_iter.peek() {
11684                    let next_rows = next_selection.spanned_rows(false, &display_map);
11685                    if next_rows.start < rows.end {
11686                        rows.end = next_rows.end;
11687                        selections_iter.next().unwrap();
11688                    } else {
11689                        break;
11690                    }
11691                }
11692
11693                // Copy the text from the selected row region and splice it either at the start
11694                // or end of the region.
11695                let start = Point::new(rows.start.0, 0);
11696                let end = Point::new(
11697                    rows.end.previous_row().0,
11698                    buffer.line_len(rows.end.previous_row()),
11699                );
11700
11701                let mut text = buffer.text_for_range(start..end).collect::<String>();
11702
11703                let insert_location = if upwards {
11704                    // When duplicating upward, we need to insert before the current line.
11705                    // If we're on the last line and it doesn't end with a newline,
11706                    // we need to add a newline before the duplicated content.
11707                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11708                        && buffer.max_point().column > 0
11709                        && !text.ends_with('\n');
11710
11711                    if needs_leading_newline {
11712                        text.insert(0, '\n');
11713                        end
11714                    } else {
11715                        text.push('\n');
11716                        Point::new(rows.start.0, 0)
11717                    }
11718                } else {
11719                    text.push('\n');
11720                    start
11721                };
11722                edits.push((insert_location..insert_location, text));
11723            } else {
11724                // duplicate character-wise
11725                let start = selection.start;
11726                let end = selection.end;
11727                let text = buffer.text_for_range(start..end).collect::<String>();
11728                edits.push((selection.end..selection.end, text));
11729            }
11730        }
11731
11732        self.transact(window, cx, |this, window, cx| {
11733            this.buffer.update(cx, |buffer, cx| {
11734                buffer.edit(edits, None, cx);
11735            });
11736
11737            // When duplicating upward with whole lines, move the cursor to the duplicated line
11738            if upwards && whole_lines {
11739                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
11740
11741                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11742                    let mut new_ranges = Vec::new();
11743                    let selections = s.all::<Point>(&display_map);
11744                    let mut selections_iter = selections.iter().peekable();
11745
11746                    while let Some(first_selection) = selections_iter.next() {
11747                        // Group contiguous selections together to find the total row span
11748                        let mut group_selections = vec![first_selection];
11749                        let mut rows = first_selection.spanned_rows(false, &display_map);
11750
11751                        while let Some(next_selection) = selections_iter.peek() {
11752                            let next_rows = next_selection.spanned_rows(false, &display_map);
11753                            if next_rows.start < rows.end {
11754                                rows.end = next_rows.end;
11755                                group_selections.push(selections_iter.next().unwrap());
11756                            } else {
11757                                break;
11758                            }
11759                        }
11760
11761                        let row_count = rows.end.0 - rows.start.0;
11762
11763                        // Move all selections in this group up by the total number of duplicated rows
11764                        for selection in group_selections {
11765                            let new_start = Point::new(
11766                                selection.start.row.saturating_sub(row_count),
11767                                selection.start.column,
11768                            );
11769
11770                            let new_end = Point::new(
11771                                selection.end.row.saturating_sub(row_count),
11772                                selection.end.column,
11773                            );
11774
11775                            new_ranges.push(new_start..new_end);
11776                        }
11777                    }
11778
11779                    s.select_ranges(new_ranges);
11780                });
11781            }
11782
11783            this.request_autoscroll(Autoscroll::fit(), cx);
11784        });
11785    }
11786
11787    pub fn duplicate_line_up(
11788        &mut self,
11789        _: &DuplicateLineUp,
11790        window: &mut Window,
11791        cx: &mut Context<Self>,
11792    ) {
11793        self.duplicate(true, true, window, cx);
11794    }
11795
11796    pub fn duplicate_line_down(
11797        &mut self,
11798        _: &DuplicateLineDown,
11799        window: &mut Window,
11800        cx: &mut Context<Self>,
11801    ) {
11802        self.duplicate(false, true, window, cx);
11803    }
11804
11805    pub fn duplicate_selection(
11806        &mut self,
11807        _: &DuplicateSelection,
11808        window: &mut Window,
11809        cx: &mut Context<Self>,
11810    ) {
11811        self.duplicate(false, false, window, cx);
11812    }
11813
11814    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11815        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11816        if self.mode.is_single_line() {
11817            cx.propagate();
11818            return;
11819        }
11820
11821        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11822        let buffer = self.buffer.read(cx).snapshot(cx);
11823
11824        let mut edits = Vec::new();
11825        let mut unfold_ranges = Vec::new();
11826        let mut refold_creases = Vec::new();
11827
11828        let selections = self.selections.all::<Point>(&display_map);
11829        let mut selections = selections.iter().peekable();
11830        let mut contiguous_row_selections = Vec::new();
11831        let mut new_selections = Vec::new();
11832
11833        while let Some(selection) = selections.next() {
11834            // Find all the selections that span a contiguous row range
11835            let (start_row, end_row) = consume_contiguous_rows(
11836                &mut contiguous_row_selections,
11837                selection,
11838                &display_map,
11839                &mut selections,
11840            );
11841
11842            // Move the text spanned by the row range to be before the line preceding the row range
11843            if start_row.0 > 0 {
11844                let range_to_move = Point::new(
11845                    start_row.previous_row().0,
11846                    buffer.line_len(start_row.previous_row()),
11847                )
11848                    ..Point::new(
11849                        end_row.previous_row().0,
11850                        buffer.line_len(end_row.previous_row()),
11851                    );
11852                let insertion_point = display_map
11853                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11854                    .0;
11855
11856                // Don't move lines across excerpts
11857                if buffer
11858                    .excerpt_containing(insertion_point..range_to_move.end)
11859                    .is_some()
11860                {
11861                    let text = buffer
11862                        .text_for_range(range_to_move.clone())
11863                        .flat_map(|s| s.chars())
11864                        .skip(1)
11865                        .chain(['\n'])
11866                        .collect::<String>();
11867
11868                    edits.push((
11869                        buffer.anchor_after(range_to_move.start)
11870                            ..buffer.anchor_before(range_to_move.end),
11871                        String::new(),
11872                    ));
11873                    let insertion_anchor = buffer.anchor_after(insertion_point);
11874                    edits.push((insertion_anchor..insertion_anchor, text));
11875
11876                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11877
11878                    // Move selections up
11879                    new_selections.extend(contiguous_row_selections.drain(..).map(
11880                        |mut selection| {
11881                            selection.start.row -= row_delta;
11882                            selection.end.row -= row_delta;
11883                            selection
11884                        },
11885                    ));
11886
11887                    // Move folds up
11888                    unfold_ranges.push(range_to_move.clone());
11889                    for fold in display_map.folds_in_range(
11890                        buffer.anchor_before(range_to_move.start)
11891                            ..buffer.anchor_after(range_to_move.end),
11892                    ) {
11893                        let mut start = fold.range.start.to_point(&buffer);
11894                        let mut end = fold.range.end.to_point(&buffer);
11895                        start.row -= row_delta;
11896                        end.row -= row_delta;
11897                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11898                    }
11899                }
11900            }
11901
11902            // If we didn't move line(s), preserve the existing selections
11903            new_selections.append(&mut contiguous_row_selections);
11904        }
11905
11906        self.transact(window, cx, |this, window, cx| {
11907            this.unfold_ranges(&unfold_ranges, true, true, cx);
11908            this.buffer.update(cx, |buffer, cx| {
11909                for (range, text) in edits {
11910                    buffer.edit([(range, text)], None, cx);
11911                }
11912            });
11913            this.fold_creases(refold_creases, true, window, cx);
11914            this.change_selections(Default::default(), window, cx, |s| {
11915                s.select(new_selections);
11916            })
11917        });
11918    }
11919
11920    pub fn move_line_down(
11921        &mut self,
11922        _: &MoveLineDown,
11923        window: &mut Window,
11924        cx: &mut Context<Self>,
11925    ) {
11926        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11927        if self.mode.is_single_line() {
11928            cx.propagate();
11929            return;
11930        }
11931
11932        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11933        let buffer = self.buffer.read(cx).snapshot(cx);
11934
11935        let mut edits = Vec::new();
11936        let mut unfold_ranges = Vec::new();
11937        let mut refold_creases = Vec::new();
11938
11939        let selections = self.selections.all::<Point>(&display_map);
11940        let mut selections = selections.iter().peekable();
11941        let mut contiguous_row_selections = Vec::new();
11942        let mut new_selections = Vec::new();
11943
11944        while let Some(selection) = selections.next() {
11945            // Find all the selections that span a contiguous row range
11946            let (start_row, end_row) = consume_contiguous_rows(
11947                &mut contiguous_row_selections,
11948                selection,
11949                &display_map,
11950                &mut selections,
11951            );
11952
11953            // Move the text spanned by the row range to be after the last line of the row range
11954            if end_row.0 <= buffer.max_point().row {
11955                let range_to_move =
11956                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11957                let insertion_point = display_map
11958                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11959                    .0;
11960
11961                // Don't move lines across excerpt boundaries
11962                if buffer
11963                    .excerpt_containing(range_to_move.start..insertion_point)
11964                    .is_some()
11965                {
11966                    let mut text = String::from("\n");
11967                    text.extend(buffer.text_for_range(range_to_move.clone()));
11968                    text.pop(); // Drop trailing newline
11969                    edits.push((
11970                        buffer.anchor_after(range_to_move.start)
11971                            ..buffer.anchor_before(range_to_move.end),
11972                        String::new(),
11973                    ));
11974                    let insertion_anchor = buffer.anchor_after(insertion_point);
11975                    edits.push((insertion_anchor..insertion_anchor, text));
11976
11977                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11978
11979                    // Move selections down
11980                    new_selections.extend(contiguous_row_selections.drain(..).map(
11981                        |mut selection| {
11982                            selection.start.row += row_delta;
11983                            selection.end.row += row_delta;
11984                            selection
11985                        },
11986                    ));
11987
11988                    // Move folds down
11989                    unfold_ranges.push(range_to_move.clone());
11990                    for fold in display_map.folds_in_range(
11991                        buffer.anchor_before(range_to_move.start)
11992                            ..buffer.anchor_after(range_to_move.end),
11993                    ) {
11994                        let mut start = fold.range.start.to_point(&buffer);
11995                        let mut end = fold.range.end.to_point(&buffer);
11996                        start.row += row_delta;
11997                        end.row += row_delta;
11998                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11999                    }
12000                }
12001            }
12002
12003            // If we didn't move line(s), preserve the existing selections
12004            new_selections.append(&mut contiguous_row_selections);
12005        }
12006
12007        self.transact(window, cx, |this, window, cx| {
12008            this.unfold_ranges(&unfold_ranges, true, true, cx);
12009            this.buffer.update(cx, |buffer, cx| {
12010                for (range, text) in edits {
12011                    buffer.edit([(range, text)], None, cx);
12012                }
12013            });
12014            this.fold_creases(refold_creases, true, window, cx);
12015            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12016        });
12017    }
12018
12019    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12020        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12021        let text_layout_details = &self.text_layout_details(window);
12022        self.transact(window, cx, |this, window, cx| {
12023            let edits = this.change_selections(Default::default(), window, cx, |s| {
12024                let mut edits: Vec<(Range<usize>, String)> = Default::default();
12025                s.move_with(|display_map, selection| {
12026                    if !selection.is_empty() {
12027                        return;
12028                    }
12029
12030                    let mut head = selection.head();
12031                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12032                    if head.column() == display_map.line_len(head.row()) {
12033                        transpose_offset = display_map
12034                            .buffer_snapshot()
12035                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12036                    }
12037
12038                    if transpose_offset == 0 {
12039                        return;
12040                    }
12041
12042                    *head.column_mut() += 1;
12043                    head = display_map.clip_point(head, Bias::Right);
12044                    let goal = SelectionGoal::HorizontalPosition(
12045                        display_map
12046                            .x_for_display_point(head, text_layout_details)
12047                            .into(),
12048                    );
12049                    selection.collapse_to(head, goal);
12050
12051                    let transpose_start = display_map
12052                        .buffer_snapshot()
12053                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12054                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12055                        let transpose_end = display_map
12056                            .buffer_snapshot()
12057                            .clip_offset(transpose_offset + 1, Bias::Right);
12058                        if let Some(ch) = display_map
12059                            .buffer_snapshot()
12060                            .chars_at(transpose_start)
12061                            .next()
12062                        {
12063                            edits.push((transpose_start..transpose_offset, String::new()));
12064                            edits.push((transpose_end..transpose_end, ch.to_string()));
12065                        }
12066                    }
12067                });
12068                edits
12069            });
12070            this.buffer
12071                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12072            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12073            this.change_selections(Default::default(), window, cx, |s| {
12074                s.select(selections);
12075            });
12076        });
12077    }
12078
12079    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12080        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12081        if self.mode.is_single_line() {
12082            cx.propagate();
12083            return;
12084        }
12085
12086        self.rewrap_impl(RewrapOptions::default(), cx)
12087    }
12088
12089    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12090        let buffer = self.buffer.read(cx).snapshot(cx);
12091        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12092
12093        #[derive(Clone, Debug, PartialEq)]
12094        enum CommentFormat {
12095            /// single line comment, with prefix for line
12096            Line(String),
12097            /// single line within a block comment, with prefix for line
12098            BlockLine(String),
12099            /// a single line of a block comment that includes the initial delimiter
12100            BlockCommentWithStart(BlockCommentConfig),
12101            /// a single line of a block comment that includes the ending delimiter
12102            BlockCommentWithEnd(BlockCommentConfig),
12103        }
12104
12105        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12106        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12107            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12108                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12109                .peekable();
12110
12111            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12112                row
12113            } else {
12114                return Vec::new();
12115            };
12116
12117            let language_settings = buffer.language_settings_at(selection.head(), cx);
12118            let language_scope = buffer.language_scope_at(selection.head());
12119
12120            let indent_and_prefix_for_row =
12121                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12122                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12123                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12124                        &language_scope
12125                    {
12126                        let indent_end = Point::new(row, indent.len);
12127                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12128                        let line_text_after_indent = buffer
12129                            .text_for_range(indent_end..line_end)
12130                            .collect::<String>();
12131
12132                        let is_within_comment_override = buffer
12133                            .language_scope_at(indent_end)
12134                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12135                        let comment_delimiters = if is_within_comment_override {
12136                            // we are within a comment syntax node, but we don't
12137                            // yet know what kind of comment: block, doc or line
12138                            match (
12139                                language_scope.documentation_comment(),
12140                                language_scope.block_comment(),
12141                            ) {
12142                                (Some(config), _) | (_, Some(config))
12143                                    if buffer.contains_str_at(indent_end, &config.start) =>
12144                                {
12145                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12146                                }
12147                                (Some(config), _) | (_, Some(config))
12148                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12149                                {
12150                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12151                                }
12152                                (Some(config), _) | (_, Some(config))
12153                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12154                                {
12155                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12156                                }
12157                                (_, _) => language_scope
12158                                    .line_comment_prefixes()
12159                                    .iter()
12160                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12161                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12162                            }
12163                        } else {
12164                            // we not in an overridden comment node, but we may
12165                            // be within a non-overridden line comment node
12166                            language_scope
12167                                .line_comment_prefixes()
12168                                .iter()
12169                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12170                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12171                        };
12172
12173                        let rewrap_prefix = language_scope
12174                            .rewrap_prefixes()
12175                            .iter()
12176                            .find_map(|prefix_regex| {
12177                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12178                                    if mat.start() == 0 {
12179                                        Some(mat.as_str().to_string())
12180                                    } else {
12181                                        None
12182                                    }
12183                                })
12184                            })
12185                            .flatten();
12186                        (comment_delimiters, rewrap_prefix)
12187                    } else {
12188                        (None, None)
12189                    };
12190                    (indent, comment_prefix, rewrap_prefix)
12191                };
12192
12193            let mut ranges = Vec::new();
12194            let from_empty_selection = selection.is_empty();
12195
12196            let mut current_range_start = first_row;
12197            let mut prev_row = first_row;
12198            let (
12199                mut current_range_indent,
12200                mut current_range_comment_delimiters,
12201                mut current_range_rewrap_prefix,
12202            ) = indent_and_prefix_for_row(first_row);
12203
12204            for row in non_blank_rows_iter.skip(1) {
12205                let has_paragraph_break = row > prev_row + 1;
12206
12207                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12208                    indent_and_prefix_for_row(row);
12209
12210                let has_indent_change = row_indent != current_range_indent;
12211                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12212
12213                let has_boundary_change = has_comment_change
12214                    || row_rewrap_prefix.is_some()
12215                    || (has_indent_change && current_range_comment_delimiters.is_some());
12216
12217                if has_paragraph_break || has_boundary_change {
12218                    ranges.push((
12219                        language_settings.clone(),
12220                        Point::new(current_range_start, 0)
12221                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12222                        current_range_indent,
12223                        current_range_comment_delimiters.clone(),
12224                        current_range_rewrap_prefix.clone(),
12225                        from_empty_selection,
12226                    ));
12227                    current_range_start = row;
12228                    current_range_indent = row_indent;
12229                    current_range_comment_delimiters = row_comment_delimiters;
12230                    current_range_rewrap_prefix = row_rewrap_prefix;
12231                }
12232                prev_row = row;
12233            }
12234
12235            ranges.push((
12236                language_settings.clone(),
12237                Point::new(current_range_start, 0)
12238                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12239                current_range_indent,
12240                current_range_comment_delimiters,
12241                current_range_rewrap_prefix,
12242                from_empty_selection,
12243            ));
12244
12245            ranges
12246        });
12247
12248        let mut edits = Vec::new();
12249        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12250
12251        for (
12252            language_settings,
12253            wrap_range,
12254            mut indent_size,
12255            comment_prefix,
12256            rewrap_prefix,
12257            from_empty_selection,
12258        ) in wrap_ranges
12259        {
12260            let mut start_row = wrap_range.start.row;
12261            let mut end_row = wrap_range.end.row;
12262
12263            // Skip selections that overlap with a range that has already been rewrapped.
12264            let selection_range = start_row..end_row;
12265            if rewrapped_row_ranges
12266                .iter()
12267                .any(|range| range.overlaps(&selection_range))
12268            {
12269                continue;
12270            }
12271
12272            let tab_size = language_settings.tab_size;
12273
12274            let (line_prefix, inside_comment) = match &comment_prefix {
12275                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12276                    (Some(prefix.as_str()), true)
12277                }
12278                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12279                    (Some(prefix.as_ref()), true)
12280                }
12281                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12282                    start: _,
12283                    end: _,
12284                    prefix,
12285                    tab_size,
12286                })) => {
12287                    indent_size.len += tab_size;
12288                    (Some(prefix.as_ref()), true)
12289                }
12290                None => (None, false),
12291            };
12292            let indent_prefix = indent_size.chars().collect::<String>();
12293            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12294
12295            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12296                RewrapBehavior::InComments => inside_comment,
12297                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12298                RewrapBehavior::Anywhere => true,
12299            };
12300
12301            let should_rewrap = options.override_language_settings
12302                || allow_rewrap_based_on_language
12303                || self.hard_wrap.is_some();
12304            if !should_rewrap {
12305                continue;
12306            }
12307
12308            if from_empty_selection {
12309                'expand_upwards: while start_row > 0 {
12310                    let prev_row = start_row - 1;
12311                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12312                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12313                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12314                    {
12315                        start_row = prev_row;
12316                    } else {
12317                        break 'expand_upwards;
12318                    }
12319                }
12320
12321                'expand_downwards: while end_row < buffer.max_point().row {
12322                    let next_row = end_row + 1;
12323                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12324                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12325                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12326                    {
12327                        end_row = next_row;
12328                    } else {
12329                        break 'expand_downwards;
12330                    }
12331                }
12332            }
12333
12334            let start = Point::new(start_row, 0);
12335            let start_offset = ToOffset::to_offset(&start, &buffer);
12336            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12337            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12338            let mut first_line_delimiter = None;
12339            let mut last_line_delimiter = None;
12340            let Some(lines_without_prefixes) = selection_text
12341                .lines()
12342                .enumerate()
12343                .map(|(ix, line)| {
12344                    let line_trimmed = line.trim_start();
12345                    if rewrap_prefix.is_some() && ix > 0 {
12346                        Ok(line_trimmed)
12347                    } else if let Some(
12348                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12349                            start,
12350                            prefix,
12351                            end,
12352                            tab_size,
12353                        })
12354                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12355                            start,
12356                            prefix,
12357                            end,
12358                            tab_size,
12359                        }),
12360                    ) = &comment_prefix
12361                    {
12362                        let line_trimmed = line_trimmed
12363                            .strip_prefix(start.as_ref())
12364                            .map(|s| {
12365                                let mut indent_size = indent_size;
12366                                indent_size.len -= tab_size;
12367                                let indent_prefix: String = indent_size.chars().collect();
12368                                first_line_delimiter = Some((indent_prefix, start));
12369                                s.trim_start()
12370                            })
12371                            .unwrap_or(line_trimmed);
12372                        let line_trimmed = line_trimmed
12373                            .strip_suffix(end.as_ref())
12374                            .map(|s| {
12375                                last_line_delimiter = Some(end);
12376                                s.trim_end()
12377                            })
12378                            .unwrap_or(line_trimmed);
12379                        let line_trimmed = line_trimmed
12380                            .strip_prefix(prefix.as_ref())
12381                            .unwrap_or(line_trimmed);
12382                        Ok(line_trimmed)
12383                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12384                        line_trimmed.strip_prefix(prefix).with_context(|| {
12385                            format!("line did not start with prefix {prefix:?}: {line:?}")
12386                        })
12387                    } else {
12388                        line_trimmed
12389                            .strip_prefix(&line_prefix.trim_start())
12390                            .with_context(|| {
12391                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12392                            })
12393                    }
12394                })
12395                .collect::<Result<Vec<_>, _>>()
12396                .log_err()
12397            else {
12398                continue;
12399            };
12400
12401            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12402                buffer
12403                    .language_settings_at(Point::new(start_row, 0), cx)
12404                    .preferred_line_length as usize
12405            });
12406
12407            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12408                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12409            } else {
12410                line_prefix.clone()
12411            };
12412
12413            let wrapped_text = {
12414                let mut wrapped_text = wrap_with_prefix(
12415                    line_prefix,
12416                    subsequent_lines_prefix,
12417                    lines_without_prefixes.join("\n"),
12418                    wrap_column,
12419                    tab_size,
12420                    options.preserve_existing_whitespace,
12421                );
12422
12423                if let Some((indent, delimiter)) = first_line_delimiter {
12424                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12425                }
12426                if let Some(last_line) = last_line_delimiter {
12427                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12428                }
12429
12430                wrapped_text
12431            };
12432
12433            // TODO: should always use char-based diff while still supporting cursor behavior that
12434            // matches vim.
12435            let mut diff_options = DiffOptions::default();
12436            if options.override_language_settings {
12437                diff_options.max_word_diff_len = 0;
12438                diff_options.max_word_diff_line_count = 0;
12439            } else {
12440                diff_options.max_word_diff_len = usize::MAX;
12441                diff_options.max_word_diff_line_count = usize::MAX;
12442            }
12443
12444            for (old_range, new_text) in
12445                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12446            {
12447                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12448                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12449                edits.push((edit_start..edit_end, new_text));
12450            }
12451
12452            rewrapped_row_ranges.push(start_row..=end_row);
12453        }
12454
12455        self.buffer
12456            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12457    }
12458
12459    pub fn cut_common(
12460        &mut self,
12461        cut_no_selection_line: bool,
12462        window: &mut Window,
12463        cx: &mut Context<Self>,
12464    ) -> ClipboardItem {
12465        let mut text = String::new();
12466        let buffer = self.buffer.read(cx).snapshot(cx);
12467        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12468        let mut clipboard_selections = Vec::with_capacity(selections.len());
12469        {
12470            let max_point = buffer.max_point();
12471            let mut is_first = true;
12472            for selection in &mut selections {
12473                let is_entire_line =
12474                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12475                if is_entire_line {
12476                    selection.start = Point::new(selection.start.row, 0);
12477                    if !selection.is_empty() && selection.end.column == 0 {
12478                        selection.end = cmp::min(max_point, selection.end);
12479                    } else {
12480                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12481                    }
12482                    selection.goal = SelectionGoal::None;
12483                }
12484                if is_first {
12485                    is_first = false;
12486                } else {
12487                    text += "\n";
12488                }
12489                let mut len = 0;
12490                for chunk in buffer.text_for_range(selection.start..selection.end) {
12491                    text.push_str(chunk);
12492                    len += chunk.len();
12493                }
12494                clipboard_selections.push(ClipboardSelection {
12495                    len,
12496                    is_entire_line,
12497                    first_line_indent: buffer
12498                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12499                        .len,
12500                });
12501            }
12502        }
12503
12504        self.transact(window, cx, |this, window, cx| {
12505            this.change_selections(Default::default(), window, cx, |s| {
12506                s.select(selections);
12507            });
12508            this.insert("", window, cx);
12509        });
12510        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12511    }
12512
12513    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12514        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12515        let item = self.cut_common(true, window, cx);
12516        cx.write_to_clipboard(item);
12517    }
12518
12519    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12520        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12521        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12522            s.move_with(|snapshot, sel| {
12523                if sel.is_empty() {
12524                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12525                }
12526                if sel.is_empty() {
12527                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12528                }
12529            });
12530        });
12531        let item = self.cut_common(false, window, cx);
12532        cx.set_global(KillRing(item))
12533    }
12534
12535    pub fn kill_ring_yank(
12536        &mut self,
12537        _: &KillRingYank,
12538        window: &mut Window,
12539        cx: &mut Context<Self>,
12540    ) {
12541        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12542        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12543            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12544                (kill_ring.text().to_string(), kill_ring.metadata_json())
12545            } else {
12546                return;
12547            }
12548        } else {
12549            return;
12550        };
12551        self.do_paste(&text, metadata, false, window, cx);
12552    }
12553
12554    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12555        self.do_copy(true, cx);
12556    }
12557
12558    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12559        self.do_copy(false, cx);
12560    }
12561
12562    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12563        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12564        let buffer = self.buffer.read(cx).read(cx);
12565        let mut text = String::new();
12566
12567        let mut clipboard_selections = Vec::with_capacity(selections.len());
12568        {
12569            let max_point = buffer.max_point();
12570            let mut is_first = true;
12571            for selection in &selections {
12572                let mut start = selection.start;
12573                let mut end = selection.end;
12574                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12575                let mut add_trailing_newline = false;
12576                if is_entire_line {
12577                    start = Point::new(start.row, 0);
12578                    let next_line_start = Point::new(end.row + 1, 0);
12579                    if next_line_start <= max_point {
12580                        end = next_line_start;
12581                    } else {
12582                        // We're on the last line without a trailing newline.
12583                        // Copy to the end of the line and add a newline afterwards.
12584                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12585                        add_trailing_newline = true;
12586                    }
12587                }
12588
12589                let mut trimmed_selections = Vec::new();
12590                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12591                    let row = MultiBufferRow(start.row);
12592                    let first_indent = buffer.indent_size_for_line(row);
12593                    if first_indent.len == 0 || start.column > first_indent.len {
12594                        trimmed_selections.push(start..end);
12595                    } else {
12596                        trimmed_selections.push(
12597                            Point::new(row.0, first_indent.len)
12598                                ..Point::new(row.0, buffer.line_len(row)),
12599                        );
12600                        for row in start.row + 1..=end.row {
12601                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12602                            if row == end.row {
12603                                line_len = end.column;
12604                            }
12605                            if line_len == 0 {
12606                                trimmed_selections
12607                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12608                                continue;
12609                            }
12610                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12611                            if row_indent_size.len >= first_indent.len {
12612                                trimmed_selections.push(
12613                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12614                                );
12615                            } else {
12616                                trimmed_selections.clear();
12617                                trimmed_selections.push(start..end);
12618                                break;
12619                            }
12620                        }
12621                    }
12622                } else {
12623                    trimmed_selections.push(start..end);
12624                }
12625
12626                for trimmed_range in trimmed_selections {
12627                    if is_first {
12628                        is_first = false;
12629                    } else {
12630                        text += "\n";
12631                    }
12632                    let mut len = 0;
12633                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12634                        text.push_str(chunk);
12635                        len += chunk.len();
12636                    }
12637                    if add_trailing_newline {
12638                        text.push('\n');
12639                        len += 1;
12640                    }
12641                    clipboard_selections.push(ClipboardSelection {
12642                        len,
12643                        is_entire_line,
12644                        first_line_indent: buffer
12645                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12646                            .len,
12647                    });
12648                }
12649            }
12650        }
12651
12652        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12653            text,
12654            clipboard_selections,
12655        ));
12656    }
12657
12658    pub fn do_paste(
12659        &mut self,
12660        text: &String,
12661        clipboard_selections: Option<Vec<ClipboardSelection>>,
12662        handle_entire_lines: bool,
12663        window: &mut Window,
12664        cx: &mut Context<Self>,
12665    ) {
12666        if self.read_only(cx) {
12667            return;
12668        }
12669
12670        let clipboard_text = Cow::Borrowed(text.as_str());
12671
12672        self.transact(window, cx, |this, window, cx| {
12673            let had_active_edit_prediction = this.has_active_edit_prediction();
12674            let display_map = this.display_snapshot(cx);
12675            let old_selections = this.selections.all::<usize>(&display_map);
12676            let cursor_offset = this.selections.last::<usize>(&display_map).head();
12677
12678            if let Some(mut clipboard_selections) = clipboard_selections {
12679                let all_selections_were_entire_line =
12680                    clipboard_selections.iter().all(|s| s.is_entire_line);
12681                let first_selection_indent_column =
12682                    clipboard_selections.first().map(|s| s.first_line_indent);
12683                if clipboard_selections.len() != old_selections.len() {
12684                    clipboard_selections.drain(..);
12685                }
12686                let mut auto_indent_on_paste = true;
12687
12688                this.buffer.update(cx, |buffer, cx| {
12689                    let snapshot = buffer.read(cx);
12690                    auto_indent_on_paste = snapshot
12691                        .language_settings_at(cursor_offset, cx)
12692                        .auto_indent_on_paste;
12693
12694                    let mut start_offset = 0;
12695                    let mut edits = Vec::new();
12696                    let mut original_indent_columns = Vec::new();
12697                    for (ix, selection) in old_selections.iter().enumerate() {
12698                        let to_insert;
12699                        let entire_line;
12700                        let original_indent_column;
12701                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12702                            let end_offset = start_offset + clipboard_selection.len;
12703                            to_insert = &clipboard_text[start_offset..end_offset];
12704                            entire_line = clipboard_selection.is_entire_line;
12705                            start_offset = end_offset + 1;
12706                            original_indent_column = Some(clipboard_selection.first_line_indent);
12707                        } else {
12708                            to_insert = &*clipboard_text;
12709                            entire_line = all_selections_were_entire_line;
12710                            original_indent_column = first_selection_indent_column
12711                        }
12712
12713                        let (range, to_insert) =
12714                            if selection.is_empty() && handle_entire_lines && entire_line {
12715                                // If the corresponding selection was empty when this slice of the
12716                                // clipboard text was written, then the entire line containing the
12717                                // selection was copied. If this selection is also currently empty,
12718                                // then paste the line before the current line of the buffer.
12719                                let column = selection.start.to_point(&snapshot).column as usize;
12720                                let line_start = selection.start - column;
12721                                (line_start..line_start, Cow::Borrowed(to_insert))
12722                            } else {
12723                                let language = snapshot.language_at(selection.head());
12724                                let range = selection.range();
12725                                if let Some(language) = language
12726                                    && language.name() == "Markdown".into()
12727                                {
12728                                    edit_for_markdown_paste(
12729                                        &snapshot,
12730                                        range,
12731                                        to_insert,
12732                                        url::Url::parse(to_insert).ok(),
12733                                    )
12734                                } else {
12735                                    (range, Cow::Borrowed(to_insert))
12736                                }
12737                            };
12738
12739                        edits.push((range, to_insert));
12740                        original_indent_columns.push(original_indent_column);
12741                    }
12742                    drop(snapshot);
12743
12744                    buffer.edit(
12745                        edits,
12746                        if auto_indent_on_paste {
12747                            Some(AutoindentMode::Block {
12748                                original_indent_columns,
12749                            })
12750                        } else {
12751                            None
12752                        },
12753                        cx,
12754                    );
12755                });
12756
12757                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12758                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12759            } else {
12760                let url = url::Url::parse(&clipboard_text).ok();
12761
12762                let auto_indent_mode = if !clipboard_text.is_empty() {
12763                    Some(AutoindentMode::Block {
12764                        original_indent_columns: Vec::new(),
12765                    })
12766                } else {
12767                    None
12768                };
12769
12770                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12771                    let snapshot = buffer.snapshot(cx);
12772
12773                    let anchors = old_selections
12774                        .iter()
12775                        .map(|s| {
12776                            let anchor = snapshot.anchor_after(s.head());
12777                            s.map(|_| anchor)
12778                        })
12779                        .collect::<Vec<_>>();
12780
12781                    let mut edits = Vec::new();
12782
12783                    for selection in old_selections.iter() {
12784                        let language = snapshot.language_at(selection.head());
12785                        let range = selection.range();
12786
12787                        let (edit_range, edit_text) = if let Some(language) = language
12788                            && language.name() == "Markdown".into()
12789                        {
12790                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12791                        } else {
12792                            (range, clipboard_text.clone())
12793                        };
12794
12795                        edits.push((edit_range, edit_text));
12796                    }
12797
12798                    drop(snapshot);
12799                    buffer.edit(edits, auto_indent_mode, cx);
12800
12801                    anchors
12802                });
12803
12804                this.change_selections(Default::default(), window, cx, |s| {
12805                    s.select_anchors(selection_anchors);
12806                });
12807            }
12808
12809            let trigger_in_words =
12810                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12811
12812            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12813        });
12814    }
12815
12816    pub fn diff_clipboard_with_selection(
12817        &mut self,
12818        _: &DiffClipboardWithSelection,
12819        window: &mut Window,
12820        cx: &mut Context<Self>,
12821    ) {
12822        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
12823
12824        if selections.is_empty() {
12825            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12826            return;
12827        };
12828
12829        let clipboard_text = match cx.read_from_clipboard() {
12830            Some(item) => match item.entries().first() {
12831                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12832                _ => None,
12833            },
12834            None => None,
12835        };
12836
12837        let Some(clipboard_text) = clipboard_text else {
12838            log::warn!("Clipboard doesn't contain text.");
12839            return;
12840        };
12841
12842        window.dispatch_action(
12843            Box::new(DiffClipboardWithSelectionData {
12844                clipboard_text,
12845                editor: cx.entity(),
12846            }),
12847            cx,
12848        );
12849    }
12850
12851    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12852        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12853        if let Some(item) = cx.read_from_clipboard() {
12854            let entries = item.entries();
12855
12856            match entries.first() {
12857                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12858                // of all the pasted entries.
12859                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12860                    .do_paste(
12861                        clipboard_string.text(),
12862                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12863                        true,
12864                        window,
12865                        cx,
12866                    ),
12867                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12868            }
12869        }
12870    }
12871
12872    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12873        if self.read_only(cx) {
12874            return;
12875        }
12876
12877        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12878
12879        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12880            if let Some((selections, _)) =
12881                self.selection_history.transaction(transaction_id).cloned()
12882            {
12883                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12884                    s.select_anchors(selections.to_vec());
12885                });
12886            } else {
12887                log::error!(
12888                    "No entry in selection_history found for undo. \
12889                     This may correspond to a bug where undo does not update the selection. \
12890                     If this is occurring, please add details to \
12891                     https://github.com/zed-industries/zed/issues/22692"
12892                );
12893            }
12894            self.request_autoscroll(Autoscroll::fit(), cx);
12895            self.unmark_text(window, cx);
12896            self.refresh_edit_prediction(true, false, window, cx);
12897            cx.emit(EditorEvent::Edited { transaction_id });
12898            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12899        }
12900    }
12901
12902    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12903        if self.read_only(cx) {
12904            return;
12905        }
12906
12907        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12908
12909        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12910            if let Some((_, Some(selections))) =
12911                self.selection_history.transaction(transaction_id).cloned()
12912            {
12913                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12914                    s.select_anchors(selections.to_vec());
12915                });
12916            } else {
12917                log::error!(
12918                    "No entry in selection_history found for redo. \
12919                     This may correspond to a bug where undo does not update the selection. \
12920                     If this is occurring, please add details to \
12921                     https://github.com/zed-industries/zed/issues/22692"
12922                );
12923            }
12924            self.request_autoscroll(Autoscroll::fit(), cx);
12925            self.unmark_text(window, cx);
12926            self.refresh_edit_prediction(true, false, window, cx);
12927            cx.emit(EditorEvent::Edited { transaction_id });
12928        }
12929    }
12930
12931    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12932        self.buffer
12933            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12934    }
12935
12936    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12937        self.buffer
12938            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12939    }
12940
12941    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12942        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12943        self.change_selections(Default::default(), window, cx, |s| {
12944            s.move_with(|map, selection| {
12945                let cursor = if selection.is_empty() {
12946                    movement::left(map, selection.start)
12947                } else {
12948                    selection.start
12949                };
12950                selection.collapse_to(cursor, SelectionGoal::None);
12951            });
12952        })
12953    }
12954
12955    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12956        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12957        self.change_selections(Default::default(), window, cx, |s| {
12958            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12959        })
12960    }
12961
12962    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12963        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12964        self.change_selections(Default::default(), window, cx, |s| {
12965            s.move_with(|map, selection| {
12966                let cursor = if selection.is_empty() {
12967                    movement::right(map, selection.end)
12968                } else {
12969                    selection.end
12970                };
12971                selection.collapse_to(cursor, SelectionGoal::None)
12972            });
12973        })
12974    }
12975
12976    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12977        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12978        self.change_selections(Default::default(), window, cx, |s| {
12979            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12980        });
12981    }
12982
12983    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12984        if self.take_rename(true, window, cx).is_some() {
12985            return;
12986        }
12987
12988        if self.mode.is_single_line() {
12989            cx.propagate();
12990            return;
12991        }
12992
12993        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12994
12995        let text_layout_details = &self.text_layout_details(window);
12996        let selection_count = self.selections.count();
12997        let first_selection = self.selections.first_anchor();
12998
12999        self.change_selections(Default::default(), window, cx, |s| {
13000            s.move_with(|map, selection| {
13001                if !selection.is_empty() {
13002                    selection.goal = SelectionGoal::None;
13003                }
13004                let (cursor, goal) = movement::up(
13005                    map,
13006                    selection.start,
13007                    selection.goal,
13008                    false,
13009                    text_layout_details,
13010                );
13011                selection.collapse_to(cursor, goal);
13012            });
13013        });
13014
13015        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13016        {
13017            cx.propagate();
13018        }
13019    }
13020
13021    pub fn move_up_by_lines(
13022        &mut self,
13023        action: &MoveUpByLines,
13024        window: &mut Window,
13025        cx: &mut Context<Self>,
13026    ) {
13027        if self.take_rename(true, window, cx).is_some() {
13028            return;
13029        }
13030
13031        if self.mode.is_single_line() {
13032            cx.propagate();
13033            return;
13034        }
13035
13036        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13037
13038        let text_layout_details = &self.text_layout_details(window);
13039
13040        self.change_selections(Default::default(), window, cx, |s| {
13041            s.move_with(|map, selection| {
13042                if !selection.is_empty() {
13043                    selection.goal = SelectionGoal::None;
13044                }
13045                let (cursor, goal) = movement::up_by_rows(
13046                    map,
13047                    selection.start,
13048                    action.lines,
13049                    selection.goal,
13050                    false,
13051                    text_layout_details,
13052                );
13053                selection.collapse_to(cursor, goal);
13054            });
13055        })
13056    }
13057
13058    pub fn move_down_by_lines(
13059        &mut self,
13060        action: &MoveDownByLines,
13061        window: &mut Window,
13062        cx: &mut Context<Self>,
13063    ) {
13064        if self.take_rename(true, window, cx).is_some() {
13065            return;
13066        }
13067
13068        if self.mode.is_single_line() {
13069            cx.propagate();
13070            return;
13071        }
13072
13073        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13074
13075        let text_layout_details = &self.text_layout_details(window);
13076
13077        self.change_selections(Default::default(), window, cx, |s| {
13078            s.move_with(|map, selection| {
13079                if !selection.is_empty() {
13080                    selection.goal = SelectionGoal::None;
13081                }
13082                let (cursor, goal) = movement::down_by_rows(
13083                    map,
13084                    selection.start,
13085                    action.lines,
13086                    selection.goal,
13087                    false,
13088                    text_layout_details,
13089                );
13090                selection.collapse_to(cursor, goal);
13091            });
13092        })
13093    }
13094
13095    pub fn select_down_by_lines(
13096        &mut self,
13097        action: &SelectDownByLines,
13098        window: &mut Window,
13099        cx: &mut Context<Self>,
13100    ) {
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::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13106            })
13107        })
13108    }
13109
13110    pub fn select_up_by_lines(
13111        &mut self,
13112        action: &SelectUpByLines,
13113        window: &mut Window,
13114        cx: &mut Context<Self>,
13115    ) {
13116        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13117        let text_layout_details = &self.text_layout_details(window);
13118        self.change_selections(Default::default(), window, cx, |s| {
13119            s.move_heads_with(|map, head, goal| {
13120                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13121            })
13122        })
13123    }
13124
13125    pub fn select_page_up(
13126        &mut self,
13127        _: &SelectPageUp,
13128        window: &mut Window,
13129        cx: &mut Context<Self>,
13130    ) {
13131        let Some(row_count) = self.visible_row_count() else {
13132            return;
13133        };
13134
13135        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13136
13137        let text_layout_details = &self.text_layout_details(window);
13138
13139        self.change_selections(Default::default(), window, cx, |s| {
13140            s.move_heads_with(|map, head, goal| {
13141                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13142            })
13143        })
13144    }
13145
13146    pub fn move_page_up(
13147        &mut self,
13148        action: &MovePageUp,
13149        window: &mut Window,
13150        cx: &mut Context<Self>,
13151    ) {
13152        if self.take_rename(true, window, cx).is_some() {
13153            return;
13154        }
13155
13156        if self
13157            .context_menu
13158            .borrow_mut()
13159            .as_mut()
13160            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13161            .unwrap_or(false)
13162        {
13163            return;
13164        }
13165
13166        if matches!(self.mode, EditorMode::SingleLine) {
13167            cx.propagate();
13168            return;
13169        }
13170
13171        let Some(row_count) = self.visible_row_count() else {
13172            return;
13173        };
13174
13175        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13176
13177        let effects = if action.center_cursor {
13178            SelectionEffects::scroll(Autoscroll::center())
13179        } else {
13180            SelectionEffects::default()
13181        };
13182
13183        let text_layout_details = &self.text_layout_details(window);
13184
13185        self.change_selections(effects, window, cx, |s| {
13186            s.move_with(|map, selection| {
13187                if !selection.is_empty() {
13188                    selection.goal = SelectionGoal::None;
13189                }
13190                let (cursor, goal) = movement::up_by_rows(
13191                    map,
13192                    selection.end,
13193                    row_count,
13194                    selection.goal,
13195                    false,
13196                    text_layout_details,
13197                );
13198                selection.collapse_to(cursor, goal);
13199            });
13200        });
13201    }
13202
13203    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13204        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13205        let text_layout_details = &self.text_layout_details(window);
13206        self.change_selections(Default::default(), window, cx, |s| {
13207            s.move_heads_with(|map, head, goal| {
13208                movement::up(map, head, goal, false, text_layout_details)
13209            })
13210        })
13211    }
13212
13213    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13214        self.take_rename(true, window, cx);
13215
13216        if self.mode.is_single_line() {
13217            cx.propagate();
13218            return;
13219        }
13220
13221        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13222
13223        let text_layout_details = &self.text_layout_details(window);
13224        let selection_count = self.selections.count();
13225        let first_selection = self.selections.first_anchor();
13226
13227        self.change_selections(Default::default(), window, cx, |s| {
13228            s.move_with(|map, selection| {
13229                if !selection.is_empty() {
13230                    selection.goal = SelectionGoal::None;
13231                }
13232                let (cursor, goal) = movement::down(
13233                    map,
13234                    selection.end,
13235                    selection.goal,
13236                    false,
13237                    text_layout_details,
13238                );
13239                selection.collapse_to(cursor, goal);
13240            });
13241        });
13242
13243        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13244        {
13245            cx.propagate();
13246        }
13247    }
13248
13249    pub fn select_page_down(
13250        &mut self,
13251        _: &SelectPageDown,
13252        window: &mut Window,
13253        cx: &mut Context<Self>,
13254    ) {
13255        let Some(row_count) = self.visible_row_count() else {
13256            return;
13257        };
13258
13259        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13260
13261        let text_layout_details = &self.text_layout_details(window);
13262
13263        self.change_selections(Default::default(), window, cx, |s| {
13264            s.move_heads_with(|map, head, goal| {
13265                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13266            })
13267        })
13268    }
13269
13270    pub fn move_page_down(
13271        &mut self,
13272        action: &MovePageDown,
13273        window: &mut Window,
13274        cx: &mut Context<Self>,
13275    ) {
13276        if self.take_rename(true, window, cx).is_some() {
13277            return;
13278        }
13279
13280        if self
13281            .context_menu
13282            .borrow_mut()
13283            .as_mut()
13284            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13285            .unwrap_or(false)
13286        {
13287            return;
13288        }
13289
13290        if matches!(self.mode, EditorMode::SingleLine) {
13291            cx.propagate();
13292            return;
13293        }
13294
13295        let Some(row_count) = self.visible_row_count() else {
13296            return;
13297        };
13298
13299        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13300
13301        let effects = if action.center_cursor {
13302            SelectionEffects::scroll(Autoscroll::center())
13303        } else {
13304            SelectionEffects::default()
13305        };
13306
13307        let text_layout_details = &self.text_layout_details(window);
13308        self.change_selections(effects, window, cx, |s| {
13309            s.move_with(|map, selection| {
13310                if !selection.is_empty() {
13311                    selection.goal = SelectionGoal::None;
13312                }
13313                let (cursor, goal) = movement::down_by_rows(
13314                    map,
13315                    selection.end,
13316                    row_count,
13317                    selection.goal,
13318                    false,
13319                    text_layout_details,
13320                );
13321                selection.collapse_to(cursor, goal);
13322            });
13323        });
13324    }
13325
13326    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13327        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13328        let text_layout_details = &self.text_layout_details(window);
13329        self.change_selections(Default::default(), window, cx, |s| {
13330            s.move_heads_with(|map, head, goal| {
13331                movement::down(map, head, goal, false, text_layout_details)
13332            })
13333        });
13334    }
13335
13336    pub fn context_menu_first(
13337        &mut self,
13338        _: &ContextMenuFirst,
13339        window: &mut Window,
13340        cx: &mut Context<Self>,
13341    ) {
13342        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13343            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13344        }
13345    }
13346
13347    pub fn context_menu_prev(
13348        &mut self,
13349        _: &ContextMenuPrevious,
13350        window: &mut Window,
13351        cx: &mut Context<Self>,
13352    ) {
13353        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13354            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13355        }
13356    }
13357
13358    pub fn context_menu_next(
13359        &mut self,
13360        _: &ContextMenuNext,
13361        window: &mut Window,
13362        cx: &mut Context<Self>,
13363    ) {
13364        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13365            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13366        }
13367    }
13368
13369    pub fn context_menu_last(
13370        &mut self,
13371        _: &ContextMenuLast,
13372        window: &mut Window,
13373        cx: &mut Context<Self>,
13374    ) {
13375        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13376            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13377        }
13378    }
13379
13380    pub fn signature_help_prev(
13381        &mut self,
13382        _: &SignatureHelpPrevious,
13383        _: &mut Window,
13384        cx: &mut Context<Self>,
13385    ) {
13386        if let Some(popover) = self.signature_help_state.popover_mut() {
13387            if popover.current_signature == 0 {
13388                popover.current_signature = popover.signatures.len() - 1;
13389            } else {
13390                popover.current_signature -= 1;
13391            }
13392            cx.notify();
13393        }
13394    }
13395
13396    pub fn signature_help_next(
13397        &mut self,
13398        _: &SignatureHelpNext,
13399        _: &mut Window,
13400        cx: &mut Context<Self>,
13401    ) {
13402        if let Some(popover) = self.signature_help_state.popover_mut() {
13403            if popover.current_signature + 1 == popover.signatures.len() {
13404                popover.current_signature = 0;
13405            } else {
13406                popover.current_signature += 1;
13407            }
13408            cx.notify();
13409        }
13410    }
13411
13412    pub fn move_to_previous_word_start(
13413        &mut self,
13414        _: &MoveToPreviousWordStart,
13415        window: &mut Window,
13416        cx: &mut Context<Self>,
13417    ) {
13418        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13419        self.change_selections(Default::default(), window, cx, |s| {
13420            s.move_cursors_with(|map, head, _| {
13421                (
13422                    movement::previous_word_start(map, head),
13423                    SelectionGoal::None,
13424                )
13425            });
13426        })
13427    }
13428
13429    pub fn move_to_previous_subword_start(
13430        &mut self,
13431        _: &MoveToPreviousSubwordStart,
13432        window: &mut Window,
13433        cx: &mut Context<Self>,
13434    ) {
13435        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13436        self.change_selections(Default::default(), window, cx, |s| {
13437            s.move_cursors_with(|map, head, _| {
13438                (
13439                    movement::previous_subword_start(map, head),
13440                    SelectionGoal::None,
13441                )
13442            });
13443        })
13444    }
13445
13446    pub fn select_to_previous_word_start(
13447        &mut self,
13448        _: &SelectToPreviousWordStart,
13449        window: &mut Window,
13450        cx: &mut Context<Self>,
13451    ) {
13452        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13453        self.change_selections(Default::default(), window, cx, |s| {
13454            s.move_heads_with(|map, head, _| {
13455                (
13456                    movement::previous_word_start(map, head),
13457                    SelectionGoal::None,
13458                )
13459            });
13460        })
13461    }
13462
13463    pub fn select_to_previous_subword_start(
13464        &mut self,
13465        _: &SelectToPreviousSubwordStart,
13466        window: &mut Window,
13467        cx: &mut Context<Self>,
13468    ) {
13469        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13470        self.change_selections(Default::default(), window, cx, |s| {
13471            s.move_heads_with(|map, head, _| {
13472                (
13473                    movement::previous_subword_start(map, head),
13474                    SelectionGoal::None,
13475                )
13476            });
13477        })
13478    }
13479
13480    pub fn delete_to_previous_word_start(
13481        &mut self,
13482        action: &DeleteToPreviousWordStart,
13483        window: &mut Window,
13484        cx: &mut Context<Self>,
13485    ) {
13486        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13487        self.transact(window, cx, |this, window, cx| {
13488            this.select_autoclose_pair(window, cx);
13489            this.change_selections(Default::default(), window, cx, |s| {
13490                s.move_with(|map, selection| {
13491                    if selection.is_empty() {
13492                        let mut cursor = if action.ignore_newlines {
13493                            movement::previous_word_start(map, selection.head())
13494                        } else {
13495                            movement::previous_word_start_or_newline(map, selection.head())
13496                        };
13497                        cursor = movement::adjust_greedy_deletion(
13498                            map,
13499                            selection.head(),
13500                            cursor,
13501                            action.ignore_brackets,
13502                        );
13503                        selection.set_head(cursor, SelectionGoal::None);
13504                    }
13505                });
13506            });
13507            this.insert("", window, cx);
13508        });
13509    }
13510
13511    pub fn delete_to_previous_subword_start(
13512        &mut self,
13513        _: &DeleteToPreviousSubwordStart,
13514        window: &mut Window,
13515        cx: &mut Context<Self>,
13516    ) {
13517        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13518        self.transact(window, cx, |this, window, cx| {
13519            this.select_autoclose_pair(window, cx);
13520            this.change_selections(Default::default(), window, cx, |s| {
13521                s.move_with(|map, selection| {
13522                    if selection.is_empty() {
13523                        let mut cursor = movement::previous_subword_start(map, selection.head());
13524                        cursor =
13525                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13526                        selection.set_head(cursor, SelectionGoal::None);
13527                    }
13528                });
13529            });
13530            this.insert("", window, cx);
13531        });
13532    }
13533
13534    pub fn move_to_next_word_end(
13535        &mut self,
13536        _: &MoveToNextWordEnd,
13537        window: &mut Window,
13538        cx: &mut Context<Self>,
13539    ) {
13540        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13541        self.change_selections(Default::default(), window, cx, |s| {
13542            s.move_cursors_with(|map, head, _| {
13543                (movement::next_word_end(map, head), SelectionGoal::None)
13544            });
13545        })
13546    }
13547
13548    pub fn move_to_next_subword_end(
13549        &mut self,
13550        _: &MoveToNextSubwordEnd,
13551        window: &mut Window,
13552        cx: &mut Context<Self>,
13553    ) {
13554        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13555        self.change_selections(Default::default(), window, cx, |s| {
13556            s.move_cursors_with(|map, head, _| {
13557                (movement::next_subword_end(map, head), SelectionGoal::None)
13558            });
13559        })
13560    }
13561
13562    pub fn select_to_next_word_end(
13563        &mut self,
13564        _: &SelectToNextWordEnd,
13565        window: &mut Window,
13566        cx: &mut Context<Self>,
13567    ) {
13568        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13569        self.change_selections(Default::default(), window, cx, |s| {
13570            s.move_heads_with(|map, head, _| {
13571                (movement::next_word_end(map, head), SelectionGoal::None)
13572            });
13573        })
13574    }
13575
13576    pub fn select_to_next_subword_end(
13577        &mut self,
13578        _: &SelectToNextSubwordEnd,
13579        window: &mut Window,
13580        cx: &mut Context<Self>,
13581    ) {
13582        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13583        self.change_selections(Default::default(), window, cx, |s| {
13584            s.move_heads_with(|map, head, _| {
13585                (movement::next_subword_end(map, head), SelectionGoal::None)
13586            });
13587        })
13588    }
13589
13590    pub fn delete_to_next_word_end(
13591        &mut self,
13592        action: &DeleteToNextWordEnd,
13593        window: &mut Window,
13594        cx: &mut Context<Self>,
13595    ) {
13596        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13597        self.transact(window, cx, |this, window, cx| {
13598            this.change_selections(Default::default(), window, cx, |s| {
13599                s.move_with(|map, selection| {
13600                    if selection.is_empty() {
13601                        let mut cursor = if action.ignore_newlines {
13602                            movement::next_word_end(map, selection.head())
13603                        } else {
13604                            movement::next_word_end_or_newline(map, selection.head())
13605                        };
13606                        cursor = movement::adjust_greedy_deletion(
13607                            map,
13608                            selection.head(),
13609                            cursor,
13610                            action.ignore_brackets,
13611                        );
13612                        selection.set_head(cursor, SelectionGoal::None);
13613                    }
13614                });
13615            });
13616            this.insert("", window, cx);
13617        });
13618    }
13619
13620    pub fn delete_to_next_subword_end(
13621        &mut self,
13622        _: &DeleteToNextSubwordEnd,
13623        window: &mut Window,
13624        cx: &mut Context<Self>,
13625    ) {
13626        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13627        self.transact(window, cx, |this, window, cx| {
13628            this.change_selections(Default::default(), window, cx, |s| {
13629                s.move_with(|map, selection| {
13630                    if selection.is_empty() {
13631                        let mut cursor = movement::next_subword_end(map, selection.head());
13632                        cursor =
13633                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13634                        selection.set_head(cursor, SelectionGoal::None);
13635                    }
13636                });
13637            });
13638            this.insert("", window, cx);
13639        });
13640    }
13641
13642    pub fn move_to_beginning_of_line(
13643        &mut self,
13644        action: &MoveToBeginningOfLine,
13645        window: &mut Window,
13646        cx: &mut Context<Self>,
13647    ) {
13648        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13649        self.change_selections(Default::default(), window, cx, |s| {
13650            s.move_cursors_with(|map, head, _| {
13651                (
13652                    movement::indented_line_beginning(
13653                        map,
13654                        head,
13655                        action.stop_at_soft_wraps,
13656                        action.stop_at_indent,
13657                    ),
13658                    SelectionGoal::None,
13659                )
13660            });
13661        })
13662    }
13663
13664    pub fn select_to_beginning_of_line(
13665        &mut self,
13666        action: &SelectToBeginningOfLine,
13667        window: &mut Window,
13668        cx: &mut Context<Self>,
13669    ) {
13670        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13671        self.change_selections(Default::default(), window, cx, |s| {
13672            s.move_heads_with(|map, head, _| {
13673                (
13674                    movement::indented_line_beginning(
13675                        map,
13676                        head,
13677                        action.stop_at_soft_wraps,
13678                        action.stop_at_indent,
13679                    ),
13680                    SelectionGoal::None,
13681                )
13682            });
13683        });
13684    }
13685
13686    pub fn delete_to_beginning_of_line(
13687        &mut self,
13688        action: &DeleteToBeginningOfLine,
13689        window: &mut Window,
13690        cx: &mut Context<Self>,
13691    ) {
13692        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13693        self.transact(window, cx, |this, window, cx| {
13694            this.change_selections(Default::default(), window, cx, |s| {
13695                s.move_with(|_, selection| {
13696                    selection.reversed = true;
13697                });
13698            });
13699
13700            this.select_to_beginning_of_line(
13701                &SelectToBeginningOfLine {
13702                    stop_at_soft_wraps: false,
13703                    stop_at_indent: action.stop_at_indent,
13704                },
13705                window,
13706                cx,
13707            );
13708            this.backspace(&Backspace, window, cx);
13709        });
13710    }
13711
13712    pub fn move_to_end_of_line(
13713        &mut self,
13714        action: &MoveToEndOfLine,
13715        window: &mut Window,
13716        cx: &mut Context<Self>,
13717    ) {
13718        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13719        self.change_selections(Default::default(), window, cx, |s| {
13720            s.move_cursors_with(|map, head, _| {
13721                (
13722                    movement::line_end(map, head, action.stop_at_soft_wraps),
13723                    SelectionGoal::None,
13724                )
13725            });
13726        })
13727    }
13728
13729    pub fn select_to_end_of_line(
13730        &mut self,
13731        action: &SelectToEndOfLine,
13732        window: &mut Window,
13733        cx: &mut Context<Self>,
13734    ) {
13735        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13736        self.change_selections(Default::default(), window, cx, |s| {
13737            s.move_heads_with(|map, head, _| {
13738                (
13739                    movement::line_end(map, head, action.stop_at_soft_wraps),
13740                    SelectionGoal::None,
13741                )
13742            });
13743        })
13744    }
13745
13746    pub fn delete_to_end_of_line(
13747        &mut self,
13748        _: &DeleteToEndOfLine,
13749        window: &mut Window,
13750        cx: &mut Context<Self>,
13751    ) {
13752        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13753        self.transact(window, cx, |this, window, cx| {
13754            this.select_to_end_of_line(
13755                &SelectToEndOfLine {
13756                    stop_at_soft_wraps: false,
13757                },
13758                window,
13759                cx,
13760            );
13761            this.delete(&Delete, window, cx);
13762        });
13763    }
13764
13765    pub fn cut_to_end_of_line(
13766        &mut self,
13767        action: &CutToEndOfLine,
13768        window: &mut Window,
13769        cx: &mut Context<Self>,
13770    ) {
13771        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13772        self.transact(window, cx, |this, window, cx| {
13773            this.select_to_end_of_line(
13774                &SelectToEndOfLine {
13775                    stop_at_soft_wraps: false,
13776                },
13777                window,
13778                cx,
13779            );
13780            if !action.stop_at_newlines {
13781                this.change_selections(Default::default(), window, cx, |s| {
13782                    s.move_with(|_, sel| {
13783                        if sel.is_empty() {
13784                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13785                        }
13786                    });
13787                });
13788            }
13789            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13790            let item = this.cut_common(false, window, cx);
13791            cx.write_to_clipboard(item);
13792        });
13793    }
13794
13795    pub fn move_to_start_of_paragraph(
13796        &mut self,
13797        _: &MoveToStartOfParagraph,
13798        window: &mut Window,
13799        cx: &mut Context<Self>,
13800    ) {
13801        if matches!(self.mode, EditorMode::SingleLine) {
13802            cx.propagate();
13803            return;
13804        }
13805        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13806        self.change_selections(Default::default(), window, cx, |s| {
13807            s.move_with(|map, selection| {
13808                selection.collapse_to(
13809                    movement::start_of_paragraph(map, selection.head(), 1),
13810                    SelectionGoal::None,
13811                )
13812            });
13813        })
13814    }
13815
13816    pub fn move_to_end_of_paragraph(
13817        &mut self,
13818        _: &MoveToEndOfParagraph,
13819        window: &mut Window,
13820        cx: &mut Context<Self>,
13821    ) {
13822        if matches!(self.mode, EditorMode::SingleLine) {
13823            cx.propagate();
13824            return;
13825        }
13826        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13827        self.change_selections(Default::default(), window, cx, |s| {
13828            s.move_with(|map, selection| {
13829                selection.collapse_to(
13830                    movement::end_of_paragraph(map, selection.head(), 1),
13831                    SelectionGoal::None,
13832                )
13833            });
13834        })
13835    }
13836
13837    pub fn select_to_start_of_paragraph(
13838        &mut self,
13839        _: &SelectToStartOfParagraph,
13840        window: &mut Window,
13841        cx: &mut Context<Self>,
13842    ) {
13843        if matches!(self.mode, EditorMode::SingleLine) {
13844            cx.propagate();
13845            return;
13846        }
13847        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13848        self.change_selections(Default::default(), window, cx, |s| {
13849            s.move_heads_with(|map, head, _| {
13850                (
13851                    movement::start_of_paragraph(map, head, 1),
13852                    SelectionGoal::None,
13853                )
13854            });
13855        })
13856    }
13857
13858    pub fn select_to_end_of_paragraph(
13859        &mut self,
13860        _: &SelectToEndOfParagraph,
13861        window: &mut Window,
13862        cx: &mut Context<Self>,
13863    ) {
13864        if matches!(self.mode, EditorMode::SingleLine) {
13865            cx.propagate();
13866            return;
13867        }
13868        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13869        self.change_selections(Default::default(), window, cx, |s| {
13870            s.move_heads_with(|map, head, _| {
13871                (
13872                    movement::end_of_paragraph(map, head, 1),
13873                    SelectionGoal::None,
13874                )
13875            });
13876        })
13877    }
13878
13879    pub fn move_to_start_of_excerpt(
13880        &mut self,
13881        _: &MoveToStartOfExcerpt,
13882        window: &mut Window,
13883        cx: &mut Context<Self>,
13884    ) {
13885        if matches!(self.mode, EditorMode::SingleLine) {
13886            cx.propagate();
13887            return;
13888        }
13889        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13890        self.change_selections(Default::default(), window, cx, |s| {
13891            s.move_with(|map, selection| {
13892                selection.collapse_to(
13893                    movement::start_of_excerpt(
13894                        map,
13895                        selection.head(),
13896                        workspace::searchable::Direction::Prev,
13897                    ),
13898                    SelectionGoal::None,
13899                )
13900            });
13901        })
13902    }
13903
13904    pub fn move_to_start_of_next_excerpt(
13905        &mut self,
13906        _: &MoveToStartOfNextExcerpt,
13907        window: &mut Window,
13908        cx: &mut Context<Self>,
13909    ) {
13910        if matches!(self.mode, EditorMode::SingleLine) {
13911            cx.propagate();
13912            return;
13913        }
13914
13915        self.change_selections(Default::default(), window, cx, |s| {
13916            s.move_with(|map, selection| {
13917                selection.collapse_to(
13918                    movement::start_of_excerpt(
13919                        map,
13920                        selection.head(),
13921                        workspace::searchable::Direction::Next,
13922                    ),
13923                    SelectionGoal::None,
13924                )
13925            });
13926        })
13927    }
13928
13929    pub fn move_to_end_of_excerpt(
13930        &mut self,
13931        _: &MoveToEndOfExcerpt,
13932        window: &mut Window,
13933        cx: &mut Context<Self>,
13934    ) {
13935        if matches!(self.mode, EditorMode::SingleLine) {
13936            cx.propagate();
13937            return;
13938        }
13939        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13940        self.change_selections(Default::default(), window, cx, |s| {
13941            s.move_with(|map, selection| {
13942                selection.collapse_to(
13943                    movement::end_of_excerpt(
13944                        map,
13945                        selection.head(),
13946                        workspace::searchable::Direction::Next,
13947                    ),
13948                    SelectionGoal::None,
13949                )
13950            });
13951        })
13952    }
13953
13954    pub fn move_to_end_of_previous_excerpt(
13955        &mut self,
13956        _: &MoveToEndOfPreviousExcerpt,
13957        window: &mut Window,
13958        cx: &mut Context<Self>,
13959    ) {
13960        if matches!(self.mode, EditorMode::SingleLine) {
13961            cx.propagate();
13962            return;
13963        }
13964        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13965        self.change_selections(Default::default(), window, cx, |s| {
13966            s.move_with(|map, selection| {
13967                selection.collapse_to(
13968                    movement::end_of_excerpt(
13969                        map,
13970                        selection.head(),
13971                        workspace::searchable::Direction::Prev,
13972                    ),
13973                    SelectionGoal::None,
13974                )
13975            });
13976        })
13977    }
13978
13979    pub fn select_to_start_of_excerpt(
13980        &mut self,
13981        _: &SelectToStartOfExcerpt,
13982        window: &mut Window,
13983        cx: &mut Context<Self>,
13984    ) {
13985        if matches!(self.mode, EditorMode::SingleLine) {
13986            cx.propagate();
13987            return;
13988        }
13989        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13990        self.change_selections(Default::default(), window, cx, |s| {
13991            s.move_heads_with(|map, head, _| {
13992                (
13993                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13994                    SelectionGoal::None,
13995                )
13996            });
13997        })
13998    }
13999
14000    pub fn select_to_start_of_next_excerpt(
14001        &mut self,
14002        _: &SelectToStartOfNextExcerpt,
14003        window: &mut Window,
14004        cx: &mut Context<Self>,
14005    ) {
14006        if matches!(self.mode, EditorMode::SingleLine) {
14007            cx.propagate();
14008            return;
14009        }
14010        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14011        self.change_selections(Default::default(), window, cx, |s| {
14012            s.move_heads_with(|map, head, _| {
14013                (
14014                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14015                    SelectionGoal::None,
14016                )
14017            });
14018        })
14019    }
14020
14021    pub fn select_to_end_of_excerpt(
14022        &mut self,
14023        _: &SelectToEndOfExcerpt,
14024        window: &mut Window,
14025        cx: &mut Context<Self>,
14026    ) {
14027        if matches!(self.mode, EditorMode::SingleLine) {
14028            cx.propagate();
14029            return;
14030        }
14031        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14032        self.change_selections(Default::default(), window, cx, |s| {
14033            s.move_heads_with(|map, head, _| {
14034                (
14035                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14036                    SelectionGoal::None,
14037                )
14038            });
14039        })
14040    }
14041
14042    pub fn select_to_end_of_previous_excerpt(
14043        &mut self,
14044        _: &SelectToEndOfPreviousExcerpt,
14045        window: &mut Window,
14046        cx: &mut Context<Self>,
14047    ) {
14048        if matches!(self.mode, EditorMode::SingleLine) {
14049            cx.propagate();
14050            return;
14051        }
14052        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14053        self.change_selections(Default::default(), window, cx, |s| {
14054            s.move_heads_with(|map, head, _| {
14055                (
14056                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14057                    SelectionGoal::None,
14058                )
14059            });
14060        })
14061    }
14062
14063    pub fn move_to_beginning(
14064        &mut self,
14065        _: &MoveToBeginning,
14066        window: &mut Window,
14067        cx: &mut Context<Self>,
14068    ) {
14069        if matches!(self.mode, EditorMode::SingleLine) {
14070            cx.propagate();
14071            return;
14072        }
14073        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14074        self.change_selections(Default::default(), window, cx, |s| {
14075            s.select_ranges(vec![0..0]);
14076        });
14077    }
14078
14079    pub fn select_to_beginning(
14080        &mut self,
14081        _: &SelectToBeginning,
14082        window: &mut Window,
14083        cx: &mut Context<Self>,
14084    ) {
14085        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14086        selection.set_head(Point::zero(), SelectionGoal::None);
14087        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14088        self.change_selections(Default::default(), window, cx, |s| {
14089            s.select(vec![selection]);
14090        });
14091    }
14092
14093    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14094        if matches!(self.mode, EditorMode::SingleLine) {
14095            cx.propagate();
14096            return;
14097        }
14098        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14099        let cursor = self.buffer.read(cx).read(cx).len();
14100        self.change_selections(Default::default(), window, cx, |s| {
14101            s.select_ranges(vec![cursor..cursor])
14102        });
14103    }
14104
14105    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14106        self.nav_history = nav_history;
14107    }
14108
14109    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14110        self.nav_history.as_ref()
14111    }
14112
14113    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14114        self.push_to_nav_history(
14115            self.selections.newest_anchor().head(),
14116            None,
14117            false,
14118            true,
14119            cx,
14120        );
14121    }
14122
14123    fn push_to_nav_history(
14124        &mut self,
14125        cursor_anchor: Anchor,
14126        new_position: Option<Point>,
14127        is_deactivate: bool,
14128        always: bool,
14129        cx: &mut Context<Self>,
14130    ) {
14131        if let Some(nav_history) = self.nav_history.as_mut() {
14132            let buffer = self.buffer.read(cx).read(cx);
14133            let cursor_position = cursor_anchor.to_point(&buffer);
14134            let scroll_state = self.scroll_manager.anchor();
14135            let scroll_top_row = scroll_state.top_row(&buffer);
14136            drop(buffer);
14137
14138            if let Some(new_position) = new_position {
14139                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14140                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14141                    return;
14142                }
14143            }
14144
14145            nav_history.push(
14146                Some(NavigationData {
14147                    cursor_anchor,
14148                    cursor_position,
14149                    scroll_anchor: scroll_state,
14150                    scroll_top_row,
14151                }),
14152                cx,
14153            );
14154            cx.emit(EditorEvent::PushedToNavHistory {
14155                anchor: cursor_anchor,
14156                is_deactivate,
14157            })
14158        }
14159    }
14160
14161    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14162        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14163        let buffer = self.buffer.read(cx).snapshot(cx);
14164        let mut selection = self.selections.first::<usize>(&self.display_snapshot(cx));
14165        selection.set_head(buffer.len(), SelectionGoal::None);
14166        self.change_selections(Default::default(), window, cx, |s| {
14167            s.select(vec![selection]);
14168        });
14169    }
14170
14171    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14172        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14173        let end = self.buffer.read(cx).read(cx).len();
14174        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14175            s.select_ranges(vec![0..end]);
14176        });
14177    }
14178
14179    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14180        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14181        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14182        let mut selections = self.selections.all::<Point>(&display_map);
14183        let max_point = display_map.buffer_snapshot().max_point();
14184        for selection in &mut selections {
14185            let rows = selection.spanned_rows(true, &display_map);
14186            selection.start = Point::new(rows.start.0, 0);
14187            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14188            selection.reversed = false;
14189        }
14190        self.change_selections(Default::default(), window, cx, |s| {
14191            s.select(selections);
14192        });
14193    }
14194
14195    pub fn split_selection_into_lines(
14196        &mut self,
14197        action: &SplitSelectionIntoLines,
14198        window: &mut Window,
14199        cx: &mut Context<Self>,
14200    ) {
14201        let selections = self
14202            .selections
14203            .all::<Point>(&self.display_snapshot(cx))
14204            .into_iter()
14205            .map(|selection| selection.start..selection.end)
14206            .collect::<Vec<_>>();
14207        self.unfold_ranges(&selections, true, true, cx);
14208
14209        let mut new_selection_ranges = Vec::new();
14210        {
14211            let buffer = self.buffer.read(cx).read(cx);
14212            for selection in selections {
14213                for row in selection.start.row..selection.end.row {
14214                    let line_start = Point::new(row, 0);
14215                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14216
14217                    if action.keep_selections {
14218                        // Keep the selection range for each line
14219                        let selection_start = if row == selection.start.row {
14220                            selection.start
14221                        } else {
14222                            line_start
14223                        };
14224                        new_selection_ranges.push(selection_start..line_end);
14225                    } else {
14226                        // Collapse to cursor at end of line
14227                        new_selection_ranges.push(line_end..line_end);
14228                    }
14229                }
14230
14231                let is_multiline_selection = selection.start.row != selection.end.row;
14232                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14233                // so this action feels more ergonomic when paired with other selection operations
14234                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14235                if !should_skip_last {
14236                    if action.keep_selections {
14237                        if is_multiline_selection {
14238                            let line_start = Point::new(selection.end.row, 0);
14239                            new_selection_ranges.push(line_start..selection.end);
14240                        } else {
14241                            new_selection_ranges.push(selection.start..selection.end);
14242                        }
14243                    } else {
14244                        new_selection_ranges.push(selection.end..selection.end);
14245                    }
14246                }
14247            }
14248        }
14249        self.change_selections(Default::default(), window, cx, |s| {
14250            s.select_ranges(new_selection_ranges);
14251        });
14252    }
14253
14254    pub fn add_selection_above(
14255        &mut self,
14256        action: &AddSelectionAbove,
14257        window: &mut Window,
14258        cx: &mut Context<Self>,
14259    ) {
14260        self.add_selection(true, action.skip_soft_wrap, window, cx);
14261    }
14262
14263    pub fn add_selection_below(
14264        &mut self,
14265        action: &AddSelectionBelow,
14266        window: &mut Window,
14267        cx: &mut Context<Self>,
14268    ) {
14269        self.add_selection(false, action.skip_soft_wrap, window, cx);
14270    }
14271
14272    fn add_selection(
14273        &mut self,
14274        above: bool,
14275        skip_soft_wrap: bool,
14276        window: &mut Window,
14277        cx: &mut Context<Self>,
14278    ) {
14279        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14280
14281        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14282        let all_selections = self.selections.all::<Point>(&display_map);
14283        let text_layout_details = self.text_layout_details(window);
14284
14285        let (mut columnar_selections, new_selections_to_columnarize) = {
14286            if let Some(state) = self.add_selections_state.as_ref() {
14287                let columnar_selection_ids: HashSet<_> = state
14288                    .groups
14289                    .iter()
14290                    .flat_map(|group| group.stack.iter())
14291                    .copied()
14292                    .collect();
14293
14294                all_selections
14295                    .into_iter()
14296                    .partition(|s| columnar_selection_ids.contains(&s.id))
14297            } else {
14298                (Vec::new(), all_selections)
14299            }
14300        };
14301
14302        let mut state = self
14303            .add_selections_state
14304            .take()
14305            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14306
14307        for selection in new_selections_to_columnarize {
14308            let range = selection.display_range(&display_map).sorted();
14309            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14310            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14311            let positions = start_x.min(end_x)..start_x.max(end_x);
14312            let mut stack = Vec::new();
14313            for row in range.start.row().0..=range.end.row().0 {
14314                if let Some(selection) = self.selections.build_columnar_selection(
14315                    &display_map,
14316                    DisplayRow(row),
14317                    &positions,
14318                    selection.reversed,
14319                    &text_layout_details,
14320                ) {
14321                    stack.push(selection.id);
14322                    columnar_selections.push(selection);
14323                }
14324            }
14325            if !stack.is_empty() {
14326                if above {
14327                    stack.reverse();
14328                }
14329                state.groups.push(AddSelectionsGroup { above, stack });
14330            }
14331        }
14332
14333        let mut final_selections = Vec::new();
14334        let end_row = if above {
14335            DisplayRow(0)
14336        } else {
14337            display_map.max_point().row()
14338        };
14339
14340        let mut last_added_item_per_group = HashMap::default();
14341        for group in state.groups.iter_mut() {
14342            if let Some(last_id) = group.stack.last() {
14343                last_added_item_per_group.insert(*last_id, group);
14344            }
14345        }
14346
14347        for selection in columnar_selections {
14348            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14349                if above == group.above {
14350                    let range = selection.display_range(&display_map).sorted();
14351                    debug_assert_eq!(range.start.row(), range.end.row());
14352                    let mut row = range.start.row();
14353                    let positions =
14354                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14355                            Pixels::from(start)..Pixels::from(end)
14356                        } else {
14357                            let start_x =
14358                                display_map.x_for_display_point(range.start, &text_layout_details);
14359                            let end_x =
14360                                display_map.x_for_display_point(range.end, &text_layout_details);
14361                            start_x.min(end_x)..start_x.max(end_x)
14362                        };
14363
14364                    let mut maybe_new_selection = None;
14365                    let direction = if above { -1 } else { 1 };
14366
14367                    while row != end_row {
14368                        if skip_soft_wrap {
14369                            row = display_map
14370                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14371                                .row();
14372                        } else if above {
14373                            row.0 -= 1;
14374                        } else {
14375                            row.0 += 1;
14376                        }
14377
14378                        if let Some(new_selection) = self.selections.build_columnar_selection(
14379                            &display_map,
14380                            row,
14381                            &positions,
14382                            selection.reversed,
14383                            &text_layout_details,
14384                        ) {
14385                            maybe_new_selection = Some(new_selection);
14386                            break;
14387                        }
14388                    }
14389
14390                    if let Some(new_selection) = maybe_new_selection {
14391                        group.stack.push(new_selection.id);
14392                        if above {
14393                            final_selections.push(new_selection);
14394                            final_selections.push(selection);
14395                        } else {
14396                            final_selections.push(selection);
14397                            final_selections.push(new_selection);
14398                        }
14399                    } else {
14400                        final_selections.push(selection);
14401                    }
14402                } else {
14403                    group.stack.pop();
14404                }
14405            } else {
14406                final_selections.push(selection);
14407            }
14408        }
14409
14410        self.change_selections(Default::default(), window, cx, |s| {
14411            s.select(final_selections);
14412        });
14413
14414        let final_selection_ids: HashSet<_> = self
14415            .selections
14416            .all::<Point>(&display_map)
14417            .iter()
14418            .map(|s| s.id)
14419            .collect();
14420        state.groups.retain_mut(|group| {
14421            // selections might get merged above so we remove invalid items from stacks
14422            group.stack.retain(|id| final_selection_ids.contains(id));
14423
14424            // single selection in stack can be treated as initial state
14425            group.stack.len() > 1
14426        });
14427
14428        if !state.groups.is_empty() {
14429            self.add_selections_state = Some(state);
14430        }
14431    }
14432
14433    fn select_match_ranges(
14434        &mut self,
14435        range: Range<usize>,
14436        reversed: bool,
14437        replace_newest: bool,
14438        auto_scroll: Option<Autoscroll>,
14439        window: &mut Window,
14440        cx: &mut Context<Editor>,
14441    ) {
14442        self.unfold_ranges(
14443            std::slice::from_ref(&range),
14444            false,
14445            auto_scroll.is_some(),
14446            cx,
14447        );
14448        let effects = if let Some(scroll) = auto_scroll {
14449            SelectionEffects::scroll(scroll)
14450        } else {
14451            SelectionEffects::no_scroll()
14452        };
14453        self.change_selections(effects, window, cx, |s| {
14454            if replace_newest {
14455                s.delete(s.newest_anchor().id);
14456            }
14457            if reversed {
14458                s.insert_range(range.end..range.start);
14459            } else {
14460                s.insert_range(range);
14461            }
14462        });
14463    }
14464
14465    pub fn select_next_match_internal(
14466        &mut self,
14467        display_map: &DisplaySnapshot,
14468        replace_newest: bool,
14469        autoscroll: Option<Autoscroll>,
14470        window: &mut Window,
14471        cx: &mut Context<Self>,
14472    ) -> Result<()> {
14473        let buffer = display_map.buffer_snapshot();
14474        let mut selections = self.selections.all::<usize>(&display_map);
14475        if let Some(mut select_next_state) = self.select_next_state.take() {
14476            let query = &select_next_state.query;
14477            if !select_next_state.done {
14478                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14479                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14480                let mut next_selected_range = None;
14481
14482                let bytes_after_last_selection =
14483                    buffer.bytes_in_range(last_selection.end..buffer.len());
14484                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14485                let query_matches = query
14486                    .stream_find_iter(bytes_after_last_selection)
14487                    .map(|result| (last_selection.end, result))
14488                    .chain(
14489                        query
14490                            .stream_find_iter(bytes_before_first_selection)
14491                            .map(|result| (0, result)),
14492                    );
14493
14494                for (start_offset, query_match) in query_matches {
14495                    let query_match = query_match.unwrap(); // can only fail due to I/O
14496                    let offset_range =
14497                        start_offset + query_match.start()..start_offset + query_match.end();
14498
14499                    if !select_next_state.wordwise
14500                        || (!buffer.is_inside_word(offset_range.start, None)
14501                            && !buffer.is_inside_word(offset_range.end, None))
14502                    {
14503                        let idx = selections
14504                            .partition_point(|selection| selection.end <= offset_range.start);
14505                        let overlaps = selections
14506                            .get(idx)
14507                            .map_or(false, |selection| selection.start < offset_range.end);
14508
14509                        if !overlaps {
14510                            next_selected_range = Some(offset_range);
14511                            break;
14512                        }
14513                    }
14514                }
14515
14516                if let Some(next_selected_range) = next_selected_range {
14517                    self.select_match_ranges(
14518                        next_selected_range,
14519                        last_selection.reversed,
14520                        replace_newest,
14521                        autoscroll,
14522                        window,
14523                        cx,
14524                    );
14525                } else {
14526                    select_next_state.done = true;
14527                }
14528            }
14529
14530            self.select_next_state = Some(select_next_state);
14531        } else {
14532            let mut only_carets = true;
14533            let mut same_text_selected = true;
14534            let mut selected_text = None;
14535
14536            let mut selections_iter = selections.iter().peekable();
14537            while let Some(selection) = selections_iter.next() {
14538                if selection.start != selection.end {
14539                    only_carets = false;
14540                }
14541
14542                if same_text_selected {
14543                    if selected_text.is_none() {
14544                        selected_text =
14545                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14546                    }
14547
14548                    if let Some(next_selection) = selections_iter.peek() {
14549                        if next_selection.range().len() == selection.range().len() {
14550                            let next_selected_text = buffer
14551                                .text_for_range(next_selection.range())
14552                                .collect::<String>();
14553                            if Some(next_selected_text) != selected_text {
14554                                same_text_selected = false;
14555                                selected_text = None;
14556                            }
14557                        } else {
14558                            same_text_selected = false;
14559                            selected_text = None;
14560                        }
14561                    }
14562                }
14563            }
14564
14565            if only_carets {
14566                for selection in &mut selections {
14567                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14568                    selection.start = word_range.start;
14569                    selection.end = word_range.end;
14570                    selection.goal = SelectionGoal::None;
14571                    selection.reversed = false;
14572                    self.select_match_ranges(
14573                        selection.start..selection.end,
14574                        selection.reversed,
14575                        replace_newest,
14576                        autoscroll,
14577                        window,
14578                        cx,
14579                    );
14580                }
14581
14582                if selections.len() == 1 {
14583                    let selection = selections
14584                        .last()
14585                        .expect("ensured that there's only one selection");
14586                    let query = buffer
14587                        .text_for_range(selection.start..selection.end)
14588                        .collect::<String>();
14589                    let is_empty = query.is_empty();
14590                    let select_state = SelectNextState {
14591                        query: AhoCorasick::new(&[query])?,
14592                        wordwise: true,
14593                        done: is_empty,
14594                    };
14595                    self.select_next_state = Some(select_state);
14596                } else {
14597                    self.select_next_state = None;
14598                }
14599            } else if let Some(selected_text) = selected_text {
14600                self.select_next_state = Some(SelectNextState {
14601                    query: AhoCorasick::new(&[selected_text])?,
14602                    wordwise: false,
14603                    done: false,
14604                });
14605                self.select_next_match_internal(
14606                    display_map,
14607                    replace_newest,
14608                    autoscroll,
14609                    window,
14610                    cx,
14611                )?;
14612            }
14613        }
14614        Ok(())
14615    }
14616
14617    pub fn select_all_matches(
14618        &mut self,
14619        _action: &SelectAllMatches,
14620        window: &mut Window,
14621        cx: &mut Context<Self>,
14622    ) -> Result<()> {
14623        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14624
14625        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14626
14627        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14628        let Some(select_next_state) = self.select_next_state.as_mut() else {
14629            return Ok(());
14630        };
14631        if select_next_state.done {
14632            return Ok(());
14633        }
14634
14635        let mut new_selections = Vec::new();
14636
14637        let reversed = self.selections.oldest::<usize>(&display_map).reversed;
14638        let buffer = display_map.buffer_snapshot();
14639        let query_matches = select_next_state
14640            .query
14641            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14642
14643        for query_match in query_matches.into_iter() {
14644            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14645            let offset_range = if reversed {
14646                query_match.end()..query_match.start()
14647            } else {
14648                query_match.start()..query_match.end()
14649            };
14650
14651            if !select_next_state.wordwise
14652                || (!buffer.is_inside_word(offset_range.start, None)
14653                    && !buffer.is_inside_word(offset_range.end, None))
14654            {
14655                new_selections.push(offset_range.start..offset_range.end);
14656            }
14657        }
14658
14659        select_next_state.done = true;
14660
14661        if new_selections.is_empty() {
14662            log::error!("bug: new_selections is empty in select_all_matches");
14663            return Ok(());
14664        }
14665
14666        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14667        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14668            selections.select_ranges(new_selections)
14669        });
14670
14671        Ok(())
14672    }
14673
14674    pub fn select_next(
14675        &mut self,
14676        action: &SelectNext,
14677        window: &mut Window,
14678        cx: &mut Context<Self>,
14679    ) -> Result<()> {
14680        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14681        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14682        self.select_next_match_internal(
14683            &display_map,
14684            action.replace_newest,
14685            Some(Autoscroll::newest()),
14686            window,
14687            cx,
14688        )?;
14689        Ok(())
14690    }
14691
14692    pub fn select_previous(
14693        &mut self,
14694        action: &SelectPrevious,
14695        window: &mut Window,
14696        cx: &mut Context<Self>,
14697    ) -> Result<()> {
14698        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14699        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14700        let buffer = display_map.buffer_snapshot();
14701        let mut selections = self.selections.all::<usize>(&display_map);
14702        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14703            let query = &select_prev_state.query;
14704            if !select_prev_state.done {
14705                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14706                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14707                let mut next_selected_range = None;
14708                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14709                let bytes_before_last_selection =
14710                    buffer.reversed_bytes_in_range(0..last_selection.start);
14711                let bytes_after_first_selection =
14712                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14713                let query_matches = query
14714                    .stream_find_iter(bytes_before_last_selection)
14715                    .map(|result| (last_selection.start, result))
14716                    .chain(
14717                        query
14718                            .stream_find_iter(bytes_after_first_selection)
14719                            .map(|result| (buffer.len(), result)),
14720                    );
14721                for (end_offset, query_match) in query_matches {
14722                    let query_match = query_match.unwrap(); // can only fail due to I/O
14723                    let offset_range =
14724                        end_offset - query_match.end()..end_offset - query_match.start();
14725
14726                    if !select_prev_state.wordwise
14727                        || (!buffer.is_inside_word(offset_range.start, None)
14728                            && !buffer.is_inside_word(offset_range.end, None))
14729                    {
14730                        next_selected_range = Some(offset_range);
14731                        break;
14732                    }
14733                }
14734
14735                if let Some(next_selected_range) = next_selected_range {
14736                    self.select_match_ranges(
14737                        next_selected_range,
14738                        last_selection.reversed,
14739                        action.replace_newest,
14740                        Some(Autoscroll::newest()),
14741                        window,
14742                        cx,
14743                    );
14744                } else {
14745                    select_prev_state.done = true;
14746                }
14747            }
14748
14749            self.select_prev_state = Some(select_prev_state);
14750        } else {
14751            let mut only_carets = true;
14752            let mut same_text_selected = true;
14753            let mut selected_text = None;
14754
14755            let mut selections_iter = selections.iter().peekable();
14756            while let Some(selection) = selections_iter.next() {
14757                if selection.start != selection.end {
14758                    only_carets = false;
14759                }
14760
14761                if same_text_selected {
14762                    if selected_text.is_none() {
14763                        selected_text =
14764                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14765                    }
14766
14767                    if let Some(next_selection) = selections_iter.peek() {
14768                        if next_selection.range().len() == selection.range().len() {
14769                            let next_selected_text = buffer
14770                                .text_for_range(next_selection.range())
14771                                .collect::<String>();
14772                            if Some(next_selected_text) != selected_text {
14773                                same_text_selected = false;
14774                                selected_text = None;
14775                            }
14776                        } else {
14777                            same_text_selected = false;
14778                            selected_text = None;
14779                        }
14780                    }
14781                }
14782            }
14783
14784            if only_carets {
14785                for selection in &mut selections {
14786                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14787                    selection.start = word_range.start;
14788                    selection.end = word_range.end;
14789                    selection.goal = SelectionGoal::None;
14790                    selection.reversed = false;
14791                    self.select_match_ranges(
14792                        selection.start..selection.end,
14793                        selection.reversed,
14794                        action.replace_newest,
14795                        Some(Autoscroll::newest()),
14796                        window,
14797                        cx,
14798                    );
14799                }
14800                if selections.len() == 1 {
14801                    let selection = selections
14802                        .last()
14803                        .expect("ensured that there's only one selection");
14804                    let query = buffer
14805                        .text_for_range(selection.start..selection.end)
14806                        .collect::<String>();
14807                    let is_empty = query.is_empty();
14808                    let select_state = SelectNextState {
14809                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14810                        wordwise: true,
14811                        done: is_empty,
14812                    };
14813                    self.select_prev_state = Some(select_state);
14814                } else {
14815                    self.select_prev_state = None;
14816                }
14817            } else if let Some(selected_text) = selected_text {
14818                self.select_prev_state = Some(SelectNextState {
14819                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14820                    wordwise: false,
14821                    done: false,
14822                });
14823                self.select_previous(action, window, cx)?;
14824            }
14825        }
14826        Ok(())
14827    }
14828
14829    pub fn find_next_match(
14830        &mut self,
14831        _: &FindNextMatch,
14832        window: &mut Window,
14833        cx: &mut Context<Self>,
14834    ) -> Result<()> {
14835        let selections = self.selections.disjoint_anchors_arc();
14836        match selections.first() {
14837            Some(first) if selections.len() >= 2 => {
14838                self.change_selections(Default::default(), window, cx, |s| {
14839                    s.select_ranges([first.range()]);
14840                });
14841            }
14842            _ => self.select_next(
14843                &SelectNext {
14844                    replace_newest: true,
14845                },
14846                window,
14847                cx,
14848            )?,
14849        }
14850        Ok(())
14851    }
14852
14853    pub fn find_previous_match(
14854        &mut self,
14855        _: &FindPreviousMatch,
14856        window: &mut Window,
14857        cx: &mut Context<Self>,
14858    ) -> Result<()> {
14859        let selections = self.selections.disjoint_anchors_arc();
14860        match selections.last() {
14861            Some(last) if selections.len() >= 2 => {
14862                self.change_selections(Default::default(), window, cx, |s| {
14863                    s.select_ranges([last.range()]);
14864                });
14865            }
14866            _ => self.select_previous(
14867                &SelectPrevious {
14868                    replace_newest: true,
14869                },
14870                window,
14871                cx,
14872            )?,
14873        }
14874        Ok(())
14875    }
14876
14877    pub fn toggle_comments(
14878        &mut self,
14879        action: &ToggleComments,
14880        window: &mut Window,
14881        cx: &mut Context<Self>,
14882    ) {
14883        if self.read_only(cx) {
14884            return;
14885        }
14886        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14887        let text_layout_details = &self.text_layout_details(window);
14888        self.transact(window, cx, |this, window, cx| {
14889            let mut selections = this
14890                .selections
14891                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
14892            let mut edits = Vec::new();
14893            let mut selection_edit_ranges = Vec::new();
14894            let mut last_toggled_row = None;
14895            let snapshot = this.buffer.read(cx).read(cx);
14896            let empty_str: Arc<str> = Arc::default();
14897            let mut suffixes_inserted = Vec::new();
14898            let ignore_indent = action.ignore_indent;
14899
14900            fn comment_prefix_range(
14901                snapshot: &MultiBufferSnapshot,
14902                row: MultiBufferRow,
14903                comment_prefix: &str,
14904                comment_prefix_whitespace: &str,
14905                ignore_indent: bool,
14906            ) -> Range<Point> {
14907                let indent_size = if ignore_indent {
14908                    0
14909                } else {
14910                    snapshot.indent_size_for_line(row).len
14911                };
14912
14913                let start = Point::new(row.0, indent_size);
14914
14915                let mut line_bytes = snapshot
14916                    .bytes_in_range(start..snapshot.max_point())
14917                    .flatten()
14918                    .copied();
14919
14920                // If this line currently begins with the line comment prefix, then record
14921                // the range containing the prefix.
14922                if line_bytes
14923                    .by_ref()
14924                    .take(comment_prefix.len())
14925                    .eq(comment_prefix.bytes())
14926                {
14927                    // Include any whitespace that matches the comment prefix.
14928                    let matching_whitespace_len = line_bytes
14929                        .zip(comment_prefix_whitespace.bytes())
14930                        .take_while(|(a, b)| a == b)
14931                        .count() as u32;
14932                    let end = Point::new(
14933                        start.row,
14934                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14935                    );
14936                    start..end
14937                } else {
14938                    start..start
14939                }
14940            }
14941
14942            fn comment_suffix_range(
14943                snapshot: &MultiBufferSnapshot,
14944                row: MultiBufferRow,
14945                comment_suffix: &str,
14946                comment_suffix_has_leading_space: bool,
14947            ) -> Range<Point> {
14948                let end = Point::new(row.0, snapshot.line_len(row));
14949                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14950
14951                let mut line_end_bytes = snapshot
14952                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14953                    .flatten()
14954                    .copied();
14955
14956                let leading_space_len = if suffix_start_column > 0
14957                    && line_end_bytes.next() == Some(b' ')
14958                    && comment_suffix_has_leading_space
14959                {
14960                    1
14961                } else {
14962                    0
14963                };
14964
14965                // If this line currently begins with the line comment prefix, then record
14966                // the range containing the prefix.
14967                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14968                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14969                    start..end
14970                } else {
14971                    end..end
14972                }
14973            }
14974
14975            // TODO: Handle selections that cross excerpts
14976            for selection in &mut selections {
14977                let start_column = snapshot
14978                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14979                    .len;
14980                let language = if let Some(language) =
14981                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14982                {
14983                    language
14984                } else {
14985                    continue;
14986                };
14987
14988                selection_edit_ranges.clear();
14989
14990                // If multiple selections contain a given row, avoid processing that
14991                // row more than once.
14992                let mut start_row = MultiBufferRow(selection.start.row);
14993                if last_toggled_row == Some(start_row) {
14994                    start_row = start_row.next_row();
14995                }
14996                let end_row =
14997                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14998                        MultiBufferRow(selection.end.row - 1)
14999                    } else {
15000                        MultiBufferRow(selection.end.row)
15001                    };
15002                last_toggled_row = Some(end_row);
15003
15004                if start_row > end_row {
15005                    continue;
15006                }
15007
15008                // If the language has line comments, toggle those.
15009                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15010
15011                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15012                if ignore_indent {
15013                    full_comment_prefixes = full_comment_prefixes
15014                        .into_iter()
15015                        .map(|s| Arc::from(s.trim_end()))
15016                        .collect();
15017                }
15018
15019                if !full_comment_prefixes.is_empty() {
15020                    let first_prefix = full_comment_prefixes
15021                        .first()
15022                        .expect("prefixes is non-empty");
15023                    let prefix_trimmed_lengths = full_comment_prefixes
15024                        .iter()
15025                        .map(|p| p.trim_end_matches(' ').len())
15026                        .collect::<SmallVec<[usize; 4]>>();
15027
15028                    let mut all_selection_lines_are_comments = true;
15029
15030                    for row in start_row.0..=end_row.0 {
15031                        let row = MultiBufferRow(row);
15032                        if start_row < end_row && snapshot.is_line_blank(row) {
15033                            continue;
15034                        }
15035
15036                        let prefix_range = full_comment_prefixes
15037                            .iter()
15038                            .zip(prefix_trimmed_lengths.iter().copied())
15039                            .map(|(prefix, trimmed_prefix_len)| {
15040                                comment_prefix_range(
15041                                    snapshot.deref(),
15042                                    row,
15043                                    &prefix[..trimmed_prefix_len],
15044                                    &prefix[trimmed_prefix_len..],
15045                                    ignore_indent,
15046                                )
15047                            })
15048                            .max_by_key(|range| range.end.column - range.start.column)
15049                            .expect("prefixes is non-empty");
15050
15051                        if prefix_range.is_empty() {
15052                            all_selection_lines_are_comments = false;
15053                        }
15054
15055                        selection_edit_ranges.push(prefix_range);
15056                    }
15057
15058                    if all_selection_lines_are_comments {
15059                        edits.extend(
15060                            selection_edit_ranges
15061                                .iter()
15062                                .cloned()
15063                                .map(|range| (range, empty_str.clone())),
15064                        );
15065                    } else {
15066                        let min_column = selection_edit_ranges
15067                            .iter()
15068                            .map(|range| range.start.column)
15069                            .min()
15070                            .unwrap_or(0);
15071                        edits.extend(selection_edit_ranges.iter().map(|range| {
15072                            let position = Point::new(range.start.row, min_column);
15073                            (position..position, first_prefix.clone())
15074                        }));
15075                    }
15076                } else if let Some(BlockCommentConfig {
15077                    start: full_comment_prefix,
15078                    end: comment_suffix,
15079                    ..
15080                }) = language.block_comment()
15081                {
15082                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15083                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15084                    let prefix_range = comment_prefix_range(
15085                        snapshot.deref(),
15086                        start_row,
15087                        comment_prefix,
15088                        comment_prefix_whitespace,
15089                        ignore_indent,
15090                    );
15091                    let suffix_range = comment_suffix_range(
15092                        snapshot.deref(),
15093                        end_row,
15094                        comment_suffix.trim_start_matches(' '),
15095                        comment_suffix.starts_with(' '),
15096                    );
15097
15098                    if prefix_range.is_empty() || suffix_range.is_empty() {
15099                        edits.push((
15100                            prefix_range.start..prefix_range.start,
15101                            full_comment_prefix.clone(),
15102                        ));
15103                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15104                        suffixes_inserted.push((end_row, comment_suffix.len()));
15105                    } else {
15106                        edits.push((prefix_range, empty_str.clone()));
15107                        edits.push((suffix_range, empty_str.clone()));
15108                    }
15109                } else {
15110                    continue;
15111                }
15112            }
15113
15114            drop(snapshot);
15115            this.buffer.update(cx, |buffer, cx| {
15116                buffer.edit(edits, None, cx);
15117            });
15118
15119            // Adjust selections so that they end before any comment suffixes that
15120            // were inserted.
15121            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15122            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15123            let snapshot = this.buffer.read(cx).read(cx);
15124            for selection in &mut selections {
15125                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15126                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15127                        Ordering::Less => {
15128                            suffixes_inserted.next();
15129                            continue;
15130                        }
15131                        Ordering::Greater => break,
15132                        Ordering::Equal => {
15133                            if selection.end.column == snapshot.line_len(row) {
15134                                if selection.is_empty() {
15135                                    selection.start.column -= suffix_len as u32;
15136                                }
15137                                selection.end.column -= suffix_len as u32;
15138                            }
15139                            break;
15140                        }
15141                    }
15142                }
15143            }
15144
15145            drop(snapshot);
15146            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15147
15148            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15149            let selections_on_single_row = selections.windows(2).all(|selections| {
15150                selections[0].start.row == selections[1].start.row
15151                    && selections[0].end.row == selections[1].end.row
15152                    && selections[0].start.row == selections[0].end.row
15153            });
15154            let selections_selecting = selections
15155                .iter()
15156                .any(|selection| selection.start != selection.end);
15157            let advance_downwards = action.advance_downwards
15158                && selections_on_single_row
15159                && !selections_selecting
15160                && !matches!(this.mode, EditorMode::SingleLine);
15161
15162            if advance_downwards {
15163                let snapshot = this.buffer.read(cx).snapshot(cx);
15164
15165                this.change_selections(Default::default(), window, cx, |s| {
15166                    s.move_cursors_with(|display_snapshot, display_point, _| {
15167                        let mut point = display_point.to_point(display_snapshot);
15168                        point.row += 1;
15169                        point = snapshot.clip_point(point, Bias::Left);
15170                        let display_point = point.to_display_point(display_snapshot);
15171                        let goal = SelectionGoal::HorizontalPosition(
15172                            display_snapshot
15173                                .x_for_display_point(display_point, text_layout_details)
15174                                .into(),
15175                        );
15176                        (display_point, goal)
15177                    })
15178                });
15179            }
15180        });
15181    }
15182
15183    pub fn select_enclosing_symbol(
15184        &mut self,
15185        _: &SelectEnclosingSymbol,
15186        window: &mut Window,
15187        cx: &mut Context<Self>,
15188    ) {
15189        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15190
15191        let buffer = self.buffer.read(cx).snapshot(cx);
15192        let old_selections = self
15193            .selections
15194            .all::<usize>(&self.display_snapshot(cx))
15195            .into_boxed_slice();
15196
15197        fn update_selection(
15198            selection: &Selection<usize>,
15199            buffer_snap: &MultiBufferSnapshot,
15200        ) -> Option<Selection<usize>> {
15201            let cursor = selection.head();
15202            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15203            for symbol in symbols.iter().rev() {
15204                let start = symbol.range.start.to_offset(buffer_snap);
15205                let end = symbol.range.end.to_offset(buffer_snap);
15206                let new_range = start..end;
15207                if start < selection.start || end > selection.end {
15208                    return Some(Selection {
15209                        id: selection.id,
15210                        start: new_range.start,
15211                        end: new_range.end,
15212                        goal: SelectionGoal::None,
15213                        reversed: selection.reversed,
15214                    });
15215                }
15216            }
15217            None
15218        }
15219
15220        let mut selected_larger_symbol = false;
15221        let new_selections = old_selections
15222            .iter()
15223            .map(|selection| match update_selection(selection, &buffer) {
15224                Some(new_selection) => {
15225                    if new_selection.range() != selection.range() {
15226                        selected_larger_symbol = true;
15227                    }
15228                    new_selection
15229                }
15230                None => selection.clone(),
15231            })
15232            .collect::<Vec<_>>();
15233
15234        if selected_larger_symbol {
15235            self.change_selections(Default::default(), window, cx, |s| {
15236                s.select(new_selections);
15237            });
15238        }
15239    }
15240
15241    pub fn select_larger_syntax_node(
15242        &mut self,
15243        _: &SelectLargerSyntaxNode,
15244        window: &mut Window,
15245        cx: &mut Context<Self>,
15246    ) {
15247        let Some(visible_row_count) = self.visible_row_count() else {
15248            return;
15249        };
15250        let old_selections: Box<[_]> = self
15251            .selections
15252            .all::<usize>(&self.display_snapshot(cx))
15253            .into();
15254        if old_selections.is_empty() {
15255            return;
15256        }
15257
15258        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15259
15260        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15261        let buffer = self.buffer.read(cx).snapshot(cx);
15262
15263        let mut selected_larger_node = false;
15264        let mut new_selections = old_selections
15265            .iter()
15266            .map(|selection| {
15267                let old_range = selection.start..selection.end;
15268
15269                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15270                    // manually select word at selection
15271                    if ["string_content", "inline"].contains(&node.kind()) {
15272                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15273                        // ignore if word is already selected
15274                        if !word_range.is_empty() && old_range != word_range {
15275                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15276                            // only select word if start and end point belongs to same word
15277                            if word_range == last_word_range {
15278                                selected_larger_node = true;
15279                                return Selection {
15280                                    id: selection.id,
15281                                    start: word_range.start,
15282                                    end: word_range.end,
15283                                    goal: SelectionGoal::None,
15284                                    reversed: selection.reversed,
15285                                };
15286                            }
15287                        }
15288                    }
15289                }
15290
15291                let mut new_range = old_range.clone();
15292                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15293                    new_range = range;
15294                    if !node.is_named() {
15295                        continue;
15296                    }
15297                    if !display_map.intersects_fold(new_range.start)
15298                        && !display_map.intersects_fold(new_range.end)
15299                    {
15300                        break;
15301                    }
15302                }
15303
15304                selected_larger_node |= new_range != old_range;
15305                Selection {
15306                    id: selection.id,
15307                    start: new_range.start,
15308                    end: new_range.end,
15309                    goal: SelectionGoal::None,
15310                    reversed: selection.reversed,
15311                }
15312            })
15313            .collect::<Vec<_>>();
15314
15315        if !selected_larger_node {
15316            return; // don't put this call in the history
15317        }
15318
15319        // scroll based on transformation done to the last selection created by the user
15320        let (last_old, last_new) = old_selections
15321            .last()
15322            .zip(new_selections.last().cloned())
15323            .expect("old_selections isn't empty");
15324
15325        // revert selection
15326        let is_selection_reversed = {
15327            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15328            new_selections.last_mut().expect("checked above").reversed =
15329                should_newest_selection_be_reversed;
15330            should_newest_selection_be_reversed
15331        };
15332
15333        if selected_larger_node {
15334            self.select_syntax_node_history.disable_clearing = true;
15335            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15336                s.select(new_selections.clone());
15337            });
15338            self.select_syntax_node_history.disable_clearing = false;
15339        }
15340
15341        let start_row = last_new.start.to_display_point(&display_map).row().0;
15342        let end_row = last_new.end.to_display_point(&display_map).row().0;
15343        let selection_height = end_row - start_row + 1;
15344        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15345
15346        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15347        let scroll_behavior = if fits_on_the_screen {
15348            self.request_autoscroll(Autoscroll::fit(), cx);
15349            SelectSyntaxNodeScrollBehavior::FitSelection
15350        } else if is_selection_reversed {
15351            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15352            SelectSyntaxNodeScrollBehavior::CursorTop
15353        } else {
15354            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15355            SelectSyntaxNodeScrollBehavior::CursorBottom
15356        };
15357
15358        self.select_syntax_node_history.push((
15359            old_selections,
15360            scroll_behavior,
15361            is_selection_reversed,
15362        ));
15363    }
15364
15365    pub fn select_smaller_syntax_node(
15366        &mut self,
15367        _: &SelectSmallerSyntaxNode,
15368        window: &mut Window,
15369        cx: &mut Context<Self>,
15370    ) {
15371        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15372
15373        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15374            self.select_syntax_node_history.pop()
15375        {
15376            if let Some(selection) = selections.last_mut() {
15377                selection.reversed = is_selection_reversed;
15378            }
15379
15380            self.select_syntax_node_history.disable_clearing = true;
15381            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15382                s.select(selections.to_vec());
15383            });
15384            self.select_syntax_node_history.disable_clearing = false;
15385
15386            match scroll_behavior {
15387                SelectSyntaxNodeScrollBehavior::CursorTop => {
15388                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15389                }
15390                SelectSyntaxNodeScrollBehavior::FitSelection => {
15391                    self.request_autoscroll(Autoscroll::fit(), cx);
15392                }
15393                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15394                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15395                }
15396            }
15397        }
15398    }
15399
15400    pub fn unwrap_syntax_node(
15401        &mut self,
15402        _: &UnwrapSyntaxNode,
15403        window: &mut Window,
15404        cx: &mut Context<Self>,
15405    ) {
15406        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15407
15408        let buffer = self.buffer.read(cx).snapshot(cx);
15409        let selections = self
15410            .selections
15411            .all::<usize>(&self.display_snapshot(cx))
15412            .into_iter()
15413            // subtracting the offset requires sorting
15414            .sorted_by_key(|i| i.start);
15415
15416        let full_edits = selections
15417            .into_iter()
15418            .filter_map(|selection| {
15419                let child = if selection.is_empty()
15420                    && let Some((_, ancestor_range)) =
15421                        buffer.syntax_ancestor(selection.start..selection.end)
15422                {
15423                    ancestor_range
15424                } else {
15425                    selection.range()
15426                };
15427
15428                let mut parent = child.clone();
15429                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15430                    parent = ancestor_range;
15431                    if parent.start < child.start || parent.end > child.end {
15432                        break;
15433                    }
15434                }
15435
15436                if parent == child {
15437                    return None;
15438                }
15439                let text = buffer.text_for_range(child).collect::<String>();
15440                Some((selection.id, parent, text))
15441            })
15442            .collect::<Vec<_>>();
15443        if full_edits.is_empty() {
15444            return;
15445        }
15446
15447        self.transact(window, cx, |this, window, cx| {
15448            this.buffer.update(cx, |buffer, cx| {
15449                buffer.edit(
15450                    full_edits
15451                        .iter()
15452                        .map(|(_, p, t)| (p.clone(), t.clone()))
15453                        .collect::<Vec<_>>(),
15454                    None,
15455                    cx,
15456                );
15457            });
15458            this.change_selections(Default::default(), window, cx, |s| {
15459                let mut offset = 0;
15460                let mut selections = vec![];
15461                for (id, parent, text) in full_edits {
15462                    let start = parent.start - offset;
15463                    offset += parent.len() - text.len();
15464                    selections.push(Selection {
15465                        id,
15466                        start,
15467                        end: start + text.len(),
15468                        reversed: false,
15469                        goal: Default::default(),
15470                    });
15471                }
15472                s.select(selections);
15473            });
15474        });
15475    }
15476
15477    pub fn select_next_syntax_node(
15478        &mut self,
15479        _: &SelectNextSyntaxNode,
15480        window: &mut Window,
15481        cx: &mut Context<Self>,
15482    ) {
15483        let old_selections: Box<[_]> = self
15484            .selections
15485            .all::<usize>(&self.display_snapshot(cx))
15486            .into();
15487        if old_selections.is_empty() {
15488            return;
15489        }
15490
15491        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15492
15493        let buffer = self.buffer.read(cx).snapshot(cx);
15494        let mut selected_sibling = false;
15495
15496        let new_selections = old_selections
15497            .iter()
15498            .map(|selection| {
15499                let old_range = selection.start..selection.end;
15500
15501                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15502                    let new_range = node.byte_range();
15503                    selected_sibling = true;
15504                    Selection {
15505                        id: selection.id,
15506                        start: new_range.start,
15507                        end: new_range.end,
15508                        goal: SelectionGoal::None,
15509                        reversed: selection.reversed,
15510                    }
15511                } else {
15512                    selection.clone()
15513                }
15514            })
15515            .collect::<Vec<_>>();
15516
15517        if selected_sibling {
15518            self.change_selections(
15519                SelectionEffects::scroll(Autoscroll::fit()),
15520                window,
15521                cx,
15522                |s| {
15523                    s.select(new_selections);
15524                },
15525            );
15526        }
15527    }
15528
15529    pub fn select_prev_syntax_node(
15530        &mut self,
15531        _: &SelectPreviousSyntaxNode,
15532        window: &mut Window,
15533        cx: &mut Context<Self>,
15534    ) {
15535        let old_selections: Box<[_]> = self
15536            .selections
15537            .all::<usize>(&self.display_snapshot(cx))
15538            .into();
15539        if old_selections.is_empty() {
15540            return;
15541        }
15542
15543        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15544
15545        let buffer = self.buffer.read(cx).snapshot(cx);
15546        let mut selected_sibling = false;
15547
15548        let new_selections = old_selections
15549            .iter()
15550            .map(|selection| {
15551                let old_range = selection.start..selection.end;
15552
15553                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15554                    let new_range = node.byte_range();
15555                    selected_sibling = true;
15556                    Selection {
15557                        id: selection.id,
15558                        start: new_range.start,
15559                        end: new_range.end,
15560                        goal: SelectionGoal::None,
15561                        reversed: selection.reversed,
15562                    }
15563                } else {
15564                    selection.clone()
15565                }
15566            })
15567            .collect::<Vec<_>>();
15568
15569        if selected_sibling {
15570            self.change_selections(
15571                SelectionEffects::scroll(Autoscroll::fit()),
15572                window,
15573                cx,
15574                |s| {
15575                    s.select(new_selections);
15576                },
15577            );
15578        }
15579    }
15580
15581    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15582        if !EditorSettings::get_global(cx).gutter.runnables {
15583            self.clear_tasks();
15584            return Task::ready(());
15585        }
15586        let project = self.project().map(Entity::downgrade);
15587        let task_sources = self.lsp_task_sources(cx);
15588        let multi_buffer = self.buffer.downgrade();
15589        cx.spawn_in(window, async move |editor, cx| {
15590            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15591            let Some(project) = project.and_then(|p| p.upgrade()) else {
15592                return;
15593            };
15594            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15595                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15596            }) else {
15597                return;
15598            };
15599
15600            let hide_runnables = project
15601                .update(cx, |project, _| project.is_via_collab())
15602                .unwrap_or(true);
15603            if hide_runnables {
15604                return;
15605            }
15606            let new_rows =
15607                cx.background_spawn({
15608                    let snapshot = display_snapshot.clone();
15609                    async move {
15610                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15611                    }
15612                })
15613                    .await;
15614            let Ok(lsp_tasks) =
15615                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15616            else {
15617                return;
15618            };
15619            let lsp_tasks = lsp_tasks.await;
15620
15621            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15622                lsp_tasks
15623                    .into_iter()
15624                    .flat_map(|(kind, tasks)| {
15625                        tasks.into_iter().filter_map(move |(location, task)| {
15626                            Some((kind.clone(), location?, task))
15627                        })
15628                    })
15629                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15630                        let buffer = location.target.buffer;
15631                        let buffer_snapshot = buffer.read(cx).snapshot();
15632                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15633                            |(excerpt_id, snapshot, _)| {
15634                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15635                                    display_snapshot
15636                                        .buffer_snapshot()
15637                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15638                                } else {
15639                                    None
15640                                }
15641                            },
15642                        );
15643                        if let Some(offset) = offset {
15644                            let task_buffer_range =
15645                                location.target.range.to_point(&buffer_snapshot);
15646                            let context_buffer_range =
15647                                task_buffer_range.to_offset(&buffer_snapshot);
15648                            let context_range = BufferOffset(context_buffer_range.start)
15649                                ..BufferOffset(context_buffer_range.end);
15650
15651                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15652                                .or_insert_with(|| RunnableTasks {
15653                                    templates: Vec::new(),
15654                                    offset,
15655                                    column: task_buffer_range.start.column,
15656                                    extra_variables: HashMap::default(),
15657                                    context_range,
15658                                })
15659                                .templates
15660                                .push((kind, task.original_task().clone()));
15661                        }
15662
15663                        acc
15664                    })
15665            }) else {
15666                return;
15667            };
15668
15669            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15670                buffer.language_settings(cx).tasks.prefer_lsp
15671            }) else {
15672                return;
15673            };
15674
15675            let rows = Self::runnable_rows(
15676                project,
15677                display_snapshot,
15678                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15679                new_rows,
15680                cx.clone(),
15681            )
15682            .await;
15683            editor
15684                .update(cx, |editor, _| {
15685                    editor.clear_tasks();
15686                    for (key, mut value) in rows {
15687                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15688                            value.templates.extend(lsp_tasks.templates);
15689                        }
15690
15691                        editor.insert_tasks(key, value);
15692                    }
15693                    for (key, value) in lsp_tasks_by_rows {
15694                        editor.insert_tasks(key, value);
15695                    }
15696                })
15697                .ok();
15698        })
15699    }
15700    fn fetch_runnable_ranges(
15701        snapshot: &DisplaySnapshot,
15702        range: Range<Anchor>,
15703    ) -> Vec<language::RunnableRange> {
15704        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15705    }
15706
15707    fn runnable_rows(
15708        project: Entity<Project>,
15709        snapshot: DisplaySnapshot,
15710        prefer_lsp: bool,
15711        runnable_ranges: Vec<RunnableRange>,
15712        cx: AsyncWindowContext,
15713    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15714        cx.spawn(async move |cx| {
15715            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15716            for mut runnable in runnable_ranges {
15717                let Some(tasks) = cx
15718                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15719                    .ok()
15720                else {
15721                    continue;
15722                };
15723                let mut tasks = tasks.await;
15724
15725                if prefer_lsp {
15726                    tasks.retain(|(task_kind, _)| {
15727                        !matches!(task_kind, TaskSourceKind::Language { .. })
15728                    });
15729                }
15730                if tasks.is_empty() {
15731                    continue;
15732                }
15733
15734                let point = runnable
15735                    .run_range
15736                    .start
15737                    .to_point(&snapshot.buffer_snapshot());
15738                let Some(row) = snapshot
15739                    .buffer_snapshot()
15740                    .buffer_line_for_row(MultiBufferRow(point.row))
15741                    .map(|(_, range)| range.start.row)
15742                else {
15743                    continue;
15744                };
15745
15746                let context_range =
15747                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15748                runnable_rows.push((
15749                    (runnable.buffer_id, row),
15750                    RunnableTasks {
15751                        templates: tasks,
15752                        offset: snapshot
15753                            .buffer_snapshot()
15754                            .anchor_before(runnable.run_range.start),
15755                        context_range,
15756                        column: point.column,
15757                        extra_variables: runnable.extra_captures,
15758                    },
15759                ));
15760            }
15761            runnable_rows
15762        })
15763    }
15764
15765    fn templates_with_tags(
15766        project: &Entity<Project>,
15767        runnable: &mut Runnable,
15768        cx: &mut App,
15769    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15770        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15771            let (worktree_id, file) = project
15772                .buffer_for_id(runnable.buffer, cx)
15773                .and_then(|buffer| buffer.read(cx).file())
15774                .map(|file| (file.worktree_id(cx), file.clone()))
15775                .unzip();
15776
15777            (
15778                project.task_store().read(cx).task_inventory().cloned(),
15779                worktree_id,
15780                file,
15781            )
15782        });
15783
15784        let tags = mem::take(&mut runnable.tags);
15785        let language = runnable.language.clone();
15786        cx.spawn(async move |cx| {
15787            let mut templates_with_tags = Vec::new();
15788            if let Some(inventory) = inventory {
15789                for RunnableTag(tag) in tags {
15790                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15791                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15792                    }) else {
15793                        return templates_with_tags;
15794                    };
15795                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15796                        move |(_, template)| {
15797                            template.tags.iter().any(|source_tag| source_tag == &tag)
15798                        },
15799                    ));
15800                }
15801            }
15802            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15803
15804            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15805                // Strongest source wins; if we have worktree tag binding, prefer that to
15806                // global and language bindings;
15807                // if we have a global binding, prefer that to language binding.
15808                let first_mismatch = templates_with_tags
15809                    .iter()
15810                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15811                if let Some(index) = first_mismatch {
15812                    templates_with_tags.truncate(index);
15813                }
15814            }
15815
15816            templates_with_tags
15817        })
15818    }
15819
15820    pub fn move_to_enclosing_bracket(
15821        &mut self,
15822        _: &MoveToEnclosingBracket,
15823        window: &mut Window,
15824        cx: &mut Context<Self>,
15825    ) {
15826        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15827        self.change_selections(Default::default(), window, cx, |s| {
15828            s.move_offsets_with(|snapshot, selection| {
15829                let Some(enclosing_bracket_ranges) =
15830                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15831                else {
15832                    return;
15833                };
15834
15835                let mut best_length = usize::MAX;
15836                let mut best_inside = false;
15837                let mut best_in_bracket_range = false;
15838                let mut best_destination = None;
15839                for (open, close) in enclosing_bracket_ranges {
15840                    let close = close.to_inclusive();
15841                    let length = close.end() - open.start;
15842                    let inside = selection.start >= open.end && selection.end <= *close.start();
15843                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15844                        || close.contains(&selection.head());
15845
15846                    // If best is next to a bracket and current isn't, skip
15847                    if !in_bracket_range && best_in_bracket_range {
15848                        continue;
15849                    }
15850
15851                    // Prefer smaller lengths unless best is inside and current isn't
15852                    if length > best_length && (best_inside || !inside) {
15853                        continue;
15854                    }
15855
15856                    best_length = length;
15857                    best_inside = inside;
15858                    best_in_bracket_range = in_bracket_range;
15859                    best_destination = Some(
15860                        if close.contains(&selection.start) && close.contains(&selection.end) {
15861                            if inside { open.end } else { open.start }
15862                        } else if inside {
15863                            *close.start()
15864                        } else {
15865                            *close.end()
15866                        },
15867                    );
15868                }
15869
15870                if let Some(destination) = best_destination {
15871                    selection.collapse_to(destination, SelectionGoal::None);
15872                }
15873            })
15874        });
15875    }
15876
15877    pub fn undo_selection(
15878        &mut self,
15879        _: &UndoSelection,
15880        window: &mut Window,
15881        cx: &mut Context<Self>,
15882    ) {
15883        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15884        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15885            self.selection_history.mode = SelectionHistoryMode::Undoing;
15886            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15887                this.end_selection(window, cx);
15888                this.change_selections(
15889                    SelectionEffects::scroll(Autoscroll::newest()),
15890                    window,
15891                    cx,
15892                    |s| s.select_anchors(entry.selections.to_vec()),
15893                );
15894            });
15895            self.selection_history.mode = SelectionHistoryMode::Normal;
15896
15897            self.select_next_state = entry.select_next_state;
15898            self.select_prev_state = entry.select_prev_state;
15899            self.add_selections_state = entry.add_selections_state;
15900        }
15901    }
15902
15903    pub fn redo_selection(
15904        &mut self,
15905        _: &RedoSelection,
15906        window: &mut Window,
15907        cx: &mut Context<Self>,
15908    ) {
15909        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15910        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15911            self.selection_history.mode = SelectionHistoryMode::Redoing;
15912            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15913                this.end_selection(window, cx);
15914                this.change_selections(
15915                    SelectionEffects::scroll(Autoscroll::newest()),
15916                    window,
15917                    cx,
15918                    |s| s.select_anchors(entry.selections.to_vec()),
15919                );
15920            });
15921            self.selection_history.mode = SelectionHistoryMode::Normal;
15922
15923            self.select_next_state = entry.select_next_state;
15924            self.select_prev_state = entry.select_prev_state;
15925            self.add_selections_state = entry.add_selections_state;
15926        }
15927    }
15928
15929    pub fn expand_excerpts(
15930        &mut self,
15931        action: &ExpandExcerpts,
15932        _: &mut Window,
15933        cx: &mut Context<Self>,
15934    ) {
15935        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15936    }
15937
15938    pub fn expand_excerpts_down(
15939        &mut self,
15940        action: &ExpandExcerptsDown,
15941        _: &mut Window,
15942        cx: &mut Context<Self>,
15943    ) {
15944        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15945    }
15946
15947    pub fn expand_excerpts_up(
15948        &mut self,
15949        action: &ExpandExcerptsUp,
15950        _: &mut Window,
15951        cx: &mut Context<Self>,
15952    ) {
15953        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15954    }
15955
15956    pub fn expand_excerpts_for_direction(
15957        &mut self,
15958        lines: u32,
15959        direction: ExpandExcerptDirection,
15960
15961        cx: &mut Context<Self>,
15962    ) {
15963        let selections = self.selections.disjoint_anchors_arc();
15964
15965        let lines = if lines == 0 {
15966            EditorSettings::get_global(cx).expand_excerpt_lines
15967        } else {
15968            lines
15969        };
15970
15971        self.buffer.update(cx, |buffer, cx| {
15972            let snapshot = buffer.snapshot(cx);
15973            let mut excerpt_ids = selections
15974                .iter()
15975                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15976                .collect::<Vec<_>>();
15977            excerpt_ids.sort();
15978            excerpt_ids.dedup();
15979            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15980        })
15981    }
15982
15983    pub fn expand_excerpt(
15984        &mut self,
15985        excerpt: ExcerptId,
15986        direction: ExpandExcerptDirection,
15987        window: &mut Window,
15988        cx: &mut Context<Self>,
15989    ) {
15990        let current_scroll_position = self.scroll_position(cx);
15991        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15992        let mut scroll = None;
15993
15994        if direction == ExpandExcerptDirection::Down {
15995            let multi_buffer = self.buffer.read(cx);
15996            let snapshot = multi_buffer.snapshot(cx);
15997            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15998                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15999                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16000            {
16001                let buffer_snapshot = buffer.read(cx).snapshot();
16002                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16003                let last_row = buffer_snapshot.max_point().row;
16004                let lines_below = last_row.saturating_sub(excerpt_end_row);
16005                if lines_below >= lines_to_expand {
16006                    scroll = Some(
16007                        current_scroll_position
16008                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
16009                    );
16010                }
16011            }
16012        }
16013        if direction == ExpandExcerptDirection::Up
16014            && self
16015                .buffer
16016                .read(cx)
16017                .snapshot(cx)
16018                .excerpt_before(excerpt)
16019                .is_none()
16020        {
16021            scroll = Some(current_scroll_position);
16022        }
16023
16024        self.buffer.update(cx, |buffer, cx| {
16025            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16026        });
16027
16028        if let Some(new_scroll_position) = scroll {
16029            self.set_scroll_position(new_scroll_position, window, cx);
16030        }
16031    }
16032
16033    pub fn go_to_singleton_buffer_point(
16034        &mut self,
16035        point: Point,
16036        window: &mut Window,
16037        cx: &mut Context<Self>,
16038    ) {
16039        self.go_to_singleton_buffer_range(point..point, window, cx);
16040    }
16041
16042    pub fn go_to_singleton_buffer_range(
16043        &mut self,
16044        range: Range<Point>,
16045        window: &mut Window,
16046        cx: &mut Context<Self>,
16047    ) {
16048        let multibuffer = self.buffer().read(cx);
16049        let Some(buffer) = multibuffer.as_singleton() else {
16050            return;
16051        };
16052        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16053            return;
16054        };
16055        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16056            return;
16057        };
16058        self.change_selections(
16059            SelectionEffects::default().nav_history(true),
16060            window,
16061            cx,
16062            |s| s.select_anchor_ranges([start..end]),
16063        );
16064    }
16065
16066    pub fn go_to_diagnostic(
16067        &mut self,
16068        action: &GoToDiagnostic,
16069        window: &mut Window,
16070        cx: &mut Context<Self>,
16071    ) {
16072        if !self.diagnostics_enabled() {
16073            return;
16074        }
16075        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16076        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16077    }
16078
16079    pub fn go_to_prev_diagnostic(
16080        &mut self,
16081        action: &GoToPreviousDiagnostic,
16082        window: &mut Window,
16083        cx: &mut Context<Self>,
16084    ) {
16085        if !self.diagnostics_enabled() {
16086            return;
16087        }
16088        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16089        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16090    }
16091
16092    pub fn go_to_diagnostic_impl(
16093        &mut self,
16094        direction: Direction,
16095        severity: GoToDiagnosticSeverityFilter,
16096        window: &mut Window,
16097        cx: &mut Context<Self>,
16098    ) {
16099        let buffer = self.buffer.read(cx).snapshot(cx);
16100        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
16101
16102        let mut active_group_id = None;
16103        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16104            && active_group.active_range.start.to_offset(&buffer) == selection.start
16105        {
16106            active_group_id = Some(active_group.group_id);
16107        }
16108
16109        fn filtered<'a>(
16110            severity: GoToDiagnosticSeverityFilter,
16111            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
16112        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
16113            diagnostics
16114                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16115                .filter(|entry| entry.range.start != entry.range.end)
16116                .filter(|entry| !entry.diagnostic.is_unnecessary)
16117        }
16118
16119        let before = filtered(
16120            severity,
16121            buffer
16122                .diagnostics_in_range(0..selection.start)
16123                .filter(|entry| entry.range.start <= selection.start),
16124        );
16125        let after = filtered(
16126            severity,
16127            buffer
16128                .diagnostics_in_range(selection.start..buffer.len())
16129                .filter(|entry| entry.range.start >= selection.start),
16130        );
16131
16132        let mut found: Option<DiagnosticEntryRef<usize>> = None;
16133        if direction == Direction::Prev {
16134            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16135            {
16136                for diagnostic in prev_diagnostics.into_iter().rev() {
16137                    if diagnostic.range.start != selection.start
16138                        || active_group_id
16139                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16140                    {
16141                        found = Some(diagnostic);
16142                        break 'outer;
16143                    }
16144                }
16145            }
16146        } else {
16147            for diagnostic in after.chain(before) {
16148                if diagnostic.range.start != selection.start
16149                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16150                {
16151                    found = Some(diagnostic);
16152                    break;
16153                }
16154            }
16155        }
16156        let Some(next_diagnostic) = found else {
16157            return;
16158        };
16159
16160        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16161        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16162            return;
16163        };
16164        let snapshot = self.snapshot(window, cx);
16165        if snapshot.intersects_fold(next_diagnostic.range.start) {
16166            self.unfold_ranges(
16167                std::slice::from_ref(&next_diagnostic.range),
16168                true,
16169                false,
16170                cx,
16171            );
16172        }
16173        self.change_selections(Default::default(), window, cx, |s| {
16174            s.select_ranges(vec![
16175                next_diagnostic.range.start..next_diagnostic.range.start,
16176            ])
16177        });
16178        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16179        self.refresh_edit_prediction(false, true, window, cx);
16180    }
16181
16182    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16183        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16184        let snapshot = self.snapshot(window, cx);
16185        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16186        self.go_to_hunk_before_or_after_position(
16187            &snapshot,
16188            selection.head(),
16189            Direction::Next,
16190            window,
16191            cx,
16192        );
16193    }
16194
16195    pub fn go_to_hunk_before_or_after_position(
16196        &mut self,
16197        snapshot: &EditorSnapshot,
16198        position: Point,
16199        direction: Direction,
16200        window: &mut Window,
16201        cx: &mut Context<Editor>,
16202    ) {
16203        let row = if direction == Direction::Next {
16204            self.hunk_after_position(snapshot, position)
16205                .map(|hunk| hunk.row_range.start)
16206        } else {
16207            self.hunk_before_position(snapshot, position)
16208        };
16209
16210        if let Some(row) = row {
16211            let destination = Point::new(row.0, 0);
16212            let autoscroll = Autoscroll::center();
16213
16214            self.unfold_ranges(&[destination..destination], false, false, cx);
16215            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16216                s.select_ranges([destination..destination]);
16217            });
16218        }
16219    }
16220
16221    fn hunk_after_position(
16222        &mut self,
16223        snapshot: &EditorSnapshot,
16224        position: Point,
16225    ) -> Option<MultiBufferDiffHunk> {
16226        snapshot
16227            .buffer_snapshot()
16228            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16229            .find(|hunk| hunk.row_range.start.0 > position.row)
16230            .or_else(|| {
16231                snapshot
16232                    .buffer_snapshot()
16233                    .diff_hunks_in_range(Point::zero()..position)
16234                    .find(|hunk| hunk.row_range.end.0 < position.row)
16235            })
16236    }
16237
16238    fn go_to_prev_hunk(
16239        &mut self,
16240        _: &GoToPreviousHunk,
16241        window: &mut Window,
16242        cx: &mut Context<Self>,
16243    ) {
16244        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16245        let snapshot = self.snapshot(window, cx);
16246        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16247        self.go_to_hunk_before_or_after_position(
16248            &snapshot,
16249            selection.head(),
16250            Direction::Prev,
16251            window,
16252            cx,
16253        );
16254    }
16255
16256    fn hunk_before_position(
16257        &mut self,
16258        snapshot: &EditorSnapshot,
16259        position: Point,
16260    ) -> Option<MultiBufferRow> {
16261        snapshot
16262            .buffer_snapshot()
16263            .diff_hunk_before(position)
16264            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16265    }
16266
16267    fn go_to_next_change(
16268        &mut self,
16269        _: &GoToNextChange,
16270        window: &mut Window,
16271        cx: &mut Context<Self>,
16272    ) {
16273        if let Some(selections) = self
16274            .change_list
16275            .next_change(1, Direction::Next)
16276            .map(|s| s.to_vec())
16277        {
16278            self.change_selections(Default::default(), window, cx, |s| {
16279                let map = s.display_map();
16280                s.select_display_ranges(selections.iter().map(|a| {
16281                    let point = a.to_display_point(&map);
16282                    point..point
16283                }))
16284            })
16285        }
16286    }
16287
16288    fn go_to_previous_change(
16289        &mut self,
16290        _: &GoToPreviousChange,
16291        window: &mut Window,
16292        cx: &mut Context<Self>,
16293    ) {
16294        if let Some(selections) = self
16295            .change_list
16296            .next_change(1, Direction::Prev)
16297            .map(|s| s.to_vec())
16298        {
16299            self.change_selections(Default::default(), window, cx, |s| {
16300                let map = s.display_map();
16301                s.select_display_ranges(selections.iter().map(|a| {
16302                    let point = a.to_display_point(&map);
16303                    point..point
16304                }))
16305            })
16306        }
16307    }
16308
16309    pub fn go_to_next_document_highlight(
16310        &mut self,
16311        _: &GoToNextDocumentHighlight,
16312        window: &mut Window,
16313        cx: &mut Context<Self>,
16314    ) {
16315        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16316    }
16317
16318    pub fn go_to_prev_document_highlight(
16319        &mut self,
16320        _: &GoToPreviousDocumentHighlight,
16321        window: &mut Window,
16322        cx: &mut Context<Self>,
16323    ) {
16324        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16325    }
16326
16327    pub fn go_to_document_highlight_before_or_after_position(
16328        &mut self,
16329        direction: Direction,
16330        window: &mut Window,
16331        cx: &mut Context<Editor>,
16332    ) {
16333        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16334        let snapshot = self.snapshot(window, cx);
16335        let buffer = &snapshot.buffer_snapshot();
16336        let position = self
16337            .selections
16338            .newest::<Point>(&snapshot.display_snapshot)
16339            .head();
16340        let anchor_position = buffer.anchor_after(position);
16341
16342        // Get all document highlights (both read and write)
16343        let mut all_highlights = Vec::new();
16344
16345        if let Some((_, read_highlights)) = self
16346            .background_highlights
16347            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16348        {
16349            all_highlights.extend(read_highlights.iter());
16350        }
16351
16352        if let Some((_, write_highlights)) = self
16353            .background_highlights
16354            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16355        {
16356            all_highlights.extend(write_highlights.iter());
16357        }
16358
16359        if all_highlights.is_empty() {
16360            return;
16361        }
16362
16363        // Sort highlights by position
16364        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16365
16366        let target_highlight = match direction {
16367            Direction::Next => {
16368                // Find the first highlight after the current position
16369                all_highlights
16370                    .iter()
16371                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16372            }
16373            Direction::Prev => {
16374                // Find the last highlight before the current position
16375                all_highlights
16376                    .iter()
16377                    .rev()
16378                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16379            }
16380        };
16381
16382        if let Some(highlight) = target_highlight {
16383            let destination = highlight.start.to_point(buffer);
16384            let autoscroll = Autoscroll::center();
16385
16386            self.unfold_ranges(&[destination..destination], false, false, cx);
16387            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16388                s.select_ranges([destination..destination]);
16389            });
16390        }
16391    }
16392
16393    fn go_to_line<T: 'static>(
16394        &mut self,
16395        position: Anchor,
16396        highlight_color: Option<Hsla>,
16397        window: &mut Window,
16398        cx: &mut Context<Self>,
16399    ) {
16400        let snapshot = self.snapshot(window, cx).display_snapshot;
16401        let position = position.to_point(&snapshot.buffer_snapshot());
16402        let start = snapshot
16403            .buffer_snapshot()
16404            .clip_point(Point::new(position.row, 0), Bias::Left);
16405        let end = start + Point::new(1, 0);
16406        let start = snapshot.buffer_snapshot().anchor_before(start);
16407        let end = snapshot.buffer_snapshot().anchor_before(end);
16408
16409        self.highlight_rows::<T>(
16410            start..end,
16411            highlight_color
16412                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16413            Default::default(),
16414            cx,
16415        );
16416
16417        if self.buffer.read(cx).is_singleton() {
16418            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16419        }
16420    }
16421
16422    pub fn go_to_definition(
16423        &mut self,
16424        _: &GoToDefinition,
16425        window: &mut Window,
16426        cx: &mut Context<Self>,
16427    ) -> Task<Result<Navigated>> {
16428        let definition =
16429            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16430        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16431        cx.spawn_in(window, async move |editor, cx| {
16432            if definition.await? == Navigated::Yes {
16433                return Ok(Navigated::Yes);
16434            }
16435            match fallback_strategy {
16436                GoToDefinitionFallback::None => Ok(Navigated::No),
16437                GoToDefinitionFallback::FindAllReferences => {
16438                    match editor.update_in(cx, |editor, window, cx| {
16439                        editor.find_all_references(&FindAllReferences, window, cx)
16440                    })? {
16441                        Some(references) => references.await,
16442                        None => Ok(Navigated::No),
16443                    }
16444                }
16445            }
16446        })
16447    }
16448
16449    pub fn go_to_declaration(
16450        &mut self,
16451        _: &GoToDeclaration,
16452        window: &mut Window,
16453        cx: &mut Context<Self>,
16454    ) -> Task<Result<Navigated>> {
16455        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16456    }
16457
16458    pub fn go_to_declaration_split(
16459        &mut self,
16460        _: &GoToDeclaration,
16461        window: &mut Window,
16462        cx: &mut Context<Self>,
16463    ) -> Task<Result<Navigated>> {
16464        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16465    }
16466
16467    pub fn go_to_implementation(
16468        &mut self,
16469        _: &GoToImplementation,
16470        window: &mut Window,
16471        cx: &mut Context<Self>,
16472    ) -> Task<Result<Navigated>> {
16473        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16474    }
16475
16476    pub fn go_to_implementation_split(
16477        &mut self,
16478        _: &GoToImplementationSplit,
16479        window: &mut Window,
16480        cx: &mut Context<Self>,
16481    ) -> Task<Result<Navigated>> {
16482        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16483    }
16484
16485    pub fn go_to_type_definition(
16486        &mut self,
16487        _: &GoToTypeDefinition,
16488        window: &mut Window,
16489        cx: &mut Context<Self>,
16490    ) -> Task<Result<Navigated>> {
16491        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16492    }
16493
16494    pub fn go_to_definition_split(
16495        &mut self,
16496        _: &GoToDefinitionSplit,
16497        window: &mut Window,
16498        cx: &mut Context<Self>,
16499    ) -> Task<Result<Navigated>> {
16500        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16501    }
16502
16503    pub fn go_to_type_definition_split(
16504        &mut self,
16505        _: &GoToTypeDefinitionSplit,
16506        window: &mut Window,
16507        cx: &mut Context<Self>,
16508    ) -> Task<Result<Navigated>> {
16509        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16510    }
16511
16512    fn go_to_definition_of_kind(
16513        &mut self,
16514        kind: GotoDefinitionKind,
16515        split: bool,
16516        window: &mut Window,
16517        cx: &mut Context<Self>,
16518    ) -> Task<Result<Navigated>> {
16519        let Some(provider) = self.semantics_provider.clone() else {
16520            return Task::ready(Ok(Navigated::No));
16521        };
16522        let head = self
16523            .selections
16524            .newest::<usize>(&self.display_snapshot(cx))
16525            .head();
16526        let buffer = self.buffer.read(cx);
16527        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16528            return Task::ready(Ok(Navigated::No));
16529        };
16530        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16531            return Task::ready(Ok(Navigated::No));
16532        };
16533
16534        cx.spawn_in(window, async move |editor, cx| {
16535            let Some(definitions) = definitions.await? else {
16536                return Ok(Navigated::No);
16537            };
16538            let navigated = editor
16539                .update_in(cx, |editor, window, cx| {
16540                    editor.navigate_to_hover_links(
16541                        Some(kind),
16542                        definitions
16543                            .into_iter()
16544                            .filter(|location| {
16545                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16546                            })
16547                            .map(HoverLink::Text)
16548                            .collect::<Vec<_>>(),
16549                        split,
16550                        window,
16551                        cx,
16552                    )
16553                })?
16554                .await?;
16555            anyhow::Ok(navigated)
16556        })
16557    }
16558
16559    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16560        let selection = self.selections.newest_anchor();
16561        let head = selection.head();
16562        let tail = selection.tail();
16563
16564        let Some((buffer, start_position)) =
16565            self.buffer.read(cx).text_anchor_for_position(head, cx)
16566        else {
16567            return;
16568        };
16569
16570        let end_position = if head != tail {
16571            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16572                return;
16573            };
16574            Some(pos)
16575        } else {
16576            None
16577        };
16578
16579        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16580            let url = if let Some(end_pos) = end_position {
16581                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16582            } else {
16583                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16584            };
16585
16586            if let Some(url) = url {
16587                cx.update(|window, cx| {
16588                    if parse_zed_link(&url, cx).is_some() {
16589                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16590                    } else {
16591                        cx.open_url(&url);
16592                    }
16593                })?;
16594            }
16595
16596            anyhow::Ok(())
16597        });
16598
16599        url_finder.detach();
16600    }
16601
16602    pub fn open_selected_filename(
16603        &mut self,
16604        _: &OpenSelectedFilename,
16605        window: &mut Window,
16606        cx: &mut Context<Self>,
16607    ) {
16608        let Some(workspace) = self.workspace() else {
16609            return;
16610        };
16611
16612        let position = self.selections.newest_anchor().head();
16613
16614        let Some((buffer, buffer_position)) =
16615            self.buffer.read(cx).text_anchor_for_position(position, cx)
16616        else {
16617            return;
16618        };
16619
16620        let project = self.project.clone();
16621
16622        cx.spawn_in(window, async move |_, cx| {
16623            let result = find_file(&buffer, project, buffer_position, cx).await;
16624
16625            if let Some((_, path)) = result {
16626                workspace
16627                    .update_in(cx, |workspace, window, cx| {
16628                        workspace.open_resolved_path(path, window, cx)
16629                    })?
16630                    .await?;
16631            }
16632            anyhow::Ok(())
16633        })
16634        .detach();
16635    }
16636
16637    pub(crate) fn navigate_to_hover_links(
16638        &mut self,
16639        kind: Option<GotoDefinitionKind>,
16640        definitions: Vec<HoverLink>,
16641        split: bool,
16642        window: &mut Window,
16643        cx: &mut Context<Editor>,
16644    ) -> Task<Result<Navigated>> {
16645        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16646        let mut first_url_or_file = None;
16647        let definitions: Vec<_> = definitions
16648            .into_iter()
16649            .filter_map(|def| match def {
16650                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16651                HoverLink::InlayHint(lsp_location, server_id) => {
16652                    let computation =
16653                        self.compute_target_location(lsp_location, server_id, window, cx);
16654                    Some(cx.background_spawn(computation))
16655                }
16656                HoverLink::Url(url) => {
16657                    first_url_or_file = Some(Either::Left(url));
16658                    None
16659                }
16660                HoverLink::File(path) => {
16661                    first_url_or_file = Some(Either::Right(path));
16662                    None
16663                }
16664            })
16665            .collect();
16666
16667        let workspace = self.workspace();
16668
16669        cx.spawn_in(window, async move |editor, cx| {
16670            let locations: Vec<Location> = future::join_all(definitions)
16671                .await
16672                .into_iter()
16673                .filter_map(|location| location.transpose())
16674                .collect::<Result<_>>()
16675                .context("location tasks")?;
16676            let mut locations = cx.update(|_, cx| {
16677                locations
16678                    .into_iter()
16679                    .map(|location| {
16680                        let buffer = location.buffer.read(cx);
16681                        (location.buffer, location.range.to_point(buffer))
16682                    })
16683                    .into_group_map()
16684            })?;
16685            let mut num_locations = 0;
16686            for ranges in locations.values_mut() {
16687                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16688                ranges.dedup();
16689                num_locations += ranges.len();
16690            }
16691
16692            if num_locations > 1 {
16693                let Some(workspace) = workspace else {
16694                    return Ok(Navigated::No);
16695                };
16696
16697                let tab_kind = match kind {
16698                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16699                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16700                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16701                    Some(GotoDefinitionKind::Type) => "Types",
16702                };
16703                let title = editor
16704                    .update_in(cx, |_, _, cx| {
16705                        let target = locations
16706                            .iter()
16707                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16708                            .map(|(buffer, location)| {
16709                                buffer
16710                                    .read(cx)
16711                                    .text_for_range(location.clone())
16712                                    .collect::<String>()
16713                            })
16714                            .filter(|text| !text.contains('\n'))
16715                            .unique()
16716                            .take(3)
16717                            .join(", ");
16718                        if target.is_empty() {
16719                            tab_kind.to_owned()
16720                        } else {
16721                            format!("{tab_kind} for {target}")
16722                        }
16723                    })
16724                    .context("buffer title")?;
16725
16726                let opened = workspace
16727                    .update_in(cx, |workspace, window, cx| {
16728                        Self::open_locations_in_multibuffer(
16729                            workspace,
16730                            locations,
16731                            title,
16732                            split,
16733                            MultibufferSelectionMode::First,
16734                            window,
16735                            cx,
16736                        )
16737                    })
16738                    .is_ok();
16739
16740                anyhow::Ok(Navigated::from_bool(opened))
16741            } else if num_locations == 0 {
16742                // If there is one url or file, open it directly
16743                match first_url_or_file {
16744                    Some(Either::Left(url)) => {
16745                        cx.update(|_, cx| cx.open_url(&url))?;
16746                        Ok(Navigated::Yes)
16747                    }
16748                    Some(Either::Right(path)) => {
16749                        let Some(workspace) = workspace else {
16750                            return Ok(Navigated::No);
16751                        };
16752
16753                        workspace
16754                            .update_in(cx, |workspace, window, cx| {
16755                                workspace.open_resolved_path(path, window, cx)
16756                            })?
16757                            .await?;
16758                        Ok(Navigated::Yes)
16759                    }
16760                    None => Ok(Navigated::No),
16761                }
16762            } else {
16763                let Some(workspace) = workspace else {
16764                    return Ok(Navigated::No);
16765                };
16766
16767                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16768                let target_range = target_ranges.first().unwrap().clone();
16769
16770                editor.update_in(cx, |editor, window, cx| {
16771                    let range = target_range.to_point(target_buffer.read(cx));
16772                    let range = editor.range_for_match(&range, false);
16773                    let range = collapse_multiline_range(range);
16774
16775                    if !split
16776                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16777                    {
16778                        editor.go_to_singleton_buffer_range(range, window, cx);
16779                    } else {
16780                        let pane = workspace.read(cx).active_pane().clone();
16781                        window.defer(cx, move |window, cx| {
16782                            let target_editor: Entity<Self> =
16783                                workspace.update(cx, |workspace, cx| {
16784                                    let pane = if split {
16785                                        workspace.adjacent_pane(window, cx)
16786                                    } else {
16787                                        workspace.active_pane().clone()
16788                                    };
16789
16790                                    workspace.open_project_item(
16791                                        pane,
16792                                        target_buffer.clone(),
16793                                        true,
16794                                        true,
16795                                        window,
16796                                        cx,
16797                                    )
16798                                });
16799                            target_editor.update(cx, |target_editor, cx| {
16800                                // When selecting a definition in a different buffer, disable the nav history
16801                                // to avoid creating a history entry at the previous cursor location.
16802                                pane.update(cx, |pane, _| pane.disable_history());
16803                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16804                                pane.update(cx, |pane, _| pane.enable_history());
16805                            });
16806                        });
16807                    }
16808                    Navigated::Yes
16809                })
16810            }
16811        })
16812    }
16813
16814    fn compute_target_location(
16815        &self,
16816        lsp_location: lsp::Location,
16817        server_id: LanguageServerId,
16818        window: &mut Window,
16819        cx: &mut Context<Self>,
16820    ) -> Task<anyhow::Result<Option<Location>>> {
16821        let Some(project) = self.project.clone() else {
16822            return Task::ready(Ok(None));
16823        };
16824
16825        cx.spawn_in(window, async move |editor, cx| {
16826            let location_task = editor.update(cx, |_, cx| {
16827                project.update(cx, |project, cx| {
16828                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16829                })
16830            })?;
16831            let location = Some({
16832                let target_buffer_handle = location_task.await.context("open local buffer")?;
16833                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16834                    let target_start = target_buffer
16835                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16836                    let target_end = target_buffer
16837                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16838                    target_buffer.anchor_after(target_start)
16839                        ..target_buffer.anchor_before(target_end)
16840                })?;
16841                Location {
16842                    buffer: target_buffer_handle,
16843                    range,
16844                }
16845            });
16846            Ok(location)
16847        })
16848    }
16849
16850    fn go_to_next_reference(
16851        &mut self,
16852        _: &GoToNextReference,
16853        window: &mut Window,
16854        cx: &mut Context<Self>,
16855    ) {
16856        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
16857        if let Some(task) = task {
16858            task.detach();
16859        };
16860    }
16861
16862    fn go_to_prev_reference(
16863        &mut self,
16864        _: &GoToPreviousReference,
16865        window: &mut Window,
16866        cx: &mut Context<Self>,
16867    ) {
16868        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
16869        if let Some(task) = task {
16870            task.detach();
16871        };
16872    }
16873
16874    pub fn go_to_reference_before_or_after_position(
16875        &mut self,
16876        direction: Direction,
16877        count: usize,
16878        window: &mut Window,
16879        cx: &mut Context<Self>,
16880    ) -> Option<Task<Result<()>>> {
16881        let selection = self.selections.newest_anchor();
16882        let head = selection.head();
16883
16884        let multi_buffer = self.buffer.read(cx);
16885
16886        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
16887        let workspace = self.workspace()?;
16888        let project = workspace.read(cx).project().clone();
16889        let references =
16890            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
16891        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
16892            let Some(locations) = references.await? else {
16893                return Ok(());
16894            };
16895
16896            if locations.is_empty() {
16897                // totally normal - the cursor may be on something which is not
16898                // a symbol (e.g. a keyword)
16899                log::info!("no references found under cursor");
16900                return Ok(());
16901            }
16902
16903            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
16904
16905            let multi_buffer_snapshot =
16906                multi_buffer.read_with(cx, |multi_buffer, cx| multi_buffer.snapshot(cx))?;
16907
16908            let (locations, current_location_index) =
16909                multi_buffer.update(cx, |multi_buffer, cx| {
16910                    let mut locations = locations
16911                        .into_iter()
16912                        .filter_map(|loc| {
16913                            let start = multi_buffer.buffer_anchor_to_anchor(
16914                                &loc.buffer,
16915                                loc.range.start,
16916                                cx,
16917                            )?;
16918                            let end = multi_buffer.buffer_anchor_to_anchor(
16919                                &loc.buffer,
16920                                loc.range.end,
16921                                cx,
16922                            )?;
16923                            Some(start..end)
16924                        })
16925                        .collect::<Vec<_>>();
16926
16927                    // There is an O(n) implementation, but given this list will be
16928                    // small (usually <100 items), the extra O(log(n)) factor isn't
16929                    // worth the (surprisingly large amount of) extra complexity.
16930                    locations
16931                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
16932
16933                    let head_offset = head.to_offset(&multi_buffer_snapshot);
16934
16935                    let current_location_index = locations.iter().position(|loc| {
16936                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
16937                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
16938                    });
16939
16940                    (locations, current_location_index)
16941                })?;
16942
16943            let Some(current_location_index) = current_location_index else {
16944                // This indicates something has gone wrong, because we already
16945                // handle the "no references" case above
16946                log::error!(
16947                    "failed to find current reference under cursor. Total references: {}",
16948                    locations.len()
16949                );
16950                return Ok(());
16951            };
16952
16953            let destination_location_index = match direction {
16954                Direction::Next => (current_location_index + count) % locations.len(),
16955                Direction::Prev => {
16956                    (current_location_index + locations.len() - count % locations.len())
16957                        % locations.len()
16958                }
16959            };
16960
16961            // TODO(cameron): is this needed?
16962            // the thinking is to avoid "jumping to the current location" (avoid
16963            // polluting "jumplist" in vim terms)
16964            if current_location_index == destination_location_index {
16965                return Ok(());
16966            }
16967
16968            let Range { start, end } = locations[destination_location_index];
16969
16970            editor.update_in(cx, |editor, window, cx| {
16971                let effects = SelectionEffects::default();
16972
16973                editor.unfold_ranges(&[start..end], false, false, cx);
16974                editor.change_selections(effects, window, cx, |s| {
16975                    s.select_ranges([start..start]);
16976                });
16977            })?;
16978
16979            Ok(())
16980        }))
16981    }
16982
16983    pub fn find_all_references(
16984        &mut self,
16985        _: &FindAllReferences,
16986        window: &mut Window,
16987        cx: &mut Context<Self>,
16988    ) -> Option<Task<Result<Navigated>>> {
16989        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
16990        let multi_buffer = self.buffer.read(cx);
16991        let head = selection.head();
16992
16993        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16994        let head_anchor = multi_buffer_snapshot.anchor_at(
16995            head,
16996            if head < selection.tail() {
16997                Bias::Right
16998            } else {
16999                Bias::Left
17000            },
17001        );
17002
17003        match self
17004            .find_all_references_task_sources
17005            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17006        {
17007            Ok(_) => {
17008                log::info!(
17009                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
17010                );
17011                return None;
17012            }
17013            Err(i) => {
17014                self.find_all_references_task_sources.insert(i, head_anchor);
17015            }
17016        }
17017
17018        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
17019        let workspace = self.workspace()?;
17020        let project = workspace.read(cx).project().clone();
17021        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
17022        Some(cx.spawn_in(window, async move |editor, cx| {
17023            let _cleanup = cx.on_drop(&editor, move |editor, _| {
17024                if let Ok(i) = editor
17025                    .find_all_references_task_sources
17026                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17027                {
17028                    editor.find_all_references_task_sources.remove(i);
17029                }
17030            });
17031
17032            let Some(locations) = references.await? else {
17033                return anyhow::Ok(Navigated::No);
17034            };
17035            let mut locations = cx.update(|_, cx| {
17036                locations
17037                    .into_iter()
17038                    .map(|location| {
17039                        let buffer = location.buffer.read(cx);
17040                        (location.buffer, location.range.to_point(buffer))
17041                    })
17042                    .into_group_map()
17043            })?;
17044            if locations.is_empty() {
17045                return anyhow::Ok(Navigated::No);
17046            }
17047            for ranges in locations.values_mut() {
17048                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17049                ranges.dedup();
17050            }
17051
17052            workspace.update_in(cx, |workspace, window, cx| {
17053                let target = locations
17054                    .iter()
17055                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17056                    .map(|(buffer, location)| {
17057                        buffer
17058                            .read(cx)
17059                            .text_for_range(location.clone())
17060                            .collect::<String>()
17061                    })
17062                    .filter(|text| !text.contains('\n'))
17063                    .unique()
17064                    .take(3)
17065                    .join(", ");
17066                let title = if target.is_empty() {
17067                    "References".to_owned()
17068                } else {
17069                    format!("References to {target}")
17070                };
17071                Self::open_locations_in_multibuffer(
17072                    workspace,
17073                    locations,
17074                    title,
17075                    false,
17076                    MultibufferSelectionMode::First,
17077                    window,
17078                    cx,
17079                );
17080                Navigated::Yes
17081            })
17082        }))
17083    }
17084
17085    /// Opens a multibuffer with the given project locations in it
17086    pub fn open_locations_in_multibuffer(
17087        workspace: &mut Workspace,
17088        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
17089        title: String,
17090        split: bool,
17091        multibuffer_selection_mode: MultibufferSelectionMode,
17092        window: &mut Window,
17093        cx: &mut Context<Workspace>,
17094    ) {
17095        if locations.is_empty() {
17096            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
17097            return;
17098        }
17099
17100        let capability = workspace.project().read(cx).capability();
17101        let mut ranges = <Vec<Range<Anchor>>>::new();
17102
17103        // a key to find existing multibuffer editors with the same set of locations
17104        // to prevent us from opening more and more multibuffer tabs for searches and the like
17105        let mut key = (title.clone(), vec![]);
17106        let excerpt_buffer = cx.new(|cx| {
17107            let key = &mut key.1;
17108            let mut multibuffer = MultiBuffer::new(capability);
17109            for (buffer, mut ranges_for_buffer) in locations {
17110                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17111                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17112                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17113                    PathKey::for_buffer(&buffer, cx),
17114                    buffer.clone(),
17115                    ranges_for_buffer,
17116                    multibuffer_context_lines(cx),
17117                    cx,
17118                );
17119                ranges.extend(new_ranges)
17120            }
17121
17122            multibuffer.with_title(title)
17123        });
17124        let existing = workspace.active_pane().update(cx, |pane, cx| {
17125            pane.items()
17126                .filter_map(|item| item.downcast::<Editor>())
17127                .find(|editor| {
17128                    editor
17129                        .read(cx)
17130                        .lookup_key
17131                        .as_ref()
17132                        .and_then(|it| {
17133                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17134                        })
17135                        .is_some_and(|it| *it == key)
17136                })
17137        });
17138        let editor = existing.unwrap_or_else(|| {
17139            cx.new(|cx| {
17140                let mut editor = Editor::for_multibuffer(
17141                    excerpt_buffer,
17142                    Some(workspace.project().clone()),
17143                    window,
17144                    cx,
17145                );
17146                editor.lookup_key = Some(Box::new(key));
17147                editor
17148            })
17149        });
17150        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17151            MultibufferSelectionMode::First => {
17152                if let Some(first_range) = ranges.first() {
17153                    editor.change_selections(
17154                        SelectionEffects::no_scroll(),
17155                        window,
17156                        cx,
17157                        |selections| {
17158                            selections.clear_disjoint();
17159                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17160                        },
17161                    );
17162                }
17163                editor.highlight_background::<Self>(
17164                    &ranges,
17165                    |theme| theme.colors().editor_highlighted_line_background,
17166                    cx,
17167                );
17168            }
17169            MultibufferSelectionMode::All => {
17170                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17171                    selections.clear_disjoint();
17172                    selections.select_anchor_ranges(ranges);
17173                });
17174            }
17175        });
17176
17177        let item = Box::new(editor);
17178        let item_id = item.item_id();
17179
17180        if split {
17181            let pane = workspace.adjacent_pane(window, cx);
17182            workspace.add_item(pane, item, None, true, true, window, cx);
17183        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
17184            let (preview_item_id, preview_item_idx) =
17185                workspace.active_pane().read_with(cx, |pane, _| {
17186                    (pane.preview_item_id(), pane.preview_item_idx())
17187                });
17188
17189            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
17190
17191            if let Some(preview_item_id) = preview_item_id {
17192                workspace.active_pane().update(cx, |pane, cx| {
17193                    pane.remove_item(preview_item_id, false, false, window, cx);
17194                });
17195            }
17196        } else {
17197            workspace.add_item_to_active_pane(item, None, true, window, cx);
17198        }
17199        workspace.active_pane().update(cx, |pane, cx| {
17200            pane.set_preview_item_id(Some(item_id), cx);
17201        });
17202    }
17203
17204    pub fn rename(
17205        &mut self,
17206        _: &Rename,
17207        window: &mut Window,
17208        cx: &mut Context<Self>,
17209    ) -> Option<Task<Result<()>>> {
17210        use language::ToOffset as _;
17211
17212        let provider = self.semantics_provider.clone()?;
17213        let selection = self.selections.newest_anchor().clone();
17214        let (cursor_buffer, cursor_buffer_position) = self
17215            .buffer
17216            .read(cx)
17217            .text_anchor_for_position(selection.head(), cx)?;
17218        let (tail_buffer, cursor_buffer_position_end) = self
17219            .buffer
17220            .read(cx)
17221            .text_anchor_for_position(selection.tail(), cx)?;
17222        if tail_buffer != cursor_buffer {
17223            return None;
17224        }
17225
17226        let snapshot = cursor_buffer.read(cx).snapshot();
17227        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17228        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17229        let prepare_rename = provider
17230            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17231            .unwrap_or_else(|| Task::ready(Ok(None)));
17232        drop(snapshot);
17233
17234        Some(cx.spawn_in(window, async move |this, cx| {
17235            let rename_range = if let Some(range) = prepare_rename.await? {
17236                Some(range)
17237            } else {
17238                this.update(cx, |this, cx| {
17239                    let buffer = this.buffer.read(cx).snapshot(cx);
17240                    let mut buffer_highlights = this
17241                        .document_highlights_for_position(selection.head(), &buffer)
17242                        .filter(|highlight| {
17243                            highlight.start.excerpt_id == selection.head().excerpt_id
17244                                && highlight.end.excerpt_id == selection.head().excerpt_id
17245                        });
17246                    buffer_highlights
17247                        .next()
17248                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17249                })?
17250            };
17251            if let Some(rename_range) = rename_range {
17252                this.update_in(cx, |this, window, cx| {
17253                    let snapshot = cursor_buffer.read(cx).snapshot();
17254                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17255                    let cursor_offset_in_rename_range =
17256                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17257                    let cursor_offset_in_rename_range_end =
17258                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17259
17260                    this.take_rename(false, window, cx);
17261                    let buffer = this.buffer.read(cx).read(cx);
17262                    let cursor_offset = selection.head().to_offset(&buffer);
17263                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
17264                    let rename_end = rename_start + rename_buffer_range.len();
17265                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17266                    let mut old_highlight_id = None;
17267                    let old_name: Arc<str> = buffer
17268                        .chunks(rename_start..rename_end, true)
17269                        .map(|chunk| {
17270                            if old_highlight_id.is_none() {
17271                                old_highlight_id = chunk.syntax_highlight_id;
17272                            }
17273                            chunk.text
17274                        })
17275                        .collect::<String>()
17276                        .into();
17277
17278                    drop(buffer);
17279
17280                    // Position the selection in the rename editor so that it matches the current selection.
17281                    this.show_local_selections = false;
17282                    let rename_editor = cx.new(|cx| {
17283                        let mut editor = Editor::single_line(window, cx);
17284                        editor.buffer.update(cx, |buffer, cx| {
17285                            buffer.edit([(0..0, old_name.clone())], None, cx)
17286                        });
17287                        let rename_selection_range = match cursor_offset_in_rename_range
17288                            .cmp(&cursor_offset_in_rename_range_end)
17289                        {
17290                            Ordering::Equal => {
17291                                editor.select_all(&SelectAll, window, cx);
17292                                return editor;
17293                            }
17294                            Ordering::Less => {
17295                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17296                            }
17297                            Ordering::Greater => {
17298                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17299                            }
17300                        };
17301                        if rename_selection_range.end > old_name.len() {
17302                            editor.select_all(&SelectAll, window, cx);
17303                        } else {
17304                            editor.change_selections(Default::default(), window, cx, |s| {
17305                                s.select_ranges([rename_selection_range]);
17306                            });
17307                        }
17308                        editor
17309                    });
17310                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17311                        if e == &EditorEvent::Focused {
17312                            cx.emit(EditorEvent::FocusedIn)
17313                        }
17314                    })
17315                    .detach();
17316
17317                    let write_highlights =
17318                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17319                    let read_highlights =
17320                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17321                    let ranges = write_highlights
17322                        .iter()
17323                        .flat_map(|(_, ranges)| ranges.iter())
17324                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17325                        .cloned()
17326                        .collect();
17327
17328                    this.highlight_text::<Rename>(
17329                        ranges,
17330                        HighlightStyle {
17331                            fade_out: Some(0.6),
17332                            ..Default::default()
17333                        },
17334                        cx,
17335                    );
17336                    let rename_focus_handle = rename_editor.focus_handle(cx);
17337                    window.focus(&rename_focus_handle);
17338                    let block_id = this.insert_blocks(
17339                        [BlockProperties {
17340                            style: BlockStyle::Flex,
17341                            placement: BlockPlacement::Below(range.start),
17342                            height: Some(1),
17343                            render: Arc::new({
17344                                let rename_editor = rename_editor.clone();
17345                                move |cx: &mut BlockContext| {
17346                                    let mut text_style = cx.editor_style.text.clone();
17347                                    if let Some(highlight_style) = old_highlight_id
17348                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17349                                    {
17350                                        text_style = text_style.highlight(highlight_style);
17351                                    }
17352                                    div()
17353                                        .block_mouse_except_scroll()
17354                                        .pl(cx.anchor_x)
17355                                        .child(EditorElement::new(
17356                                            &rename_editor,
17357                                            EditorStyle {
17358                                                background: cx.theme().system().transparent,
17359                                                local_player: cx.editor_style.local_player,
17360                                                text: text_style,
17361                                                scrollbar_width: cx.editor_style.scrollbar_width,
17362                                                syntax: cx.editor_style.syntax.clone(),
17363                                                status: cx.editor_style.status.clone(),
17364                                                inlay_hints_style: HighlightStyle {
17365                                                    font_weight: Some(FontWeight::BOLD),
17366                                                    ..make_inlay_hints_style(cx.app)
17367                                                },
17368                                                edit_prediction_styles: make_suggestion_styles(
17369                                                    cx.app,
17370                                                ),
17371                                                ..EditorStyle::default()
17372                                            },
17373                                        ))
17374                                        .into_any_element()
17375                                }
17376                            }),
17377                            priority: 0,
17378                        }],
17379                        Some(Autoscroll::fit()),
17380                        cx,
17381                    )[0];
17382                    this.pending_rename = Some(RenameState {
17383                        range,
17384                        old_name,
17385                        editor: rename_editor,
17386                        block_id,
17387                    });
17388                })?;
17389            }
17390
17391            Ok(())
17392        }))
17393    }
17394
17395    pub fn confirm_rename(
17396        &mut self,
17397        _: &ConfirmRename,
17398        window: &mut Window,
17399        cx: &mut Context<Self>,
17400    ) -> Option<Task<Result<()>>> {
17401        let rename = self.take_rename(false, window, cx)?;
17402        let workspace = self.workspace()?.downgrade();
17403        let (buffer, start) = self
17404            .buffer
17405            .read(cx)
17406            .text_anchor_for_position(rename.range.start, cx)?;
17407        let (end_buffer, _) = self
17408            .buffer
17409            .read(cx)
17410            .text_anchor_for_position(rename.range.end, cx)?;
17411        if buffer != end_buffer {
17412            return None;
17413        }
17414
17415        let old_name = rename.old_name;
17416        let new_name = rename.editor.read(cx).text(cx);
17417
17418        let rename = self.semantics_provider.as_ref()?.perform_rename(
17419            &buffer,
17420            start,
17421            new_name.clone(),
17422            cx,
17423        )?;
17424
17425        Some(cx.spawn_in(window, async move |editor, cx| {
17426            let project_transaction = rename.await?;
17427            Self::open_project_transaction(
17428                &editor,
17429                workspace,
17430                project_transaction,
17431                format!("Rename: {}{}", old_name, new_name),
17432                cx,
17433            )
17434            .await?;
17435
17436            editor.update(cx, |editor, cx| {
17437                editor.refresh_document_highlights(cx);
17438            })?;
17439            Ok(())
17440        }))
17441    }
17442
17443    fn take_rename(
17444        &mut self,
17445        moving_cursor: bool,
17446        window: &mut Window,
17447        cx: &mut Context<Self>,
17448    ) -> Option<RenameState> {
17449        let rename = self.pending_rename.take()?;
17450        if rename.editor.focus_handle(cx).is_focused(window) {
17451            window.focus(&self.focus_handle);
17452        }
17453
17454        self.remove_blocks(
17455            [rename.block_id].into_iter().collect(),
17456            Some(Autoscroll::fit()),
17457            cx,
17458        );
17459        self.clear_highlights::<Rename>(cx);
17460        self.show_local_selections = true;
17461
17462        if moving_cursor {
17463            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17464                editor
17465                    .selections
17466                    .newest::<usize>(&editor.display_snapshot(cx))
17467                    .head()
17468            });
17469
17470            // Update the selection to match the position of the selection inside
17471            // the rename editor.
17472            let snapshot = self.buffer.read(cx).read(cx);
17473            let rename_range = rename.range.to_offset(&snapshot);
17474            let cursor_in_editor = snapshot
17475                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17476                .min(rename_range.end);
17477            drop(snapshot);
17478
17479            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17480                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17481            });
17482        } else {
17483            self.refresh_document_highlights(cx);
17484        }
17485
17486        Some(rename)
17487    }
17488
17489    pub fn pending_rename(&self) -> Option<&RenameState> {
17490        self.pending_rename.as_ref()
17491    }
17492
17493    fn format(
17494        &mut self,
17495        _: &Format,
17496        window: &mut Window,
17497        cx: &mut Context<Self>,
17498    ) -> Option<Task<Result<()>>> {
17499        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17500
17501        let project = match &self.project {
17502            Some(project) => project.clone(),
17503            None => return None,
17504        };
17505
17506        Some(self.perform_format(
17507            project,
17508            FormatTrigger::Manual,
17509            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17510            window,
17511            cx,
17512        ))
17513    }
17514
17515    fn format_selections(
17516        &mut self,
17517        _: &FormatSelections,
17518        window: &mut Window,
17519        cx: &mut Context<Self>,
17520    ) -> Option<Task<Result<()>>> {
17521        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17522
17523        let project = match &self.project {
17524            Some(project) => project.clone(),
17525            None => return None,
17526        };
17527
17528        let ranges = self
17529            .selections
17530            .all_adjusted(&self.display_snapshot(cx))
17531            .into_iter()
17532            .map(|selection| selection.range())
17533            .collect_vec();
17534
17535        Some(self.perform_format(
17536            project,
17537            FormatTrigger::Manual,
17538            FormatTarget::Ranges(ranges),
17539            window,
17540            cx,
17541        ))
17542    }
17543
17544    fn perform_format(
17545        &mut self,
17546        project: Entity<Project>,
17547        trigger: FormatTrigger,
17548        target: FormatTarget,
17549        window: &mut Window,
17550        cx: &mut Context<Self>,
17551    ) -> Task<Result<()>> {
17552        let buffer = self.buffer.clone();
17553        let (buffers, target) = match target {
17554            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17555            FormatTarget::Ranges(selection_ranges) => {
17556                let multi_buffer = buffer.read(cx);
17557                let snapshot = multi_buffer.read(cx);
17558                let mut buffers = HashSet::default();
17559                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17560                    BTreeMap::new();
17561                for selection_range in selection_ranges {
17562                    for (buffer, buffer_range, _) in
17563                        snapshot.range_to_buffer_ranges(selection_range)
17564                    {
17565                        let buffer_id = buffer.remote_id();
17566                        let start = buffer.anchor_before(buffer_range.start);
17567                        let end = buffer.anchor_after(buffer_range.end);
17568                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17569                        buffer_id_to_ranges
17570                            .entry(buffer_id)
17571                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17572                            .or_insert_with(|| vec![start..end]);
17573                    }
17574                }
17575                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17576            }
17577        };
17578
17579        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17580        let selections_prev = transaction_id_prev
17581            .and_then(|transaction_id_prev| {
17582                // default to selections as they were after the last edit, if we have them,
17583                // instead of how they are now.
17584                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17585                // will take you back to where you made the last edit, instead of staying where you scrolled
17586                self.selection_history
17587                    .transaction(transaction_id_prev)
17588                    .map(|t| t.0.clone())
17589            })
17590            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17591
17592        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17593        let format = project.update(cx, |project, cx| {
17594            project.format(buffers, target, true, trigger, cx)
17595        });
17596
17597        cx.spawn_in(window, async move |editor, cx| {
17598            let transaction = futures::select_biased! {
17599                transaction = format.log_err().fuse() => transaction,
17600                () = timeout => {
17601                    log::warn!("timed out waiting for formatting");
17602                    None
17603                }
17604            };
17605
17606            buffer
17607                .update(cx, |buffer, cx| {
17608                    if let Some(transaction) = transaction
17609                        && !buffer.is_singleton()
17610                    {
17611                        buffer.push_transaction(&transaction.0, cx);
17612                    }
17613                    cx.notify();
17614                })
17615                .ok();
17616
17617            if let Some(transaction_id_now) =
17618                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17619            {
17620                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17621                if has_new_transaction {
17622                    _ = editor.update(cx, |editor, _| {
17623                        editor
17624                            .selection_history
17625                            .insert_transaction(transaction_id_now, selections_prev);
17626                    });
17627                }
17628            }
17629
17630            Ok(())
17631        })
17632    }
17633
17634    fn organize_imports(
17635        &mut self,
17636        _: &OrganizeImports,
17637        window: &mut Window,
17638        cx: &mut Context<Self>,
17639    ) -> Option<Task<Result<()>>> {
17640        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17641        let project = match &self.project {
17642            Some(project) => project.clone(),
17643            None => return None,
17644        };
17645        Some(self.perform_code_action_kind(
17646            project,
17647            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17648            window,
17649            cx,
17650        ))
17651    }
17652
17653    fn perform_code_action_kind(
17654        &mut self,
17655        project: Entity<Project>,
17656        kind: CodeActionKind,
17657        window: &mut Window,
17658        cx: &mut Context<Self>,
17659    ) -> Task<Result<()>> {
17660        let buffer = self.buffer.clone();
17661        let buffers = buffer.read(cx).all_buffers();
17662        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17663        let apply_action = project.update(cx, |project, cx| {
17664            project.apply_code_action_kind(buffers, kind, true, cx)
17665        });
17666        cx.spawn_in(window, async move |_, cx| {
17667            let transaction = futures::select_biased! {
17668                () = timeout => {
17669                    log::warn!("timed out waiting for executing code action");
17670                    None
17671                }
17672                transaction = apply_action.log_err().fuse() => transaction,
17673            };
17674            buffer
17675                .update(cx, |buffer, cx| {
17676                    // check if we need this
17677                    if let Some(transaction) = transaction
17678                        && !buffer.is_singleton()
17679                    {
17680                        buffer.push_transaction(&transaction.0, cx);
17681                    }
17682                    cx.notify();
17683                })
17684                .ok();
17685            Ok(())
17686        })
17687    }
17688
17689    pub fn restart_language_server(
17690        &mut self,
17691        _: &RestartLanguageServer,
17692        _: &mut Window,
17693        cx: &mut Context<Self>,
17694    ) {
17695        if let Some(project) = self.project.clone() {
17696            self.buffer.update(cx, |multi_buffer, cx| {
17697                project.update(cx, |project, cx| {
17698                    project.restart_language_servers_for_buffers(
17699                        multi_buffer.all_buffers().into_iter().collect(),
17700                        HashSet::default(),
17701                        cx,
17702                    );
17703                });
17704            })
17705        }
17706    }
17707
17708    pub fn stop_language_server(
17709        &mut self,
17710        _: &StopLanguageServer,
17711        _: &mut Window,
17712        cx: &mut Context<Self>,
17713    ) {
17714        if let Some(project) = self.project.clone() {
17715            self.buffer.update(cx, |multi_buffer, cx| {
17716                project.update(cx, |project, cx| {
17717                    project.stop_language_servers_for_buffers(
17718                        multi_buffer.all_buffers().into_iter().collect(),
17719                        HashSet::default(),
17720                        cx,
17721                    );
17722                });
17723            });
17724            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
17725        }
17726    }
17727
17728    fn cancel_language_server_work(
17729        workspace: &mut Workspace,
17730        _: &actions::CancelLanguageServerWork,
17731        _: &mut Window,
17732        cx: &mut Context<Workspace>,
17733    ) {
17734        let project = workspace.project();
17735        let buffers = workspace
17736            .active_item(cx)
17737            .and_then(|item| item.act_as::<Editor>(cx))
17738            .map_or(HashSet::default(), |editor| {
17739                editor.read(cx).buffer.read(cx).all_buffers()
17740            });
17741        project.update(cx, |project, cx| {
17742            project.cancel_language_server_work_for_buffers(buffers, cx);
17743        });
17744    }
17745
17746    fn show_character_palette(
17747        &mut self,
17748        _: &ShowCharacterPalette,
17749        window: &mut Window,
17750        _: &mut Context<Self>,
17751    ) {
17752        window.show_character_palette();
17753    }
17754
17755    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17756        if !self.diagnostics_enabled() {
17757            return;
17758        }
17759
17760        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17761            let buffer = self.buffer.read(cx).snapshot(cx);
17762            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17763            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17764            let is_valid = buffer
17765                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17766                .any(|entry| {
17767                    entry.diagnostic.is_primary
17768                        && !entry.range.is_empty()
17769                        && entry.range.start == primary_range_start
17770                        && entry.diagnostic.message == active_diagnostics.active_message
17771                });
17772
17773            if !is_valid {
17774                self.dismiss_diagnostics(cx);
17775            }
17776        }
17777    }
17778
17779    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17780        match &self.active_diagnostics {
17781            ActiveDiagnostic::Group(group) => Some(group),
17782            _ => None,
17783        }
17784    }
17785
17786    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17787        if !self.diagnostics_enabled() {
17788            return;
17789        }
17790        self.dismiss_diagnostics(cx);
17791        self.active_diagnostics = ActiveDiagnostic::All;
17792    }
17793
17794    fn activate_diagnostics(
17795        &mut self,
17796        buffer_id: BufferId,
17797        diagnostic: DiagnosticEntryRef<'_, usize>,
17798        window: &mut Window,
17799        cx: &mut Context<Self>,
17800    ) {
17801        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17802            return;
17803        }
17804        self.dismiss_diagnostics(cx);
17805        let snapshot = self.snapshot(window, cx);
17806        let buffer = self.buffer.read(cx).snapshot(cx);
17807        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17808            return;
17809        };
17810
17811        let diagnostic_group = buffer
17812            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17813            .collect::<Vec<_>>();
17814
17815        let blocks =
17816            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17817
17818        let blocks = self.display_map.update(cx, |display_map, cx| {
17819            display_map.insert_blocks(blocks, cx).into_iter().collect()
17820        });
17821        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17822            active_range: buffer.anchor_before(diagnostic.range.start)
17823                ..buffer.anchor_after(diagnostic.range.end),
17824            active_message: diagnostic.diagnostic.message.clone(),
17825            group_id: diagnostic.diagnostic.group_id,
17826            blocks,
17827        });
17828        cx.notify();
17829    }
17830
17831    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17832        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17833            return;
17834        };
17835
17836        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17837        if let ActiveDiagnostic::Group(group) = prev {
17838            self.display_map.update(cx, |display_map, cx| {
17839                display_map.remove_blocks(group.blocks, cx);
17840            });
17841            cx.notify();
17842        }
17843    }
17844
17845    /// Disable inline diagnostics rendering for this editor.
17846    pub fn disable_inline_diagnostics(&mut self) {
17847        self.inline_diagnostics_enabled = false;
17848        self.inline_diagnostics_update = Task::ready(());
17849        self.inline_diagnostics.clear();
17850    }
17851
17852    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17853        self.diagnostics_enabled = false;
17854        self.dismiss_diagnostics(cx);
17855        self.inline_diagnostics_update = Task::ready(());
17856        self.inline_diagnostics.clear();
17857    }
17858
17859    pub fn disable_word_completions(&mut self) {
17860        self.word_completions_enabled = false;
17861    }
17862
17863    pub fn diagnostics_enabled(&self) -> bool {
17864        self.diagnostics_enabled && self.mode.is_full()
17865    }
17866
17867    pub fn inline_diagnostics_enabled(&self) -> bool {
17868        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17869    }
17870
17871    pub fn show_inline_diagnostics(&self) -> bool {
17872        self.show_inline_diagnostics
17873    }
17874
17875    pub fn toggle_inline_diagnostics(
17876        &mut self,
17877        _: &ToggleInlineDiagnostics,
17878        window: &mut Window,
17879        cx: &mut Context<Editor>,
17880    ) {
17881        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17882        self.refresh_inline_diagnostics(false, window, cx);
17883    }
17884
17885    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17886        self.diagnostics_max_severity = severity;
17887        self.display_map.update(cx, |display_map, _| {
17888            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17889        });
17890    }
17891
17892    pub fn toggle_diagnostics(
17893        &mut self,
17894        _: &ToggleDiagnostics,
17895        window: &mut Window,
17896        cx: &mut Context<Editor>,
17897    ) {
17898        if !self.diagnostics_enabled() {
17899            return;
17900        }
17901
17902        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17903            EditorSettings::get_global(cx)
17904                .diagnostics_max_severity
17905                .filter(|severity| severity != &DiagnosticSeverity::Off)
17906                .unwrap_or(DiagnosticSeverity::Hint)
17907        } else {
17908            DiagnosticSeverity::Off
17909        };
17910        self.set_max_diagnostics_severity(new_severity, cx);
17911        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17912            self.active_diagnostics = ActiveDiagnostic::None;
17913            self.inline_diagnostics_update = Task::ready(());
17914            self.inline_diagnostics.clear();
17915        } else {
17916            self.refresh_inline_diagnostics(false, window, cx);
17917        }
17918
17919        cx.notify();
17920    }
17921
17922    pub fn toggle_minimap(
17923        &mut self,
17924        _: &ToggleMinimap,
17925        window: &mut Window,
17926        cx: &mut Context<Editor>,
17927    ) {
17928        if self.supports_minimap(cx) {
17929            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17930        }
17931    }
17932
17933    fn refresh_inline_diagnostics(
17934        &mut self,
17935        debounce: bool,
17936        window: &mut Window,
17937        cx: &mut Context<Self>,
17938    ) {
17939        let max_severity = ProjectSettings::get_global(cx)
17940            .diagnostics
17941            .inline
17942            .max_severity
17943            .unwrap_or(self.diagnostics_max_severity);
17944
17945        if !self.inline_diagnostics_enabled()
17946            || !self.diagnostics_enabled()
17947            || !self.show_inline_diagnostics
17948            || max_severity == DiagnosticSeverity::Off
17949        {
17950            self.inline_diagnostics_update = Task::ready(());
17951            self.inline_diagnostics.clear();
17952            return;
17953        }
17954
17955        let debounce_ms = ProjectSettings::get_global(cx)
17956            .diagnostics
17957            .inline
17958            .update_debounce_ms;
17959        let debounce = if debounce && debounce_ms > 0 {
17960            Some(Duration::from_millis(debounce_ms))
17961        } else {
17962            None
17963        };
17964        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17965            if let Some(debounce) = debounce {
17966                cx.background_executor().timer(debounce).await;
17967            }
17968            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17969                editor
17970                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17971                    .ok()
17972            }) else {
17973                return;
17974            };
17975
17976            let new_inline_diagnostics = cx
17977                .background_spawn(async move {
17978                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17979                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17980                        let message = diagnostic_entry
17981                            .diagnostic
17982                            .message
17983                            .split_once('\n')
17984                            .map(|(line, _)| line)
17985                            .map(SharedString::new)
17986                            .unwrap_or_else(|| {
17987                                SharedString::new(&*diagnostic_entry.diagnostic.message)
17988                            });
17989                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17990                        let (Ok(i) | Err(i)) = inline_diagnostics
17991                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17992                        inline_diagnostics.insert(
17993                            i,
17994                            (
17995                                start_anchor,
17996                                InlineDiagnostic {
17997                                    message,
17998                                    group_id: diagnostic_entry.diagnostic.group_id,
17999                                    start: diagnostic_entry.range.start.to_point(&snapshot),
18000                                    is_primary: diagnostic_entry.diagnostic.is_primary,
18001                                    severity: diagnostic_entry.diagnostic.severity,
18002                                },
18003                            ),
18004                        );
18005                    }
18006                    inline_diagnostics
18007                })
18008                .await;
18009
18010            editor
18011                .update(cx, |editor, cx| {
18012                    editor.inline_diagnostics = new_inline_diagnostics;
18013                    cx.notify();
18014                })
18015                .ok();
18016        });
18017    }
18018
18019    fn pull_diagnostics(
18020        &mut self,
18021        buffer_id: Option<BufferId>,
18022        window: &Window,
18023        cx: &mut Context<Self>,
18024    ) -> Option<()> {
18025        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
18026            return None;
18027        }
18028        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
18029            .diagnostics
18030            .lsp_pull_diagnostics;
18031        if !pull_diagnostics_settings.enabled {
18032            return None;
18033        }
18034        let project = self.project()?.downgrade();
18035        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
18036        let mut buffers = self.buffer.read(cx).all_buffers();
18037        buffers.retain(|buffer| {
18038            let buffer_id_to_retain = buffer.read(cx).remote_id();
18039            buffer_id.is_none_or(|buffer_id| buffer_id == buffer_id_to_retain)
18040                && self.registered_buffers.contains_key(&buffer_id_to_retain)
18041        });
18042        if buffers.is_empty() {
18043            self.pull_diagnostics_task = Task::ready(());
18044            return None;
18045        }
18046
18047        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
18048            cx.background_executor().timer(debounce).await;
18049
18050            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
18051                buffers
18052                    .into_iter()
18053                    .filter_map(|buffer| {
18054                        project
18055                            .update(cx, |project, cx| {
18056                                project.lsp_store().update(cx, |lsp_store, cx| {
18057                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
18058                                })
18059                            })
18060                            .ok()
18061                    })
18062                    .collect::<FuturesUnordered<_>>()
18063            }) else {
18064                return;
18065            };
18066
18067            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
18068                match pull_task {
18069                    Ok(()) => {
18070                        if editor
18071                            .update_in(cx, |editor, window, cx| {
18072                                editor.update_diagnostics_state(window, cx);
18073                            })
18074                            .is_err()
18075                        {
18076                            return;
18077                        }
18078                    }
18079                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
18080                }
18081            }
18082        });
18083
18084        Some(())
18085    }
18086
18087    pub fn set_selections_from_remote(
18088        &mut self,
18089        selections: Vec<Selection<Anchor>>,
18090        pending_selection: Option<Selection<Anchor>>,
18091        window: &mut Window,
18092        cx: &mut Context<Self>,
18093    ) {
18094        let old_cursor_position = self.selections.newest_anchor().head();
18095        self.selections.change_with(cx, |s| {
18096            s.select_anchors(selections);
18097            if let Some(pending_selection) = pending_selection {
18098                s.set_pending(pending_selection, SelectMode::Character);
18099            } else {
18100                s.clear_pending();
18101            }
18102        });
18103        self.selections_did_change(
18104            false,
18105            &old_cursor_position,
18106            SelectionEffects::default(),
18107            window,
18108            cx,
18109        );
18110    }
18111
18112    pub fn transact(
18113        &mut self,
18114        window: &mut Window,
18115        cx: &mut Context<Self>,
18116        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
18117    ) -> Option<TransactionId> {
18118        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18119            this.start_transaction_at(Instant::now(), window, cx);
18120            update(this, window, cx);
18121            this.end_transaction_at(Instant::now(), cx)
18122        })
18123    }
18124
18125    pub fn start_transaction_at(
18126        &mut self,
18127        now: Instant,
18128        window: &mut Window,
18129        cx: &mut Context<Self>,
18130    ) -> Option<TransactionId> {
18131        self.end_selection(window, cx);
18132        if let Some(tx_id) = self
18133            .buffer
18134            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18135        {
18136            self.selection_history
18137                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18138            cx.emit(EditorEvent::TransactionBegun {
18139                transaction_id: tx_id,
18140            });
18141            Some(tx_id)
18142        } else {
18143            None
18144        }
18145    }
18146
18147    pub fn end_transaction_at(
18148        &mut self,
18149        now: Instant,
18150        cx: &mut Context<Self>,
18151    ) -> Option<TransactionId> {
18152        if let Some(transaction_id) = self
18153            .buffer
18154            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18155        {
18156            if let Some((_, end_selections)) =
18157                self.selection_history.transaction_mut(transaction_id)
18158            {
18159                *end_selections = Some(self.selections.disjoint_anchors_arc());
18160            } else {
18161                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18162            }
18163
18164            cx.emit(EditorEvent::Edited { transaction_id });
18165            Some(transaction_id)
18166        } else {
18167            None
18168        }
18169    }
18170
18171    pub fn modify_transaction_selection_history(
18172        &mut self,
18173        transaction_id: TransactionId,
18174        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18175    ) -> bool {
18176        self.selection_history
18177            .transaction_mut(transaction_id)
18178            .map(modify)
18179            .is_some()
18180    }
18181
18182    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18183        if self.selection_mark_mode {
18184            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18185                s.move_with(|_, sel| {
18186                    sel.collapse_to(sel.head(), SelectionGoal::None);
18187                });
18188            })
18189        }
18190        self.selection_mark_mode = true;
18191        cx.notify();
18192    }
18193
18194    pub fn swap_selection_ends(
18195        &mut self,
18196        _: &actions::SwapSelectionEnds,
18197        window: &mut Window,
18198        cx: &mut Context<Self>,
18199    ) {
18200        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18201            s.move_with(|_, sel| {
18202                if sel.start != sel.end {
18203                    sel.reversed = !sel.reversed
18204                }
18205            });
18206        });
18207        self.request_autoscroll(Autoscroll::newest(), cx);
18208        cx.notify();
18209    }
18210
18211    pub fn toggle_focus(
18212        workspace: &mut Workspace,
18213        _: &actions::ToggleFocus,
18214        window: &mut Window,
18215        cx: &mut Context<Workspace>,
18216    ) {
18217        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18218            return;
18219        };
18220        workspace.activate_item(&item, true, true, window, cx);
18221    }
18222
18223    pub fn toggle_fold(
18224        &mut self,
18225        _: &actions::ToggleFold,
18226        window: &mut Window,
18227        cx: &mut Context<Self>,
18228    ) {
18229        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18230            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18231            let selection = self.selections.newest::<Point>(&display_map);
18232
18233            let range = if selection.is_empty() {
18234                let point = selection.head().to_display_point(&display_map);
18235                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18236                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18237                    .to_point(&display_map);
18238                start..end
18239            } else {
18240                selection.range()
18241            };
18242            if display_map.folds_in_range(range).next().is_some() {
18243                self.unfold_lines(&Default::default(), window, cx)
18244            } else {
18245                self.fold(&Default::default(), window, cx)
18246            }
18247        } else {
18248            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18249            let buffer_ids: HashSet<_> = self
18250                .selections
18251                .disjoint_anchor_ranges()
18252                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18253                .collect();
18254
18255            let should_unfold = buffer_ids
18256                .iter()
18257                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18258
18259            for buffer_id in buffer_ids {
18260                if should_unfold {
18261                    self.unfold_buffer(buffer_id, cx);
18262                } else {
18263                    self.fold_buffer(buffer_id, cx);
18264                }
18265            }
18266        }
18267    }
18268
18269    pub fn toggle_fold_recursive(
18270        &mut self,
18271        _: &actions::ToggleFoldRecursive,
18272        window: &mut Window,
18273        cx: &mut Context<Self>,
18274    ) {
18275        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
18276
18277        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18278        let range = if selection.is_empty() {
18279            let point = selection.head().to_display_point(&display_map);
18280            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18281            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18282                .to_point(&display_map);
18283            start..end
18284        } else {
18285            selection.range()
18286        };
18287        if display_map.folds_in_range(range).next().is_some() {
18288            self.unfold_recursive(&Default::default(), window, cx)
18289        } else {
18290            self.fold_recursive(&Default::default(), window, cx)
18291        }
18292    }
18293
18294    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18295        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18296            let mut to_fold = Vec::new();
18297            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18298            let selections = self.selections.all_adjusted(&display_map);
18299
18300            for selection in selections {
18301                let range = selection.range().sorted();
18302                let buffer_start_row = range.start.row;
18303
18304                if range.start.row != range.end.row {
18305                    let mut found = false;
18306                    let mut row = range.start.row;
18307                    while row <= range.end.row {
18308                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18309                        {
18310                            found = true;
18311                            row = crease.range().end.row + 1;
18312                            to_fold.push(crease);
18313                        } else {
18314                            row += 1
18315                        }
18316                    }
18317                    if found {
18318                        continue;
18319                    }
18320                }
18321
18322                for row in (0..=range.start.row).rev() {
18323                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18324                        && crease.range().end.row >= buffer_start_row
18325                    {
18326                        to_fold.push(crease);
18327                        if row <= range.start.row {
18328                            break;
18329                        }
18330                    }
18331                }
18332            }
18333
18334            self.fold_creases(to_fold, true, window, cx);
18335        } else {
18336            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18337            let buffer_ids = self
18338                .selections
18339                .disjoint_anchor_ranges()
18340                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18341                .collect::<HashSet<_>>();
18342            for buffer_id in buffer_ids {
18343                self.fold_buffer(buffer_id, cx);
18344            }
18345        }
18346    }
18347
18348    pub fn toggle_fold_all(
18349        &mut self,
18350        _: &actions::ToggleFoldAll,
18351        window: &mut Window,
18352        cx: &mut Context<Self>,
18353    ) {
18354        if self.buffer.read(cx).is_singleton() {
18355            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18356            let has_folds = display_map
18357                .folds_in_range(0..display_map.buffer_snapshot().len())
18358                .next()
18359                .is_some();
18360
18361            if has_folds {
18362                self.unfold_all(&actions::UnfoldAll, window, cx);
18363            } else {
18364                self.fold_all(&actions::FoldAll, window, cx);
18365            }
18366        } else {
18367            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18368            let should_unfold = buffer_ids
18369                .iter()
18370                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18371
18372            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18373                editor
18374                    .update_in(cx, |editor, _, cx| {
18375                        for buffer_id in buffer_ids {
18376                            if should_unfold {
18377                                editor.unfold_buffer(buffer_id, cx);
18378                            } else {
18379                                editor.fold_buffer(buffer_id, cx);
18380                            }
18381                        }
18382                    })
18383                    .ok();
18384            });
18385        }
18386    }
18387
18388    fn fold_at_level(
18389        &mut self,
18390        fold_at: &FoldAtLevel,
18391        window: &mut Window,
18392        cx: &mut Context<Self>,
18393    ) {
18394        if !self.buffer.read(cx).is_singleton() {
18395            return;
18396        }
18397
18398        let fold_at_level = fold_at.0;
18399        let snapshot = self.buffer.read(cx).snapshot(cx);
18400        let mut to_fold = Vec::new();
18401        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18402
18403        let row_ranges_to_keep: Vec<Range<u32>> = self
18404            .selections
18405            .all::<Point>(&self.display_snapshot(cx))
18406            .into_iter()
18407            .map(|sel| sel.start.row..sel.end.row)
18408            .collect();
18409
18410        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18411            while start_row < end_row {
18412                match self
18413                    .snapshot(window, cx)
18414                    .crease_for_buffer_row(MultiBufferRow(start_row))
18415                {
18416                    Some(crease) => {
18417                        let nested_start_row = crease.range().start.row + 1;
18418                        let nested_end_row = crease.range().end.row;
18419
18420                        if current_level < fold_at_level {
18421                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18422                        } else if current_level == fold_at_level {
18423                            // Fold iff there is no selection completely contained within the fold region
18424                            if !row_ranges_to_keep.iter().any(|selection| {
18425                                selection.end >= nested_start_row
18426                                    && selection.start <= nested_end_row
18427                            }) {
18428                                to_fold.push(crease);
18429                            }
18430                        }
18431
18432                        start_row = nested_end_row + 1;
18433                    }
18434                    None => start_row += 1,
18435                }
18436            }
18437        }
18438
18439        self.fold_creases(to_fold, true, window, cx);
18440    }
18441
18442    pub fn fold_at_level_1(
18443        &mut self,
18444        _: &actions::FoldAtLevel1,
18445        window: &mut Window,
18446        cx: &mut Context<Self>,
18447    ) {
18448        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18449    }
18450
18451    pub fn fold_at_level_2(
18452        &mut self,
18453        _: &actions::FoldAtLevel2,
18454        window: &mut Window,
18455        cx: &mut Context<Self>,
18456    ) {
18457        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18458    }
18459
18460    pub fn fold_at_level_3(
18461        &mut self,
18462        _: &actions::FoldAtLevel3,
18463        window: &mut Window,
18464        cx: &mut Context<Self>,
18465    ) {
18466        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18467    }
18468
18469    pub fn fold_at_level_4(
18470        &mut self,
18471        _: &actions::FoldAtLevel4,
18472        window: &mut Window,
18473        cx: &mut Context<Self>,
18474    ) {
18475        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18476    }
18477
18478    pub fn fold_at_level_5(
18479        &mut self,
18480        _: &actions::FoldAtLevel5,
18481        window: &mut Window,
18482        cx: &mut Context<Self>,
18483    ) {
18484        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18485    }
18486
18487    pub fn fold_at_level_6(
18488        &mut self,
18489        _: &actions::FoldAtLevel6,
18490        window: &mut Window,
18491        cx: &mut Context<Self>,
18492    ) {
18493        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18494    }
18495
18496    pub fn fold_at_level_7(
18497        &mut self,
18498        _: &actions::FoldAtLevel7,
18499        window: &mut Window,
18500        cx: &mut Context<Self>,
18501    ) {
18502        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18503    }
18504
18505    pub fn fold_at_level_8(
18506        &mut self,
18507        _: &actions::FoldAtLevel8,
18508        window: &mut Window,
18509        cx: &mut Context<Self>,
18510    ) {
18511        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18512    }
18513
18514    pub fn fold_at_level_9(
18515        &mut self,
18516        _: &actions::FoldAtLevel9,
18517        window: &mut Window,
18518        cx: &mut Context<Self>,
18519    ) {
18520        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18521    }
18522
18523    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18524        if self.buffer.read(cx).is_singleton() {
18525            let mut fold_ranges = Vec::new();
18526            let snapshot = self.buffer.read(cx).snapshot(cx);
18527
18528            for row in 0..snapshot.max_row().0 {
18529                if let Some(foldable_range) = self
18530                    .snapshot(window, cx)
18531                    .crease_for_buffer_row(MultiBufferRow(row))
18532                {
18533                    fold_ranges.push(foldable_range);
18534                }
18535            }
18536
18537            self.fold_creases(fold_ranges, true, window, cx);
18538        } else {
18539            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18540                editor
18541                    .update_in(cx, |editor, _, cx| {
18542                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18543                            editor.fold_buffer(buffer_id, cx);
18544                        }
18545                    })
18546                    .ok();
18547            });
18548        }
18549    }
18550
18551    pub fn fold_function_bodies(
18552        &mut self,
18553        _: &actions::FoldFunctionBodies,
18554        window: &mut Window,
18555        cx: &mut Context<Self>,
18556    ) {
18557        let snapshot = self.buffer.read(cx).snapshot(cx);
18558
18559        let ranges = snapshot
18560            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18561            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18562            .collect::<Vec<_>>();
18563
18564        let creases = ranges
18565            .into_iter()
18566            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18567            .collect();
18568
18569        self.fold_creases(creases, true, window, cx);
18570    }
18571
18572    pub fn fold_recursive(
18573        &mut self,
18574        _: &actions::FoldRecursive,
18575        window: &mut Window,
18576        cx: &mut Context<Self>,
18577    ) {
18578        let mut to_fold = Vec::new();
18579        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18580        let selections = self.selections.all_adjusted(&display_map);
18581
18582        for selection in selections {
18583            let range = selection.range().sorted();
18584            let buffer_start_row = range.start.row;
18585
18586            if range.start.row != range.end.row {
18587                let mut found = false;
18588                for row in range.start.row..=range.end.row {
18589                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18590                        found = true;
18591                        to_fold.push(crease);
18592                    }
18593                }
18594                if found {
18595                    continue;
18596                }
18597            }
18598
18599            for row in (0..=range.start.row).rev() {
18600                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18601                    if crease.range().end.row >= buffer_start_row {
18602                        to_fold.push(crease);
18603                    } else {
18604                        break;
18605                    }
18606                }
18607            }
18608        }
18609
18610        self.fold_creases(to_fold, true, window, cx);
18611    }
18612
18613    pub fn fold_at(
18614        &mut self,
18615        buffer_row: MultiBufferRow,
18616        window: &mut Window,
18617        cx: &mut Context<Self>,
18618    ) {
18619        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18620
18621        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18622            let autoscroll = self
18623                .selections
18624                .all::<Point>(&display_map)
18625                .iter()
18626                .any(|selection| crease.range().overlaps(&selection.range()));
18627
18628            self.fold_creases(vec![crease], autoscroll, window, cx);
18629        }
18630    }
18631
18632    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18633        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18634            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18635            let buffer = display_map.buffer_snapshot();
18636            let selections = self.selections.all::<Point>(&display_map);
18637            let ranges = selections
18638                .iter()
18639                .map(|s| {
18640                    let range = s.display_range(&display_map).sorted();
18641                    let mut start = range.start.to_point(&display_map);
18642                    let mut end = range.end.to_point(&display_map);
18643                    start.column = 0;
18644                    end.column = buffer.line_len(MultiBufferRow(end.row));
18645                    start..end
18646                })
18647                .collect::<Vec<_>>();
18648
18649            self.unfold_ranges(&ranges, true, true, cx);
18650        } else {
18651            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18652            let buffer_ids = self
18653                .selections
18654                .disjoint_anchor_ranges()
18655                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18656                .collect::<HashSet<_>>();
18657            for buffer_id in buffer_ids {
18658                self.unfold_buffer(buffer_id, cx);
18659            }
18660        }
18661    }
18662
18663    pub fn unfold_recursive(
18664        &mut self,
18665        _: &UnfoldRecursive,
18666        _window: &mut Window,
18667        cx: &mut Context<Self>,
18668    ) {
18669        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18670        let selections = self.selections.all::<Point>(&display_map);
18671        let ranges = selections
18672            .iter()
18673            .map(|s| {
18674                let mut range = s.display_range(&display_map).sorted();
18675                *range.start.column_mut() = 0;
18676                *range.end.column_mut() = display_map.line_len(range.end.row());
18677                let start = range.start.to_point(&display_map);
18678                let end = range.end.to_point(&display_map);
18679                start..end
18680            })
18681            .collect::<Vec<_>>();
18682
18683        self.unfold_ranges(&ranges, true, true, cx);
18684    }
18685
18686    pub fn unfold_at(
18687        &mut self,
18688        buffer_row: MultiBufferRow,
18689        _window: &mut Window,
18690        cx: &mut Context<Self>,
18691    ) {
18692        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18693
18694        let intersection_range = Point::new(buffer_row.0, 0)
18695            ..Point::new(
18696                buffer_row.0,
18697                display_map.buffer_snapshot().line_len(buffer_row),
18698            );
18699
18700        let autoscroll = self
18701            .selections
18702            .all::<Point>(&display_map)
18703            .iter()
18704            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18705
18706        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18707    }
18708
18709    pub fn unfold_all(
18710        &mut self,
18711        _: &actions::UnfoldAll,
18712        _window: &mut Window,
18713        cx: &mut Context<Self>,
18714    ) {
18715        if self.buffer.read(cx).is_singleton() {
18716            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18717            self.unfold_ranges(&[0..display_map.buffer_snapshot().len()], true, true, cx);
18718        } else {
18719            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18720                editor
18721                    .update(cx, |editor, cx| {
18722                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18723                            editor.unfold_buffer(buffer_id, cx);
18724                        }
18725                    })
18726                    .ok();
18727            });
18728        }
18729    }
18730
18731    pub fn fold_selected_ranges(
18732        &mut self,
18733        _: &FoldSelectedRanges,
18734        window: &mut Window,
18735        cx: &mut Context<Self>,
18736    ) {
18737        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18738        let selections = self.selections.all_adjusted(&display_map);
18739        let ranges = selections
18740            .into_iter()
18741            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18742            .collect::<Vec<_>>();
18743        self.fold_creases(ranges, true, window, cx);
18744    }
18745
18746    pub fn fold_ranges<T: ToOffset + Clone>(
18747        &mut self,
18748        ranges: Vec<Range<T>>,
18749        auto_scroll: bool,
18750        window: &mut Window,
18751        cx: &mut Context<Self>,
18752    ) {
18753        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18754        let ranges = ranges
18755            .into_iter()
18756            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18757            .collect::<Vec<_>>();
18758        self.fold_creases(ranges, auto_scroll, window, cx);
18759    }
18760
18761    pub fn fold_creases<T: ToOffset + Clone>(
18762        &mut self,
18763        creases: Vec<Crease<T>>,
18764        auto_scroll: bool,
18765        _window: &mut Window,
18766        cx: &mut Context<Self>,
18767    ) {
18768        if creases.is_empty() {
18769            return;
18770        }
18771
18772        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18773
18774        if auto_scroll {
18775            self.request_autoscroll(Autoscroll::fit(), cx);
18776        }
18777
18778        cx.notify();
18779
18780        self.scrollbar_marker_state.dirty = true;
18781        self.folds_did_change(cx);
18782    }
18783
18784    /// Removes any folds whose ranges intersect any of the given ranges.
18785    pub fn unfold_ranges<T: ToOffset + Clone>(
18786        &mut self,
18787        ranges: &[Range<T>],
18788        inclusive: bool,
18789        auto_scroll: bool,
18790        cx: &mut Context<Self>,
18791    ) {
18792        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18793            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18794        });
18795        self.folds_did_change(cx);
18796    }
18797
18798    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18799        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18800            return;
18801        }
18802        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18803        self.display_map.update(cx, |display_map, cx| {
18804            display_map.fold_buffers([buffer_id], cx)
18805        });
18806        cx.emit(EditorEvent::BufferFoldToggled {
18807            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18808            folded: true,
18809        });
18810        cx.notify();
18811    }
18812
18813    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18814        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18815            return;
18816        }
18817        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18818        self.display_map.update(cx, |display_map, cx| {
18819            display_map.unfold_buffers([buffer_id], cx);
18820        });
18821        cx.emit(EditorEvent::BufferFoldToggled {
18822            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18823            folded: false,
18824        });
18825        cx.notify();
18826    }
18827
18828    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18829        self.display_map.read(cx).is_buffer_folded(buffer)
18830    }
18831
18832    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18833        self.display_map.read(cx).folded_buffers()
18834    }
18835
18836    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18837        self.display_map.update(cx, |display_map, cx| {
18838            display_map.disable_header_for_buffer(buffer_id, cx);
18839        });
18840        cx.notify();
18841    }
18842
18843    /// Removes any folds with the given ranges.
18844    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18845        &mut self,
18846        ranges: &[Range<T>],
18847        type_id: TypeId,
18848        auto_scroll: bool,
18849        cx: &mut Context<Self>,
18850    ) {
18851        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18852            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18853        });
18854        self.folds_did_change(cx);
18855    }
18856
18857    fn remove_folds_with<T: ToOffset + Clone>(
18858        &mut self,
18859        ranges: &[Range<T>],
18860        auto_scroll: bool,
18861        cx: &mut Context<Self>,
18862        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18863    ) {
18864        if ranges.is_empty() {
18865            return;
18866        }
18867
18868        let mut buffers_affected = HashSet::default();
18869        let multi_buffer = self.buffer().read(cx);
18870        for range in ranges {
18871            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18872                buffers_affected.insert(buffer.read(cx).remote_id());
18873            };
18874        }
18875
18876        self.display_map.update(cx, update);
18877
18878        if auto_scroll {
18879            self.request_autoscroll(Autoscroll::fit(), cx);
18880        }
18881
18882        cx.notify();
18883        self.scrollbar_marker_state.dirty = true;
18884        self.active_indent_guides_state.dirty = true;
18885    }
18886
18887    pub fn update_renderer_widths(
18888        &mut self,
18889        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18890        cx: &mut Context<Self>,
18891    ) -> bool {
18892        self.display_map
18893            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18894    }
18895
18896    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18897        self.display_map.read(cx).fold_placeholder.clone()
18898    }
18899
18900    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18901        self.buffer.update(cx, |buffer, cx| {
18902            buffer.set_all_diff_hunks_expanded(cx);
18903        });
18904    }
18905
18906    pub fn expand_all_diff_hunks(
18907        &mut self,
18908        _: &ExpandAllDiffHunks,
18909        _window: &mut Window,
18910        cx: &mut Context<Self>,
18911    ) {
18912        self.buffer.update(cx, |buffer, cx| {
18913            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18914        });
18915    }
18916
18917    pub fn collapse_all_diff_hunks(
18918        &mut self,
18919        _: &CollapseAllDiffHunks,
18920        _window: &mut Window,
18921        cx: &mut Context<Self>,
18922    ) {
18923        self.buffer.update(cx, |buffer, cx| {
18924            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18925        });
18926    }
18927
18928    pub fn toggle_selected_diff_hunks(
18929        &mut self,
18930        _: &ToggleSelectedDiffHunks,
18931        _window: &mut Window,
18932        cx: &mut Context<Self>,
18933    ) {
18934        let ranges: Vec<_> = self
18935            .selections
18936            .disjoint_anchors()
18937            .iter()
18938            .map(|s| s.range())
18939            .collect();
18940        self.toggle_diff_hunks_in_ranges(ranges, cx);
18941    }
18942
18943    pub fn diff_hunks_in_ranges<'a>(
18944        &'a self,
18945        ranges: &'a [Range<Anchor>],
18946        buffer: &'a MultiBufferSnapshot,
18947    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18948        ranges.iter().flat_map(move |range| {
18949            let end_excerpt_id = range.end.excerpt_id;
18950            let range = range.to_point(buffer);
18951            let mut peek_end = range.end;
18952            if range.end.row < buffer.max_row().0 {
18953                peek_end = Point::new(range.end.row + 1, 0);
18954            }
18955            buffer
18956                .diff_hunks_in_range(range.start..peek_end)
18957                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18958        })
18959    }
18960
18961    pub fn has_stageable_diff_hunks_in_ranges(
18962        &self,
18963        ranges: &[Range<Anchor>],
18964        snapshot: &MultiBufferSnapshot,
18965    ) -> bool {
18966        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18967        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18968    }
18969
18970    pub fn toggle_staged_selected_diff_hunks(
18971        &mut self,
18972        _: &::git::ToggleStaged,
18973        _: &mut Window,
18974        cx: &mut Context<Self>,
18975    ) {
18976        let snapshot = self.buffer.read(cx).snapshot(cx);
18977        let ranges: Vec<_> = self
18978            .selections
18979            .disjoint_anchors()
18980            .iter()
18981            .map(|s| s.range())
18982            .collect();
18983        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18984        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18985    }
18986
18987    pub fn set_render_diff_hunk_controls(
18988        &mut self,
18989        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18990        cx: &mut Context<Self>,
18991    ) {
18992        self.render_diff_hunk_controls = render_diff_hunk_controls;
18993        cx.notify();
18994    }
18995
18996    pub fn stage_and_next(
18997        &mut self,
18998        _: &::git::StageAndNext,
18999        window: &mut Window,
19000        cx: &mut Context<Self>,
19001    ) {
19002        self.do_stage_or_unstage_and_next(true, window, cx);
19003    }
19004
19005    pub fn unstage_and_next(
19006        &mut self,
19007        _: &::git::UnstageAndNext,
19008        window: &mut Window,
19009        cx: &mut Context<Self>,
19010    ) {
19011        self.do_stage_or_unstage_and_next(false, window, cx);
19012    }
19013
19014    pub fn stage_or_unstage_diff_hunks(
19015        &mut self,
19016        stage: bool,
19017        ranges: Vec<Range<Anchor>>,
19018        cx: &mut Context<Self>,
19019    ) {
19020        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
19021        cx.spawn(async move |this, cx| {
19022            task.await?;
19023            this.update(cx, |this, cx| {
19024                let snapshot = this.buffer.read(cx).snapshot(cx);
19025                let chunk_by = this
19026                    .diff_hunks_in_ranges(&ranges, &snapshot)
19027                    .chunk_by(|hunk| hunk.buffer_id);
19028                for (buffer_id, hunks) in &chunk_by {
19029                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
19030                }
19031            })
19032        })
19033        .detach_and_log_err(cx);
19034    }
19035
19036    fn save_buffers_for_ranges_if_needed(
19037        &mut self,
19038        ranges: &[Range<Anchor>],
19039        cx: &mut Context<Editor>,
19040    ) -> Task<Result<()>> {
19041        let multibuffer = self.buffer.read(cx);
19042        let snapshot = multibuffer.read(cx);
19043        let buffer_ids: HashSet<_> = ranges
19044            .iter()
19045            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
19046            .collect();
19047        drop(snapshot);
19048
19049        let mut buffers = HashSet::default();
19050        for buffer_id in buffer_ids {
19051            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
19052                let buffer = buffer_entity.read(cx);
19053                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
19054                {
19055                    buffers.insert(buffer_entity);
19056                }
19057            }
19058        }
19059
19060        if let Some(project) = &self.project {
19061            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
19062        } else {
19063            Task::ready(Ok(()))
19064        }
19065    }
19066
19067    fn do_stage_or_unstage_and_next(
19068        &mut self,
19069        stage: bool,
19070        window: &mut Window,
19071        cx: &mut Context<Self>,
19072    ) {
19073        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
19074
19075        if ranges.iter().any(|range| range.start != range.end) {
19076            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19077            return;
19078        }
19079
19080        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19081        let snapshot = self.snapshot(window, cx);
19082        let position = self
19083            .selections
19084            .newest::<Point>(&snapshot.display_snapshot)
19085            .head();
19086        let mut row = snapshot
19087            .buffer_snapshot()
19088            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
19089            .find(|hunk| hunk.row_range.start.0 > position.row)
19090            .map(|hunk| hunk.row_range.start);
19091
19092        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
19093        // Outside of the project diff editor, wrap around to the beginning.
19094        if !all_diff_hunks_expanded {
19095            row = row.or_else(|| {
19096                snapshot
19097                    .buffer_snapshot()
19098                    .diff_hunks_in_range(Point::zero()..position)
19099                    .find(|hunk| hunk.row_range.end.0 < position.row)
19100                    .map(|hunk| hunk.row_range.start)
19101            });
19102        }
19103
19104        if let Some(row) = row {
19105            let destination = Point::new(row.0, 0);
19106            let autoscroll = Autoscroll::center();
19107
19108            self.unfold_ranges(&[destination..destination], false, false, cx);
19109            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
19110                s.select_ranges([destination..destination]);
19111            });
19112        }
19113    }
19114
19115    fn do_stage_or_unstage(
19116        &self,
19117        stage: bool,
19118        buffer_id: BufferId,
19119        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
19120        cx: &mut App,
19121    ) -> Option<()> {
19122        let project = self.project()?;
19123        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19124        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19125        let buffer_snapshot = buffer.read(cx).snapshot();
19126        let file_exists = buffer_snapshot
19127            .file()
19128            .is_some_and(|file| file.disk_state().exists());
19129        diff.update(cx, |diff, cx| {
19130            diff.stage_or_unstage_hunks(
19131                stage,
19132                &hunks
19133                    .map(|hunk| buffer_diff::DiffHunk {
19134                        buffer_range: hunk.buffer_range,
19135                        diff_base_byte_range: hunk.diff_base_byte_range,
19136                        secondary_status: hunk.secondary_status,
19137                        range: Point::zero()..Point::zero(), // unused
19138                    })
19139                    .collect::<Vec<_>>(),
19140                &buffer_snapshot,
19141                file_exists,
19142                cx,
19143            )
19144        });
19145        None
19146    }
19147
19148    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19149        let ranges: Vec<_> = self
19150            .selections
19151            .disjoint_anchors()
19152            .iter()
19153            .map(|s| s.range())
19154            .collect();
19155        self.buffer
19156            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19157    }
19158
19159    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19160        self.buffer.update(cx, |buffer, cx| {
19161            let ranges = vec![Anchor::min()..Anchor::max()];
19162            if !buffer.all_diff_hunks_expanded()
19163                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19164            {
19165                buffer.collapse_diff_hunks(ranges, cx);
19166                true
19167            } else {
19168                false
19169            }
19170        })
19171    }
19172
19173    fn toggle_diff_hunks_in_ranges(
19174        &mut self,
19175        ranges: Vec<Range<Anchor>>,
19176        cx: &mut Context<Editor>,
19177    ) {
19178        self.buffer.update(cx, |buffer, cx| {
19179            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
19180            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
19181        })
19182    }
19183
19184    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
19185        self.buffer.update(cx, |buffer, cx| {
19186            let snapshot = buffer.snapshot(cx);
19187            let excerpt_id = range.end.excerpt_id;
19188            let point_range = range.to_point(&snapshot);
19189            let expand = !buffer.single_hunk_is_expanded(range, cx);
19190            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
19191        })
19192    }
19193
19194    pub(crate) fn apply_all_diff_hunks(
19195        &mut self,
19196        _: &ApplyAllDiffHunks,
19197        window: &mut Window,
19198        cx: &mut Context<Self>,
19199    ) {
19200        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19201
19202        let buffers = self.buffer.read(cx).all_buffers();
19203        for branch_buffer in buffers {
19204            branch_buffer.update(cx, |branch_buffer, cx| {
19205                branch_buffer.merge_into_base(Vec::new(), cx);
19206            });
19207        }
19208
19209        if let Some(project) = self.project.clone() {
19210            self.save(
19211                SaveOptions {
19212                    format: true,
19213                    autosave: false,
19214                },
19215                project,
19216                window,
19217                cx,
19218            )
19219            .detach_and_log_err(cx);
19220        }
19221    }
19222
19223    pub(crate) fn apply_selected_diff_hunks(
19224        &mut self,
19225        _: &ApplyDiffHunk,
19226        window: &mut Window,
19227        cx: &mut Context<Self>,
19228    ) {
19229        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19230        let snapshot = self.snapshot(window, cx);
19231        let hunks = snapshot.hunks_for_ranges(
19232            self.selections
19233                .all(&snapshot.display_snapshot)
19234                .into_iter()
19235                .map(|selection| selection.range()),
19236        );
19237        let mut ranges_by_buffer = HashMap::default();
19238        self.transact(window, cx, |editor, _window, cx| {
19239            for hunk in hunks {
19240                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19241                    ranges_by_buffer
19242                        .entry(buffer.clone())
19243                        .or_insert_with(Vec::new)
19244                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19245                }
19246            }
19247
19248            for (buffer, ranges) in ranges_by_buffer {
19249                buffer.update(cx, |buffer, cx| {
19250                    buffer.merge_into_base(ranges, cx);
19251                });
19252            }
19253        });
19254
19255        if let Some(project) = self.project.clone() {
19256            self.save(
19257                SaveOptions {
19258                    format: true,
19259                    autosave: false,
19260                },
19261                project,
19262                window,
19263                cx,
19264            )
19265            .detach_and_log_err(cx);
19266        }
19267    }
19268
19269    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19270        if hovered != self.gutter_hovered {
19271            self.gutter_hovered = hovered;
19272            cx.notify();
19273        }
19274    }
19275
19276    pub fn insert_blocks(
19277        &mut self,
19278        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19279        autoscroll: Option<Autoscroll>,
19280        cx: &mut Context<Self>,
19281    ) -> Vec<CustomBlockId> {
19282        let blocks = self
19283            .display_map
19284            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19285        if let Some(autoscroll) = autoscroll {
19286            self.request_autoscroll(autoscroll, cx);
19287        }
19288        cx.notify();
19289        blocks
19290    }
19291
19292    pub fn resize_blocks(
19293        &mut self,
19294        heights: HashMap<CustomBlockId, u32>,
19295        autoscroll: Option<Autoscroll>,
19296        cx: &mut Context<Self>,
19297    ) {
19298        self.display_map
19299            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19300        if let Some(autoscroll) = autoscroll {
19301            self.request_autoscroll(autoscroll, cx);
19302        }
19303        cx.notify();
19304    }
19305
19306    pub fn replace_blocks(
19307        &mut self,
19308        renderers: HashMap<CustomBlockId, RenderBlock>,
19309        autoscroll: Option<Autoscroll>,
19310        cx: &mut Context<Self>,
19311    ) {
19312        self.display_map
19313            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19314        if let Some(autoscroll) = autoscroll {
19315            self.request_autoscroll(autoscroll, cx);
19316        }
19317        cx.notify();
19318    }
19319
19320    pub fn remove_blocks(
19321        &mut self,
19322        block_ids: HashSet<CustomBlockId>,
19323        autoscroll: Option<Autoscroll>,
19324        cx: &mut Context<Self>,
19325    ) {
19326        self.display_map.update(cx, |display_map, cx| {
19327            display_map.remove_blocks(block_ids, cx)
19328        });
19329        if let Some(autoscroll) = autoscroll {
19330            self.request_autoscroll(autoscroll, cx);
19331        }
19332        cx.notify();
19333    }
19334
19335    pub fn row_for_block(
19336        &self,
19337        block_id: CustomBlockId,
19338        cx: &mut Context<Self>,
19339    ) -> Option<DisplayRow> {
19340        self.display_map
19341            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19342    }
19343
19344    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19345        self.focused_block = Some(focused_block);
19346    }
19347
19348    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19349        self.focused_block.take()
19350    }
19351
19352    pub fn insert_creases(
19353        &mut self,
19354        creases: impl IntoIterator<Item = Crease<Anchor>>,
19355        cx: &mut Context<Self>,
19356    ) -> Vec<CreaseId> {
19357        self.display_map
19358            .update(cx, |map, cx| map.insert_creases(creases, cx))
19359    }
19360
19361    pub fn remove_creases(
19362        &mut self,
19363        ids: impl IntoIterator<Item = CreaseId>,
19364        cx: &mut Context<Self>,
19365    ) -> Vec<(CreaseId, Range<Anchor>)> {
19366        self.display_map
19367            .update(cx, |map, cx| map.remove_creases(ids, cx))
19368    }
19369
19370    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19371        self.display_map
19372            .update(cx, |map, cx| map.snapshot(cx))
19373            .longest_row()
19374    }
19375
19376    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19377        self.display_map
19378            .update(cx, |map, cx| map.snapshot(cx))
19379            .max_point()
19380    }
19381
19382    pub fn text(&self, cx: &App) -> String {
19383        self.buffer.read(cx).read(cx).text()
19384    }
19385
19386    pub fn is_empty(&self, cx: &App) -> bool {
19387        self.buffer.read(cx).read(cx).is_empty()
19388    }
19389
19390    pub fn text_option(&self, cx: &App) -> Option<String> {
19391        let text = self.text(cx);
19392        let text = text.trim();
19393
19394        if text.is_empty() {
19395            return None;
19396        }
19397
19398        Some(text.to_string())
19399    }
19400
19401    pub fn set_text(
19402        &mut self,
19403        text: impl Into<Arc<str>>,
19404        window: &mut Window,
19405        cx: &mut Context<Self>,
19406    ) {
19407        self.transact(window, cx, |this, _, cx| {
19408            this.buffer
19409                .read(cx)
19410                .as_singleton()
19411                .expect("you can only call set_text on editors for singleton buffers")
19412                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19413        });
19414    }
19415
19416    pub fn display_text(&self, cx: &mut App) -> String {
19417        self.display_map
19418            .update(cx, |map, cx| map.snapshot(cx))
19419            .text()
19420    }
19421
19422    fn create_minimap(
19423        &self,
19424        minimap_settings: MinimapSettings,
19425        window: &mut Window,
19426        cx: &mut Context<Self>,
19427    ) -> Option<Entity<Self>> {
19428        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19429            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19430    }
19431
19432    fn initialize_new_minimap(
19433        &self,
19434        minimap_settings: MinimapSettings,
19435        window: &mut Window,
19436        cx: &mut Context<Self>,
19437    ) -> Entity<Self> {
19438        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19439
19440        let mut minimap = Editor::new_internal(
19441            EditorMode::Minimap {
19442                parent: cx.weak_entity(),
19443            },
19444            self.buffer.clone(),
19445            None,
19446            Some(self.display_map.clone()),
19447            window,
19448            cx,
19449        );
19450        minimap.scroll_manager.clone_state(&self.scroll_manager);
19451        minimap.set_text_style_refinement(TextStyleRefinement {
19452            font_size: Some(MINIMAP_FONT_SIZE),
19453            font_weight: Some(MINIMAP_FONT_WEIGHT),
19454            ..Default::default()
19455        });
19456        minimap.update_minimap_configuration(minimap_settings, cx);
19457        cx.new(|_| minimap)
19458    }
19459
19460    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19461        let current_line_highlight = minimap_settings
19462            .current_line_highlight
19463            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19464        self.set_current_line_highlight(Some(current_line_highlight));
19465    }
19466
19467    pub fn minimap(&self) -> Option<&Entity<Self>> {
19468        self.minimap
19469            .as_ref()
19470            .filter(|_| self.minimap_visibility.visible())
19471    }
19472
19473    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19474        let mut wrap_guides = smallvec![];
19475
19476        if self.show_wrap_guides == Some(false) {
19477            return wrap_guides;
19478        }
19479
19480        let settings = self.buffer.read(cx).language_settings(cx);
19481        if settings.show_wrap_guides {
19482            match self.soft_wrap_mode(cx) {
19483                SoftWrap::Column(soft_wrap) => {
19484                    wrap_guides.push((soft_wrap as usize, true));
19485                }
19486                SoftWrap::Bounded(soft_wrap) => {
19487                    wrap_guides.push((soft_wrap as usize, true));
19488                }
19489                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19490            }
19491            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19492        }
19493
19494        wrap_guides
19495    }
19496
19497    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19498        let settings = self.buffer.read(cx).language_settings(cx);
19499        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19500        match mode {
19501            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19502                SoftWrap::None
19503            }
19504            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19505            language_settings::SoftWrap::PreferredLineLength => {
19506                SoftWrap::Column(settings.preferred_line_length)
19507            }
19508            language_settings::SoftWrap::Bounded => {
19509                SoftWrap::Bounded(settings.preferred_line_length)
19510            }
19511        }
19512    }
19513
19514    pub fn set_soft_wrap_mode(
19515        &mut self,
19516        mode: language_settings::SoftWrap,
19517
19518        cx: &mut Context<Self>,
19519    ) {
19520        self.soft_wrap_mode_override = Some(mode);
19521        cx.notify();
19522    }
19523
19524    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19525        self.hard_wrap = hard_wrap;
19526        cx.notify();
19527    }
19528
19529    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19530        self.text_style_refinement = Some(style);
19531    }
19532
19533    /// called by the Element so we know what style we were most recently rendered with.
19534    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19535        // We intentionally do not inform the display map about the minimap style
19536        // so that wrapping is not recalculated and stays consistent for the editor
19537        // and its linked minimap.
19538        if !self.mode.is_minimap() {
19539            let font = style.text.font();
19540            let font_size = style.text.font_size.to_pixels(window.rem_size());
19541            let display_map = self
19542                .placeholder_display_map
19543                .as_ref()
19544                .filter(|_| self.is_empty(cx))
19545                .unwrap_or(&self.display_map);
19546
19547            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19548        }
19549        self.style = Some(style);
19550    }
19551
19552    pub fn style(&self) -> Option<&EditorStyle> {
19553        self.style.as_ref()
19554    }
19555
19556    // Called by the element. This method is not designed to be called outside of the editor
19557    // element's layout code because it does not notify when rewrapping is computed synchronously.
19558    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19559        if self.is_empty(cx) {
19560            self.placeholder_display_map
19561                .as_ref()
19562                .map_or(false, |display_map| {
19563                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19564                })
19565        } else {
19566            self.display_map
19567                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19568        }
19569    }
19570
19571    pub fn set_soft_wrap(&mut self) {
19572        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19573    }
19574
19575    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19576        if self.soft_wrap_mode_override.is_some() {
19577            self.soft_wrap_mode_override.take();
19578        } else {
19579            let soft_wrap = match self.soft_wrap_mode(cx) {
19580                SoftWrap::GitDiff => return,
19581                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19582                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19583                    language_settings::SoftWrap::None
19584                }
19585            };
19586            self.soft_wrap_mode_override = Some(soft_wrap);
19587        }
19588        cx.notify();
19589    }
19590
19591    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19592        let Some(workspace) = self.workspace() else {
19593            return;
19594        };
19595        let fs = workspace.read(cx).app_state().fs.clone();
19596        let current_show = TabBarSettings::get_global(cx).show;
19597        update_settings_file(fs, cx, move |setting, _| {
19598            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19599        });
19600    }
19601
19602    pub fn toggle_indent_guides(
19603        &mut self,
19604        _: &ToggleIndentGuides,
19605        _: &mut Window,
19606        cx: &mut Context<Self>,
19607    ) {
19608        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19609            self.buffer
19610                .read(cx)
19611                .language_settings(cx)
19612                .indent_guides
19613                .enabled
19614        });
19615        self.show_indent_guides = Some(!currently_enabled);
19616        cx.notify();
19617    }
19618
19619    fn should_show_indent_guides(&self) -> Option<bool> {
19620        self.show_indent_guides
19621    }
19622
19623    pub fn toggle_line_numbers(
19624        &mut self,
19625        _: &ToggleLineNumbers,
19626        _: &mut Window,
19627        cx: &mut Context<Self>,
19628    ) {
19629        let mut editor_settings = EditorSettings::get_global(cx).clone();
19630        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19631        EditorSettings::override_global(editor_settings, cx);
19632    }
19633
19634    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19635        if let Some(show_line_numbers) = self.show_line_numbers {
19636            return show_line_numbers;
19637        }
19638        EditorSettings::get_global(cx).gutter.line_numbers
19639    }
19640
19641    pub fn relative_line_numbers(&self, cx: &mut App) -> RelativeLineNumbers {
19642        match (
19643            self.use_relative_line_numbers,
19644            EditorSettings::get_global(cx).relative_line_numbers,
19645        ) {
19646            (None, setting) => setting,
19647            (Some(false), _) => RelativeLineNumbers::Disabled,
19648            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
19649            (Some(true), _) => RelativeLineNumbers::Enabled,
19650        }
19651    }
19652
19653    pub fn toggle_relative_line_numbers(
19654        &mut self,
19655        _: &ToggleRelativeLineNumbers,
19656        _: &mut Window,
19657        cx: &mut Context<Self>,
19658    ) {
19659        let is_relative = self.relative_line_numbers(cx);
19660        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
19661    }
19662
19663    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19664        self.use_relative_line_numbers = is_relative;
19665        cx.notify();
19666    }
19667
19668    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19669        self.show_gutter = show_gutter;
19670        cx.notify();
19671    }
19672
19673    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19674        self.show_scrollbars = ScrollbarAxes {
19675            horizontal: show,
19676            vertical: show,
19677        };
19678        cx.notify();
19679    }
19680
19681    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19682        self.show_scrollbars.vertical = show;
19683        cx.notify();
19684    }
19685
19686    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19687        self.show_scrollbars.horizontal = show;
19688        cx.notify();
19689    }
19690
19691    pub fn set_minimap_visibility(
19692        &mut self,
19693        minimap_visibility: MinimapVisibility,
19694        window: &mut Window,
19695        cx: &mut Context<Self>,
19696    ) {
19697        if self.minimap_visibility != minimap_visibility {
19698            if minimap_visibility.visible() && self.minimap.is_none() {
19699                let minimap_settings = EditorSettings::get_global(cx).minimap;
19700                self.minimap =
19701                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19702            }
19703            self.minimap_visibility = minimap_visibility;
19704            cx.notify();
19705        }
19706    }
19707
19708    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19709        self.set_show_scrollbars(false, cx);
19710        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19711    }
19712
19713    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19714        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19715    }
19716
19717    /// Normally the text in full mode and auto height editors is padded on the
19718    /// left side by roughly half a character width for improved hit testing.
19719    ///
19720    /// Use this method to disable this for cases where this is not wanted (e.g.
19721    /// if you want to align the editor text with some other text above or below)
19722    /// or if you want to add this padding to single-line editors.
19723    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19724        self.offset_content = offset_content;
19725        cx.notify();
19726    }
19727
19728    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19729        self.show_line_numbers = Some(show_line_numbers);
19730        cx.notify();
19731    }
19732
19733    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19734        self.disable_expand_excerpt_buttons = true;
19735        cx.notify();
19736    }
19737
19738    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19739        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19740        cx.notify();
19741    }
19742
19743    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19744        self.show_code_actions = Some(show_code_actions);
19745        cx.notify();
19746    }
19747
19748    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19749        self.show_runnables = Some(show_runnables);
19750        cx.notify();
19751    }
19752
19753    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19754        self.show_breakpoints = Some(show_breakpoints);
19755        cx.notify();
19756    }
19757
19758    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19759        if self.display_map.read(cx).masked != masked {
19760            self.display_map.update(cx, |map, _| map.masked = masked);
19761        }
19762        cx.notify()
19763    }
19764
19765    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19766        self.show_wrap_guides = Some(show_wrap_guides);
19767        cx.notify();
19768    }
19769
19770    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19771        self.show_indent_guides = Some(show_indent_guides);
19772        cx.notify();
19773    }
19774
19775    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19776        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19777            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19778                && let Some(dir) = file.abs_path(cx).parent()
19779            {
19780                return Some(dir.to_owned());
19781            }
19782        }
19783
19784        None
19785    }
19786
19787    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19788        self.active_excerpt(cx)?
19789            .1
19790            .read(cx)
19791            .file()
19792            .and_then(|f| f.as_local())
19793    }
19794
19795    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19796        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19797            let buffer = buffer.read(cx);
19798            if let Some(project_path) = buffer.project_path(cx) {
19799                let project = self.project()?.read(cx);
19800                project.absolute_path(&project_path, cx)
19801            } else {
19802                buffer
19803                    .file()
19804                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19805            }
19806        })
19807    }
19808
19809    pub fn reveal_in_finder(
19810        &mut self,
19811        _: &RevealInFileManager,
19812        _window: &mut Window,
19813        cx: &mut Context<Self>,
19814    ) {
19815        if let Some(target) = self.target_file(cx) {
19816            cx.reveal_path(&target.abs_path(cx));
19817        }
19818    }
19819
19820    pub fn copy_path(
19821        &mut self,
19822        _: &zed_actions::workspace::CopyPath,
19823        _window: &mut Window,
19824        cx: &mut Context<Self>,
19825    ) {
19826        if let Some(path) = self.target_file_abs_path(cx)
19827            && let Some(path) = path.to_str()
19828        {
19829            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19830        } else {
19831            cx.propagate();
19832        }
19833    }
19834
19835    pub fn copy_relative_path(
19836        &mut self,
19837        _: &zed_actions::workspace::CopyRelativePath,
19838        _window: &mut Window,
19839        cx: &mut Context<Self>,
19840    ) {
19841        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19842            let project = self.project()?.read(cx);
19843            let path = buffer.read(cx).file()?.path();
19844            let path = path.display(project.path_style(cx));
19845            Some(path)
19846        }) {
19847            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19848        } else {
19849            cx.propagate();
19850        }
19851    }
19852
19853    /// Returns the project path for the editor's buffer, if any buffer is
19854    /// opened in the editor.
19855    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19856        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19857            buffer.read(cx).project_path(cx)
19858        } else {
19859            None
19860        }
19861    }
19862
19863    // Returns true if the editor handled a go-to-line request
19864    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19865        maybe!({
19866            let breakpoint_store = self.breakpoint_store.as_ref()?;
19867
19868            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19869            else {
19870                self.clear_row_highlights::<ActiveDebugLine>();
19871                return None;
19872            };
19873
19874            let position = active_stack_frame.position;
19875            let buffer_id = position.buffer_id?;
19876            let snapshot = self
19877                .project
19878                .as_ref()?
19879                .read(cx)
19880                .buffer_for_id(buffer_id, cx)?
19881                .read(cx)
19882                .snapshot();
19883
19884            let mut handled = false;
19885            for (id, ExcerptRange { context, .. }) in
19886                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19887            {
19888                if context.start.cmp(&position, &snapshot).is_ge()
19889                    || context.end.cmp(&position, &snapshot).is_lt()
19890                {
19891                    continue;
19892                }
19893                let snapshot = self.buffer.read(cx).snapshot(cx);
19894                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19895
19896                handled = true;
19897                self.clear_row_highlights::<ActiveDebugLine>();
19898
19899                self.go_to_line::<ActiveDebugLine>(
19900                    multibuffer_anchor,
19901                    Some(cx.theme().colors().editor_debugger_active_line_background),
19902                    window,
19903                    cx,
19904                );
19905
19906                cx.notify();
19907            }
19908
19909            handled.then_some(())
19910        })
19911        .is_some()
19912    }
19913
19914    pub fn copy_file_name_without_extension(
19915        &mut self,
19916        _: &CopyFileNameWithoutExtension,
19917        _: &mut Window,
19918        cx: &mut Context<Self>,
19919    ) {
19920        if let Some(file) = self.target_file(cx)
19921            && let Some(file_stem) = file.path().file_stem()
19922        {
19923            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
19924        }
19925    }
19926
19927    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19928        if let Some(file) = self.target_file(cx)
19929            && let Some(name) = file.path().file_name()
19930        {
19931            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19932        }
19933    }
19934
19935    pub fn toggle_git_blame(
19936        &mut self,
19937        _: &::git::Blame,
19938        window: &mut Window,
19939        cx: &mut Context<Self>,
19940    ) {
19941        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19942
19943        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19944            self.start_git_blame(true, window, cx);
19945        }
19946
19947        cx.notify();
19948    }
19949
19950    pub fn toggle_git_blame_inline(
19951        &mut self,
19952        _: &ToggleGitBlameInline,
19953        window: &mut Window,
19954        cx: &mut Context<Self>,
19955    ) {
19956        self.toggle_git_blame_inline_internal(true, window, cx);
19957        cx.notify();
19958    }
19959
19960    pub fn open_git_blame_commit(
19961        &mut self,
19962        _: &OpenGitBlameCommit,
19963        window: &mut Window,
19964        cx: &mut Context<Self>,
19965    ) {
19966        self.open_git_blame_commit_internal(window, cx);
19967    }
19968
19969    fn open_git_blame_commit_internal(
19970        &mut self,
19971        window: &mut Window,
19972        cx: &mut Context<Self>,
19973    ) -> Option<()> {
19974        let blame = self.blame.as_ref()?;
19975        let snapshot = self.snapshot(window, cx);
19976        let cursor = self
19977            .selections
19978            .newest::<Point>(&snapshot.display_snapshot)
19979            .head();
19980        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
19981        let (_, blame_entry) = blame
19982            .update(cx, |blame, cx| {
19983                blame
19984                    .blame_for_rows(
19985                        &[RowInfo {
19986                            buffer_id: Some(buffer.remote_id()),
19987                            buffer_row: Some(point.row),
19988                            ..Default::default()
19989                        }],
19990                        cx,
19991                    )
19992                    .next()
19993            })
19994            .flatten()?;
19995        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19996        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19997        let workspace = self.workspace()?.downgrade();
19998        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19999        None
20000    }
20001
20002    pub fn git_blame_inline_enabled(&self) -> bool {
20003        self.git_blame_inline_enabled
20004    }
20005
20006    pub fn toggle_selection_menu(
20007        &mut self,
20008        _: &ToggleSelectionMenu,
20009        _: &mut Window,
20010        cx: &mut Context<Self>,
20011    ) {
20012        self.show_selection_menu = self
20013            .show_selection_menu
20014            .map(|show_selections_menu| !show_selections_menu)
20015            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
20016
20017        cx.notify();
20018    }
20019
20020    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
20021        self.show_selection_menu
20022            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
20023    }
20024
20025    fn start_git_blame(
20026        &mut self,
20027        user_triggered: bool,
20028        window: &mut Window,
20029        cx: &mut Context<Self>,
20030    ) {
20031        if let Some(project) = self.project() {
20032            if let Some(buffer) = self.buffer().read(cx).as_singleton()
20033                && buffer.read(cx).file().is_none()
20034            {
20035                return;
20036            }
20037
20038            let focused = self.focus_handle(cx).contains_focused(window, cx);
20039
20040            let project = project.clone();
20041            let blame = cx
20042                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
20043            self.blame_subscription =
20044                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
20045            self.blame = Some(blame);
20046        }
20047    }
20048
20049    fn toggle_git_blame_inline_internal(
20050        &mut self,
20051        user_triggered: bool,
20052        window: &mut Window,
20053        cx: &mut Context<Self>,
20054    ) {
20055        if self.git_blame_inline_enabled {
20056            self.git_blame_inline_enabled = false;
20057            self.show_git_blame_inline = false;
20058            self.show_git_blame_inline_delay_task.take();
20059        } else {
20060            self.git_blame_inline_enabled = true;
20061            self.start_git_blame_inline(user_triggered, window, cx);
20062        }
20063
20064        cx.notify();
20065    }
20066
20067    fn start_git_blame_inline(
20068        &mut self,
20069        user_triggered: bool,
20070        window: &mut Window,
20071        cx: &mut Context<Self>,
20072    ) {
20073        self.start_git_blame(user_triggered, window, cx);
20074
20075        if ProjectSettings::get_global(cx)
20076            .git
20077            .inline_blame_delay()
20078            .is_some()
20079        {
20080            self.start_inline_blame_timer(window, cx);
20081        } else {
20082            self.show_git_blame_inline = true
20083        }
20084    }
20085
20086    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
20087        self.blame.as_ref()
20088    }
20089
20090    pub fn show_git_blame_gutter(&self) -> bool {
20091        self.show_git_blame_gutter
20092    }
20093
20094    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
20095        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
20096    }
20097
20098    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
20099        self.show_git_blame_inline
20100            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
20101            && !self.newest_selection_head_on_empty_line(cx)
20102            && self.has_blame_entries(cx)
20103    }
20104
20105    fn has_blame_entries(&self, cx: &App) -> bool {
20106        self.blame()
20107            .is_some_and(|blame| blame.read(cx).has_generated_entries())
20108    }
20109
20110    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
20111        let cursor_anchor = self.selections.newest_anchor().head();
20112
20113        let snapshot = self.buffer.read(cx).snapshot(cx);
20114        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
20115
20116        snapshot.line_len(buffer_row) == 0
20117    }
20118
20119    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
20120        let buffer_and_selection = maybe!({
20121            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20122            let selection_range = selection.range();
20123
20124            let multi_buffer = self.buffer().read(cx);
20125            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20126            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
20127
20128            let (buffer, range, _) = if selection.reversed {
20129                buffer_ranges.first()
20130            } else {
20131                buffer_ranges.last()
20132            }?;
20133
20134            let selection = text::ToPoint::to_point(&range.start, buffer).row
20135                ..text::ToPoint::to_point(&range.end, buffer).row;
20136            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
20137        });
20138
20139        let Some((buffer, selection)) = buffer_and_selection else {
20140            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
20141        };
20142
20143        let Some(project) = self.project() else {
20144            return Task::ready(Err(anyhow!("editor does not have project")));
20145        };
20146
20147        project.update(cx, |project, cx| {
20148            project.get_permalink_to_line(&buffer, selection, cx)
20149        })
20150    }
20151
20152    pub fn copy_permalink_to_line(
20153        &mut self,
20154        _: &CopyPermalinkToLine,
20155        window: &mut Window,
20156        cx: &mut Context<Self>,
20157    ) {
20158        let permalink_task = self.get_permalink_to_line(cx);
20159        let workspace = self.workspace();
20160
20161        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20162            Ok(permalink) => {
20163                cx.update(|_, cx| {
20164                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
20165                })
20166                .ok();
20167            }
20168            Err(err) => {
20169                let message = format!("Failed to copy permalink: {err}");
20170
20171                anyhow::Result::<()>::Err(err).log_err();
20172
20173                if let Some(workspace) = workspace {
20174                    workspace
20175                        .update_in(cx, |workspace, _, cx| {
20176                            struct CopyPermalinkToLine;
20177
20178                            workspace.show_toast(
20179                                Toast::new(
20180                                    NotificationId::unique::<CopyPermalinkToLine>(),
20181                                    message,
20182                                ),
20183                                cx,
20184                            )
20185                        })
20186                        .ok();
20187                }
20188            }
20189        })
20190        .detach();
20191    }
20192
20193    pub fn copy_file_location(
20194        &mut self,
20195        _: &CopyFileLocation,
20196        _: &mut Window,
20197        cx: &mut Context<Self>,
20198    ) {
20199        let selection = self
20200            .selections
20201            .newest::<Point>(&self.display_snapshot(cx))
20202            .start
20203            .row
20204            + 1;
20205        if let Some(file) = self.target_file(cx) {
20206            let path = file.path().display(file.path_style(cx));
20207            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
20208        }
20209    }
20210
20211    pub fn open_permalink_to_line(
20212        &mut self,
20213        _: &OpenPermalinkToLine,
20214        window: &mut Window,
20215        cx: &mut Context<Self>,
20216    ) {
20217        let permalink_task = self.get_permalink_to_line(cx);
20218        let workspace = self.workspace();
20219
20220        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20221            Ok(permalink) => {
20222                cx.update(|_, cx| {
20223                    cx.open_url(permalink.as_ref());
20224                })
20225                .ok();
20226            }
20227            Err(err) => {
20228                let message = format!("Failed to open permalink: {err}");
20229
20230                anyhow::Result::<()>::Err(err).log_err();
20231
20232                if let Some(workspace) = workspace {
20233                    workspace
20234                        .update(cx, |workspace, cx| {
20235                            struct OpenPermalinkToLine;
20236
20237                            workspace.show_toast(
20238                                Toast::new(
20239                                    NotificationId::unique::<OpenPermalinkToLine>(),
20240                                    message,
20241                                ),
20242                                cx,
20243                            )
20244                        })
20245                        .ok();
20246                }
20247            }
20248        })
20249        .detach();
20250    }
20251
20252    pub fn insert_uuid_v4(
20253        &mut self,
20254        _: &InsertUuidV4,
20255        window: &mut Window,
20256        cx: &mut Context<Self>,
20257    ) {
20258        self.insert_uuid(UuidVersion::V4, window, cx);
20259    }
20260
20261    pub fn insert_uuid_v7(
20262        &mut self,
20263        _: &InsertUuidV7,
20264        window: &mut Window,
20265        cx: &mut Context<Self>,
20266    ) {
20267        self.insert_uuid(UuidVersion::V7, window, cx);
20268    }
20269
20270    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20271        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20272        self.transact(window, cx, |this, window, cx| {
20273            let edits = this
20274                .selections
20275                .all::<Point>(&this.display_snapshot(cx))
20276                .into_iter()
20277                .map(|selection| {
20278                    let uuid = match version {
20279                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20280                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20281                    };
20282
20283                    (selection.range(), uuid.to_string())
20284                });
20285            this.edit(edits, cx);
20286            this.refresh_edit_prediction(true, false, window, cx);
20287        });
20288    }
20289
20290    pub fn open_selections_in_multibuffer(
20291        &mut self,
20292        _: &OpenSelectionsInMultibuffer,
20293        window: &mut Window,
20294        cx: &mut Context<Self>,
20295    ) {
20296        let multibuffer = self.buffer.read(cx);
20297
20298        let Some(buffer) = multibuffer.as_singleton() else {
20299            return;
20300        };
20301
20302        let Some(workspace) = self.workspace() else {
20303            return;
20304        };
20305
20306        let title = multibuffer.title(cx).to_string();
20307
20308        let locations = self
20309            .selections
20310            .all_anchors(cx)
20311            .iter()
20312            .map(|selection| {
20313                (
20314                    buffer.clone(),
20315                    (selection.start.text_anchor..selection.end.text_anchor)
20316                        .to_point(buffer.read(cx)),
20317                )
20318            })
20319            .into_group_map();
20320
20321        cx.spawn_in(window, async move |_, cx| {
20322            workspace.update_in(cx, |workspace, window, cx| {
20323                Self::open_locations_in_multibuffer(
20324                    workspace,
20325                    locations,
20326                    format!("Selections for '{title}'"),
20327                    false,
20328                    MultibufferSelectionMode::All,
20329                    window,
20330                    cx,
20331                );
20332            })
20333        })
20334        .detach();
20335    }
20336
20337    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20338    /// last highlight added will be used.
20339    ///
20340    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20341    pub fn highlight_rows<T: 'static>(
20342        &mut self,
20343        range: Range<Anchor>,
20344        color: Hsla,
20345        options: RowHighlightOptions,
20346        cx: &mut Context<Self>,
20347    ) {
20348        let snapshot = self.buffer().read(cx).snapshot(cx);
20349        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20350        let ix = row_highlights.binary_search_by(|highlight| {
20351            Ordering::Equal
20352                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20353                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20354        });
20355
20356        if let Err(mut ix) = ix {
20357            let index = post_inc(&mut self.highlight_order);
20358
20359            // If this range intersects with the preceding highlight, then merge it with
20360            // the preceding highlight. Otherwise insert a new highlight.
20361            let mut merged = false;
20362            if ix > 0 {
20363                let prev_highlight = &mut row_highlights[ix - 1];
20364                if prev_highlight
20365                    .range
20366                    .end
20367                    .cmp(&range.start, &snapshot)
20368                    .is_ge()
20369                {
20370                    ix -= 1;
20371                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20372                        prev_highlight.range.end = range.end;
20373                    }
20374                    merged = true;
20375                    prev_highlight.index = index;
20376                    prev_highlight.color = color;
20377                    prev_highlight.options = options;
20378                }
20379            }
20380
20381            if !merged {
20382                row_highlights.insert(
20383                    ix,
20384                    RowHighlight {
20385                        range,
20386                        index,
20387                        color,
20388                        options,
20389                        type_id: TypeId::of::<T>(),
20390                    },
20391                );
20392            }
20393
20394            // If any of the following highlights intersect with this one, merge them.
20395            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20396                let highlight = &row_highlights[ix];
20397                if next_highlight
20398                    .range
20399                    .start
20400                    .cmp(&highlight.range.end, &snapshot)
20401                    .is_le()
20402                {
20403                    if next_highlight
20404                        .range
20405                        .end
20406                        .cmp(&highlight.range.end, &snapshot)
20407                        .is_gt()
20408                    {
20409                        row_highlights[ix].range.end = next_highlight.range.end;
20410                    }
20411                    row_highlights.remove(ix + 1);
20412                } else {
20413                    break;
20414                }
20415            }
20416        }
20417    }
20418
20419    /// Remove any highlighted row ranges of the given type that intersect the
20420    /// given ranges.
20421    pub fn remove_highlighted_rows<T: 'static>(
20422        &mut self,
20423        ranges_to_remove: Vec<Range<Anchor>>,
20424        cx: &mut Context<Self>,
20425    ) {
20426        let snapshot = self.buffer().read(cx).snapshot(cx);
20427        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20428        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20429        row_highlights.retain(|highlight| {
20430            while let Some(range_to_remove) = ranges_to_remove.peek() {
20431                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20432                    Ordering::Less | Ordering::Equal => {
20433                        ranges_to_remove.next();
20434                    }
20435                    Ordering::Greater => {
20436                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20437                            Ordering::Less | Ordering::Equal => {
20438                                return false;
20439                            }
20440                            Ordering::Greater => break,
20441                        }
20442                    }
20443                }
20444            }
20445
20446            true
20447        })
20448    }
20449
20450    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20451    pub fn clear_row_highlights<T: 'static>(&mut self) {
20452        self.highlighted_rows.remove(&TypeId::of::<T>());
20453    }
20454
20455    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20456    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20457        self.highlighted_rows
20458            .get(&TypeId::of::<T>())
20459            .map_or(&[] as &[_], |vec| vec.as_slice())
20460            .iter()
20461            .map(|highlight| (highlight.range.clone(), highlight.color))
20462    }
20463
20464    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20465    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20466    /// Allows to ignore certain kinds of highlights.
20467    pub fn highlighted_display_rows(
20468        &self,
20469        window: &mut Window,
20470        cx: &mut App,
20471    ) -> BTreeMap<DisplayRow, LineHighlight> {
20472        let snapshot = self.snapshot(window, cx);
20473        let mut used_highlight_orders = HashMap::default();
20474        self.highlighted_rows
20475            .iter()
20476            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20477            .fold(
20478                BTreeMap::<DisplayRow, LineHighlight>::new(),
20479                |mut unique_rows, highlight| {
20480                    let start = highlight.range.start.to_display_point(&snapshot);
20481                    let end = highlight.range.end.to_display_point(&snapshot);
20482                    let start_row = start.row().0;
20483                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20484                        && end.column() == 0
20485                    {
20486                        end.row().0.saturating_sub(1)
20487                    } else {
20488                        end.row().0
20489                    };
20490                    for row in start_row..=end_row {
20491                        let used_index =
20492                            used_highlight_orders.entry(row).or_insert(highlight.index);
20493                        if highlight.index >= *used_index {
20494                            *used_index = highlight.index;
20495                            unique_rows.insert(
20496                                DisplayRow(row),
20497                                LineHighlight {
20498                                    include_gutter: highlight.options.include_gutter,
20499                                    border: None,
20500                                    background: highlight.color.into(),
20501                                    type_id: Some(highlight.type_id),
20502                                },
20503                            );
20504                        }
20505                    }
20506                    unique_rows
20507                },
20508            )
20509    }
20510
20511    pub fn highlighted_display_row_for_autoscroll(
20512        &self,
20513        snapshot: &DisplaySnapshot,
20514    ) -> Option<DisplayRow> {
20515        self.highlighted_rows
20516            .values()
20517            .flat_map(|highlighted_rows| highlighted_rows.iter())
20518            .filter_map(|highlight| {
20519                if highlight.options.autoscroll {
20520                    Some(highlight.range.start.to_display_point(snapshot).row())
20521                } else {
20522                    None
20523                }
20524            })
20525            .min()
20526    }
20527
20528    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20529        self.highlight_background::<SearchWithinRange>(
20530            ranges,
20531            |colors| colors.colors().editor_document_highlight_read_background,
20532            cx,
20533        )
20534    }
20535
20536    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20537        self.breadcrumb_header = Some(new_header);
20538    }
20539
20540    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20541        self.clear_background_highlights::<SearchWithinRange>(cx);
20542    }
20543
20544    pub fn highlight_background<T: 'static>(
20545        &mut self,
20546        ranges: &[Range<Anchor>],
20547        color_fetcher: fn(&Theme) -> Hsla,
20548        cx: &mut Context<Self>,
20549    ) {
20550        self.background_highlights.insert(
20551            HighlightKey::Type(TypeId::of::<T>()),
20552            (color_fetcher, Arc::from(ranges)),
20553        );
20554        self.scrollbar_marker_state.dirty = true;
20555        cx.notify();
20556    }
20557
20558    pub fn highlight_background_key<T: 'static>(
20559        &mut self,
20560        key: usize,
20561        ranges: &[Range<Anchor>],
20562        color_fetcher: fn(&Theme) -> Hsla,
20563        cx: &mut Context<Self>,
20564    ) {
20565        self.background_highlights.insert(
20566            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20567            (color_fetcher, Arc::from(ranges)),
20568        );
20569        self.scrollbar_marker_state.dirty = true;
20570        cx.notify();
20571    }
20572
20573    pub fn clear_background_highlights<T: 'static>(
20574        &mut self,
20575        cx: &mut Context<Self>,
20576    ) -> Option<BackgroundHighlight> {
20577        let text_highlights = self
20578            .background_highlights
20579            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20580        if !text_highlights.1.is_empty() {
20581            self.scrollbar_marker_state.dirty = true;
20582            cx.notify();
20583        }
20584        Some(text_highlights)
20585    }
20586
20587    pub fn highlight_gutter<T: 'static>(
20588        &mut self,
20589        ranges: impl Into<Vec<Range<Anchor>>>,
20590        color_fetcher: fn(&App) -> Hsla,
20591        cx: &mut Context<Self>,
20592    ) {
20593        self.gutter_highlights
20594            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20595        cx.notify();
20596    }
20597
20598    pub fn clear_gutter_highlights<T: 'static>(
20599        &mut self,
20600        cx: &mut Context<Self>,
20601    ) -> Option<GutterHighlight> {
20602        cx.notify();
20603        self.gutter_highlights.remove(&TypeId::of::<T>())
20604    }
20605
20606    pub fn insert_gutter_highlight<T: 'static>(
20607        &mut self,
20608        range: Range<Anchor>,
20609        color_fetcher: fn(&App) -> Hsla,
20610        cx: &mut Context<Self>,
20611    ) {
20612        let snapshot = self.buffer().read(cx).snapshot(cx);
20613        let mut highlights = self
20614            .gutter_highlights
20615            .remove(&TypeId::of::<T>())
20616            .map(|(_, highlights)| highlights)
20617            .unwrap_or_default();
20618        let ix = highlights.binary_search_by(|highlight| {
20619            Ordering::Equal
20620                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20621                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20622        });
20623        if let Err(ix) = ix {
20624            highlights.insert(ix, range);
20625        }
20626        self.gutter_highlights
20627            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20628    }
20629
20630    pub fn remove_gutter_highlights<T: 'static>(
20631        &mut self,
20632        ranges_to_remove: Vec<Range<Anchor>>,
20633        cx: &mut Context<Self>,
20634    ) {
20635        let snapshot = self.buffer().read(cx).snapshot(cx);
20636        let Some((color_fetcher, mut gutter_highlights)) =
20637            self.gutter_highlights.remove(&TypeId::of::<T>())
20638        else {
20639            return;
20640        };
20641        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20642        gutter_highlights.retain(|highlight| {
20643            while let Some(range_to_remove) = ranges_to_remove.peek() {
20644                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20645                    Ordering::Less | Ordering::Equal => {
20646                        ranges_to_remove.next();
20647                    }
20648                    Ordering::Greater => {
20649                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20650                            Ordering::Less | Ordering::Equal => {
20651                                return false;
20652                            }
20653                            Ordering::Greater => break,
20654                        }
20655                    }
20656                }
20657            }
20658
20659            true
20660        });
20661        self.gutter_highlights
20662            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20663    }
20664
20665    #[cfg(feature = "test-support")]
20666    pub fn all_text_highlights(
20667        &self,
20668        window: &mut Window,
20669        cx: &mut Context<Self>,
20670    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20671        let snapshot = self.snapshot(window, cx);
20672        self.display_map.update(cx, |display_map, _| {
20673            display_map
20674                .all_text_highlights()
20675                .map(|highlight| {
20676                    let (style, ranges) = highlight.as_ref();
20677                    (
20678                        *style,
20679                        ranges
20680                            .iter()
20681                            .map(|range| range.clone().to_display_points(&snapshot))
20682                            .collect(),
20683                    )
20684                })
20685                .collect()
20686        })
20687    }
20688
20689    #[cfg(feature = "test-support")]
20690    pub fn all_text_background_highlights(
20691        &self,
20692        window: &mut Window,
20693        cx: &mut Context<Self>,
20694    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20695        let snapshot = self.snapshot(window, cx);
20696        let buffer = &snapshot.buffer_snapshot();
20697        let start = buffer.anchor_before(0);
20698        let end = buffer.anchor_after(buffer.len());
20699        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20700    }
20701
20702    #[cfg(any(test, feature = "test-support"))]
20703    pub fn sorted_background_highlights_in_range(
20704        &self,
20705        search_range: Range<Anchor>,
20706        display_snapshot: &DisplaySnapshot,
20707        theme: &Theme,
20708    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20709        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20710        res.sort_by(|a, b| {
20711            a.0.start
20712                .cmp(&b.0.start)
20713                .then_with(|| a.0.end.cmp(&b.0.end))
20714                .then_with(|| a.1.cmp(&b.1))
20715        });
20716        res
20717    }
20718
20719    #[cfg(feature = "test-support")]
20720    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20721        let snapshot = self.buffer().read(cx).snapshot(cx);
20722
20723        let highlights = self
20724            .background_highlights
20725            .get(&HighlightKey::Type(TypeId::of::<
20726                items::BufferSearchHighlights,
20727            >()));
20728
20729        if let Some((_color, ranges)) = highlights {
20730            ranges
20731                .iter()
20732                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20733                .collect_vec()
20734        } else {
20735            vec![]
20736        }
20737    }
20738
20739    fn document_highlights_for_position<'a>(
20740        &'a self,
20741        position: Anchor,
20742        buffer: &'a MultiBufferSnapshot,
20743    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20744        let read_highlights = self
20745            .background_highlights
20746            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20747            .map(|h| &h.1);
20748        let write_highlights = self
20749            .background_highlights
20750            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20751            .map(|h| &h.1);
20752        let left_position = position.bias_left(buffer);
20753        let right_position = position.bias_right(buffer);
20754        read_highlights
20755            .into_iter()
20756            .chain(write_highlights)
20757            .flat_map(move |ranges| {
20758                let start_ix = match ranges.binary_search_by(|probe| {
20759                    let cmp = probe.end.cmp(&left_position, buffer);
20760                    if cmp.is_ge() {
20761                        Ordering::Greater
20762                    } else {
20763                        Ordering::Less
20764                    }
20765                }) {
20766                    Ok(i) | Err(i) => i,
20767                };
20768
20769                ranges[start_ix..]
20770                    .iter()
20771                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20772            })
20773    }
20774
20775    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20776        self.background_highlights
20777            .get(&HighlightKey::Type(TypeId::of::<T>()))
20778            .is_some_and(|(_, highlights)| !highlights.is_empty())
20779    }
20780
20781    /// Returns all background highlights for a given range.
20782    ///
20783    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20784    pub fn background_highlights_in_range(
20785        &self,
20786        search_range: Range<Anchor>,
20787        display_snapshot: &DisplaySnapshot,
20788        theme: &Theme,
20789    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20790        let mut results = Vec::new();
20791        for (color_fetcher, ranges) in self.background_highlights.values() {
20792            let color = color_fetcher(theme);
20793            let start_ix = match ranges.binary_search_by(|probe| {
20794                let cmp = probe
20795                    .end
20796                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20797                if cmp.is_gt() {
20798                    Ordering::Greater
20799                } else {
20800                    Ordering::Less
20801                }
20802            }) {
20803                Ok(i) | Err(i) => i,
20804            };
20805            for range in &ranges[start_ix..] {
20806                if range
20807                    .start
20808                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20809                    .is_ge()
20810                {
20811                    break;
20812                }
20813
20814                let start = range.start.to_display_point(display_snapshot);
20815                let end = range.end.to_display_point(display_snapshot);
20816                results.push((start..end, color))
20817            }
20818        }
20819        results
20820    }
20821
20822    pub fn gutter_highlights_in_range(
20823        &self,
20824        search_range: Range<Anchor>,
20825        display_snapshot: &DisplaySnapshot,
20826        cx: &App,
20827    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20828        let mut results = Vec::new();
20829        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20830            let color = color_fetcher(cx);
20831            let start_ix = match ranges.binary_search_by(|probe| {
20832                let cmp = probe
20833                    .end
20834                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20835                if cmp.is_gt() {
20836                    Ordering::Greater
20837                } else {
20838                    Ordering::Less
20839                }
20840            }) {
20841                Ok(i) | Err(i) => i,
20842            };
20843            for range in &ranges[start_ix..] {
20844                if range
20845                    .start
20846                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20847                    .is_ge()
20848                {
20849                    break;
20850                }
20851
20852                let start = range.start.to_display_point(display_snapshot);
20853                let end = range.end.to_display_point(display_snapshot);
20854                results.push((start..end, color))
20855            }
20856        }
20857        results
20858    }
20859
20860    /// Get the text ranges corresponding to the redaction query
20861    pub fn redacted_ranges(
20862        &self,
20863        search_range: Range<Anchor>,
20864        display_snapshot: &DisplaySnapshot,
20865        cx: &App,
20866    ) -> Vec<Range<DisplayPoint>> {
20867        display_snapshot
20868            .buffer_snapshot()
20869            .redacted_ranges(search_range, |file| {
20870                if let Some(file) = file {
20871                    file.is_private()
20872                        && EditorSettings::get(
20873                            Some(SettingsLocation {
20874                                worktree_id: file.worktree_id(cx),
20875                                path: file.path().as_ref(),
20876                            }),
20877                            cx,
20878                        )
20879                        .redact_private_values
20880                } else {
20881                    false
20882                }
20883            })
20884            .map(|range| {
20885                range.start.to_display_point(display_snapshot)
20886                    ..range.end.to_display_point(display_snapshot)
20887            })
20888            .collect()
20889    }
20890
20891    pub fn highlight_text_key<T: 'static>(
20892        &mut self,
20893        key: usize,
20894        ranges: Vec<Range<Anchor>>,
20895        style: HighlightStyle,
20896        cx: &mut Context<Self>,
20897    ) {
20898        self.display_map.update(cx, |map, _| {
20899            map.highlight_text(
20900                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20901                ranges,
20902                style,
20903            );
20904        });
20905        cx.notify();
20906    }
20907
20908    pub fn highlight_text<T: 'static>(
20909        &mut self,
20910        ranges: Vec<Range<Anchor>>,
20911        style: HighlightStyle,
20912        cx: &mut Context<Self>,
20913    ) {
20914        self.display_map.update(cx, |map, _| {
20915            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20916        });
20917        cx.notify();
20918    }
20919
20920    pub fn text_highlights<'a, T: 'static>(
20921        &'a self,
20922        cx: &'a App,
20923    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20924        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20925    }
20926
20927    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20928        let cleared = self
20929            .display_map
20930            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20931        if cleared {
20932            cx.notify();
20933        }
20934    }
20935
20936    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20937        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20938            && self.focus_handle.is_focused(window)
20939    }
20940
20941    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20942        self.show_cursor_when_unfocused = is_enabled;
20943        cx.notify();
20944    }
20945
20946    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20947        cx.notify();
20948    }
20949
20950    fn on_debug_session_event(
20951        &mut self,
20952        _session: Entity<Session>,
20953        event: &SessionEvent,
20954        cx: &mut Context<Self>,
20955    ) {
20956        if let SessionEvent::InvalidateInlineValue = event {
20957            self.refresh_inline_values(cx);
20958        }
20959    }
20960
20961    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20962        let Some(project) = self.project.clone() else {
20963            return;
20964        };
20965
20966        if !self.inline_value_cache.enabled {
20967            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20968            self.splice_inlays(&inlays, Vec::new(), cx);
20969            return;
20970        }
20971
20972        let current_execution_position = self
20973            .highlighted_rows
20974            .get(&TypeId::of::<ActiveDebugLine>())
20975            .and_then(|lines| lines.last().map(|line| line.range.end));
20976
20977        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20978            let inline_values = editor
20979                .update(cx, |editor, cx| {
20980                    let Some(current_execution_position) = current_execution_position else {
20981                        return Some(Task::ready(Ok(Vec::new())));
20982                    };
20983
20984                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20985                        let snapshot = buffer.snapshot(cx);
20986
20987                        let excerpt = snapshot.excerpt_containing(
20988                            current_execution_position..current_execution_position,
20989                        )?;
20990
20991                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20992                    })?;
20993
20994                    let range =
20995                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20996
20997                    project.inline_values(buffer, range, cx)
20998                })
20999                .ok()
21000                .flatten()?
21001                .await
21002                .context("refreshing debugger inlays")
21003                .log_err()?;
21004
21005            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
21006
21007            for (buffer_id, inline_value) in inline_values
21008                .into_iter()
21009                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
21010            {
21011                buffer_inline_values
21012                    .entry(buffer_id)
21013                    .or_default()
21014                    .push(inline_value);
21015            }
21016
21017            editor
21018                .update(cx, |editor, cx| {
21019                    let snapshot = editor.buffer.read(cx).snapshot(cx);
21020                    let mut new_inlays = Vec::default();
21021
21022                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
21023                        let buffer_id = buffer_snapshot.remote_id();
21024                        buffer_inline_values
21025                            .get(&buffer_id)
21026                            .into_iter()
21027                            .flatten()
21028                            .for_each(|hint| {
21029                                let inlay = Inlay::debugger(
21030                                    post_inc(&mut editor.next_inlay_id),
21031                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
21032                                    hint.text(),
21033                                );
21034                                if !inlay.text().chars().contains(&'\n') {
21035                                    new_inlays.push(inlay);
21036                                }
21037                            });
21038                    }
21039
21040                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
21041                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
21042
21043                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
21044                })
21045                .ok()?;
21046            Some(())
21047        });
21048    }
21049
21050    fn on_buffer_event(
21051        &mut self,
21052        multibuffer: &Entity<MultiBuffer>,
21053        event: &multi_buffer::Event,
21054        window: &mut Window,
21055        cx: &mut Context<Self>,
21056    ) {
21057        match event {
21058            multi_buffer::Event::Edited { edited_buffer } => {
21059                self.scrollbar_marker_state.dirty = true;
21060                self.active_indent_guides_state.dirty = true;
21061                self.refresh_active_diagnostics(cx);
21062                self.refresh_code_actions(window, cx);
21063                self.refresh_selected_text_highlights(true, window, cx);
21064                self.refresh_single_line_folds(window, cx);
21065                self.refresh_matching_bracket_highlights(window, cx);
21066                if self.has_active_edit_prediction() {
21067                    self.update_visible_edit_prediction(window, cx);
21068                }
21069
21070                if let Some(buffer) = edited_buffer {
21071                    if buffer.read(cx).file().is_none() {
21072                        cx.emit(EditorEvent::TitleChanged);
21073                    }
21074
21075                    if self.project.is_some() {
21076                        let buffer_id = buffer.read(cx).remote_id();
21077                        self.register_buffer(buffer_id, cx);
21078                        self.update_lsp_data(Some(buffer_id), window, cx);
21079                        self.refresh_inlay_hints(
21080                            InlayHintRefreshReason::BufferEdited(buffer_id),
21081                            cx,
21082                        );
21083                    }
21084                }
21085
21086                cx.emit(EditorEvent::BufferEdited);
21087                cx.emit(SearchEvent::MatchesInvalidated);
21088
21089                let Some(project) = &self.project else { return };
21090                let (telemetry, is_via_ssh) = {
21091                    let project = project.read(cx);
21092                    let telemetry = project.client().telemetry().clone();
21093                    let is_via_ssh = project.is_via_remote_server();
21094                    (telemetry, is_via_ssh)
21095                };
21096                telemetry.log_edit_event("editor", is_via_ssh);
21097            }
21098            multi_buffer::Event::ExcerptsAdded {
21099                buffer,
21100                predecessor,
21101                excerpts,
21102            } => {
21103                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21104                let buffer_id = buffer.read(cx).remote_id();
21105                if self.buffer.read(cx).diff_for(buffer_id).is_none()
21106                    && let Some(project) = &self.project
21107                {
21108                    update_uncommitted_diff_for_buffer(
21109                        cx.entity(),
21110                        project,
21111                        [buffer.clone()],
21112                        self.buffer.clone(),
21113                        cx,
21114                    )
21115                    .detach();
21116                }
21117                self.update_lsp_data(Some(buffer_id), window, cx);
21118                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21119                cx.emit(EditorEvent::ExcerptsAdded {
21120                    buffer: buffer.clone(),
21121                    predecessor: *predecessor,
21122                    excerpts: excerpts.clone(),
21123                });
21124            }
21125            multi_buffer::Event::ExcerptsRemoved {
21126                ids,
21127                removed_buffer_ids,
21128            } => {
21129                if let Some(inlay_hints) = &mut self.inlay_hints {
21130                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
21131                }
21132                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
21133                for buffer_id in removed_buffer_ids {
21134                    self.registered_buffers.remove(buffer_id);
21135                }
21136                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21137                cx.emit(EditorEvent::ExcerptsRemoved {
21138                    ids: ids.clone(),
21139                    removed_buffer_ids: removed_buffer_ids.clone(),
21140                });
21141            }
21142            multi_buffer::Event::ExcerptsEdited {
21143                excerpt_ids,
21144                buffer_ids,
21145            } => {
21146                self.display_map.update(cx, |map, cx| {
21147                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
21148                });
21149                cx.emit(EditorEvent::ExcerptsEdited {
21150                    ids: excerpt_ids.clone(),
21151                });
21152            }
21153            multi_buffer::Event::ExcerptsExpanded { ids } => {
21154                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21155                self.refresh_document_highlights(cx);
21156                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
21157            }
21158            multi_buffer::Event::Reparsed(buffer_id) => {
21159                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21160                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21161
21162                cx.emit(EditorEvent::Reparsed(*buffer_id));
21163            }
21164            multi_buffer::Event::DiffHunksToggled => {
21165                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21166            }
21167            multi_buffer::Event::LanguageChanged(buffer_id) => {
21168                self.registered_buffers.remove(&buffer_id);
21169                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21170                cx.emit(EditorEvent::Reparsed(*buffer_id));
21171                cx.notify();
21172            }
21173            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
21174            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21175            multi_buffer::Event::FileHandleChanged
21176            | multi_buffer::Event::Reloaded
21177            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21178            multi_buffer::Event::DiagnosticsUpdated => {
21179                self.update_diagnostics_state(window, cx);
21180            }
21181            _ => {}
21182        };
21183    }
21184
21185    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21186        if !self.diagnostics_enabled() {
21187            return;
21188        }
21189        self.refresh_active_diagnostics(cx);
21190        self.refresh_inline_diagnostics(true, window, cx);
21191        self.scrollbar_marker_state.dirty = true;
21192        cx.notify();
21193    }
21194
21195    pub fn start_temporary_diff_override(&mut self) {
21196        self.load_diff_task.take();
21197        self.temporary_diff_override = true;
21198    }
21199
21200    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21201        self.temporary_diff_override = false;
21202        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21203        self.buffer.update(cx, |buffer, cx| {
21204            buffer.set_all_diff_hunks_collapsed(cx);
21205        });
21206
21207        if let Some(project) = self.project.clone() {
21208            self.load_diff_task = Some(
21209                update_uncommitted_diff_for_buffer(
21210                    cx.entity(),
21211                    &project,
21212                    self.buffer.read(cx).all_buffers(),
21213                    self.buffer.clone(),
21214                    cx,
21215                )
21216                .shared(),
21217            );
21218        }
21219    }
21220
21221    fn on_display_map_changed(
21222        &mut self,
21223        _: Entity<DisplayMap>,
21224        _: &mut Window,
21225        cx: &mut Context<Self>,
21226    ) {
21227        cx.notify();
21228    }
21229
21230    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21231        if self.diagnostics_enabled() {
21232            let new_severity = EditorSettings::get_global(cx)
21233                .diagnostics_max_severity
21234                .unwrap_or(DiagnosticSeverity::Hint);
21235            self.set_max_diagnostics_severity(new_severity, cx);
21236        }
21237        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21238        self.update_edit_prediction_settings(cx);
21239        self.refresh_edit_prediction(true, false, window, cx);
21240        self.refresh_inline_values(cx);
21241        self.refresh_inlay_hints(
21242            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21243                self.selections.newest_anchor().head(),
21244                &self.buffer.read(cx).snapshot(cx),
21245                cx,
21246            )),
21247            cx,
21248        );
21249
21250        let old_cursor_shape = self.cursor_shape;
21251        let old_show_breadcrumbs = self.show_breadcrumbs;
21252
21253        {
21254            let editor_settings = EditorSettings::get_global(cx);
21255            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21256            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21257            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21258            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21259        }
21260
21261        if old_cursor_shape != self.cursor_shape {
21262            cx.emit(EditorEvent::CursorShapeChanged);
21263        }
21264
21265        if old_show_breadcrumbs != self.show_breadcrumbs {
21266            cx.emit(EditorEvent::BreadcrumbsChanged);
21267        }
21268
21269        let project_settings = ProjectSettings::get_global(cx);
21270        self.buffer_serialization = self
21271            .should_serialize_buffer()
21272            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
21273
21274        if self.mode.is_full() {
21275            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21276            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21277            if self.show_inline_diagnostics != show_inline_diagnostics {
21278                self.show_inline_diagnostics = show_inline_diagnostics;
21279                self.refresh_inline_diagnostics(false, window, cx);
21280            }
21281
21282            if self.git_blame_inline_enabled != inline_blame_enabled {
21283                self.toggle_git_blame_inline_internal(false, window, cx);
21284            }
21285
21286            let minimap_settings = EditorSettings::get_global(cx).minimap;
21287            if self.minimap_visibility != MinimapVisibility::Disabled {
21288                if self.minimap_visibility.settings_visibility()
21289                    != minimap_settings.minimap_enabled()
21290                {
21291                    self.set_minimap_visibility(
21292                        MinimapVisibility::for_mode(self.mode(), cx),
21293                        window,
21294                        cx,
21295                    );
21296                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21297                    minimap_entity.update(cx, |minimap_editor, cx| {
21298                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21299                    })
21300                }
21301            }
21302        }
21303
21304        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21305            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21306        }) {
21307            if !inlay_splice.is_empty() {
21308                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21309            }
21310            self.refresh_colors_for_visible_range(None, window, cx);
21311        }
21312
21313        cx.notify();
21314    }
21315
21316    pub fn set_searchable(&mut self, searchable: bool) {
21317        self.searchable = searchable;
21318    }
21319
21320    pub fn searchable(&self) -> bool {
21321        self.searchable
21322    }
21323
21324    pub fn open_excerpts_in_split(
21325        &mut self,
21326        _: &OpenExcerptsSplit,
21327        window: &mut Window,
21328        cx: &mut Context<Self>,
21329    ) {
21330        self.open_excerpts_common(None, true, window, cx)
21331    }
21332
21333    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21334        self.open_excerpts_common(None, false, window, cx)
21335    }
21336
21337    fn open_excerpts_common(
21338        &mut self,
21339        jump_data: Option<JumpData>,
21340        split: bool,
21341        window: &mut Window,
21342        cx: &mut Context<Self>,
21343    ) {
21344        let Some(workspace) = self.workspace() else {
21345            cx.propagate();
21346            return;
21347        };
21348
21349        if self.buffer.read(cx).is_singleton() {
21350            cx.propagate();
21351            return;
21352        }
21353
21354        let mut new_selections_by_buffer = HashMap::default();
21355        match &jump_data {
21356            Some(JumpData::MultiBufferPoint {
21357                excerpt_id,
21358                position,
21359                anchor,
21360                line_offset_from_top,
21361            }) => {
21362                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21363                if let Some(buffer) = multi_buffer_snapshot
21364                    .buffer_id_for_excerpt(*excerpt_id)
21365                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21366                {
21367                    let buffer_snapshot = buffer.read(cx).snapshot();
21368                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21369                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21370                    } else {
21371                        buffer_snapshot.clip_point(*position, Bias::Left)
21372                    };
21373                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21374                    new_selections_by_buffer.insert(
21375                        buffer,
21376                        (
21377                            vec![jump_to_offset..jump_to_offset],
21378                            Some(*line_offset_from_top),
21379                        ),
21380                    );
21381                }
21382            }
21383            Some(JumpData::MultiBufferRow {
21384                row,
21385                line_offset_from_top,
21386            }) => {
21387                let point = MultiBufferPoint::new(row.0, 0);
21388                if let Some((buffer, buffer_point, _)) =
21389                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21390                {
21391                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21392                    new_selections_by_buffer
21393                        .entry(buffer)
21394                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21395                        .0
21396                        .push(buffer_offset..buffer_offset)
21397                }
21398            }
21399            None => {
21400                let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
21401                let multi_buffer = self.buffer.read(cx);
21402                for selection in selections {
21403                    for (snapshot, range, _, anchor) in multi_buffer
21404                        .snapshot(cx)
21405                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21406                    {
21407                        if let Some(anchor) = anchor {
21408                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21409                            else {
21410                                continue;
21411                            };
21412                            let offset = text::ToOffset::to_offset(
21413                                &anchor.text_anchor,
21414                                &buffer_handle.read(cx).snapshot(),
21415                            );
21416                            let range = offset..offset;
21417                            new_selections_by_buffer
21418                                .entry(buffer_handle)
21419                                .or_insert((Vec::new(), None))
21420                                .0
21421                                .push(range)
21422                        } else {
21423                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21424                            else {
21425                                continue;
21426                            };
21427                            new_selections_by_buffer
21428                                .entry(buffer_handle)
21429                                .or_insert((Vec::new(), None))
21430                                .0
21431                                .push(range)
21432                        }
21433                    }
21434                }
21435            }
21436        }
21437
21438        new_selections_by_buffer
21439            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21440
21441        if new_selections_by_buffer.is_empty() {
21442            return;
21443        }
21444
21445        // We defer the pane interaction because we ourselves are a workspace item
21446        // and activating a new item causes the pane to call a method on us reentrantly,
21447        // which panics if we're on the stack.
21448        window.defer(cx, move |window, cx| {
21449            workspace.update(cx, |workspace, cx| {
21450                let pane = if split {
21451                    workspace.adjacent_pane(window, cx)
21452                } else {
21453                    workspace.active_pane().clone()
21454                };
21455
21456                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21457                    let editor = buffer
21458                        .read(cx)
21459                        .file()
21460                        .is_none()
21461                        .then(|| {
21462                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21463                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21464                            // Instead, we try to activate the existing editor in the pane first.
21465                            let (editor, pane_item_index) =
21466                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21467                                    let editor = item.downcast::<Editor>()?;
21468                                    let singleton_buffer =
21469                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21470                                    if singleton_buffer == buffer {
21471                                        Some((editor, i))
21472                                    } else {
21473                                        None
21474                                    }
21475                                })?;
21476                            pane.update(cx, |pane, cx| {
21477                                pane.activate_item(pane_item_index, true, true, window, cx)
21478                            });
21479                            Some(editor)
21480                        })
21481                        .flatten()
21482                        .unwrap_or_else(|| {
21483                            workspace.open_project_item::<Self>(
21484                                pane.clone(),
21485                                buffer,
21486                                true,
21487                                true,
21488                                window,
21489                                cx,
21490                            )
21491                        });
21492
21493                    editor.update(cx, |editor, cx| {
21494                        let autoscroll = match scroll_offset {
21495                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21496                            None => Autoscroll::newest(),
21497                        };
21498                        let nav_history = editor.nav_history.take();
21499                        editor.change_selections(
21500                            SelectionEffects::scroll(autoscroll),
21501                            window,
21502                            cx,
21503                            |s| {
21504                                s.select_ranges(ranges);
21505                            },
21506                        );
21507                        editor.nav_history = nav_history;
21508                    });
21509                }
21510            })
21511        });
21512    }
21513
21514    // For now, don't allow opening excerpts in buffers that aren't backed by
21515    // regular project files.
21516    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21517        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21518    }
21519
21520    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21521        let snapshot = self.buffer.read(cx).read(cx);
21522        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21523        Some(
21524            ranges
21525                .iter()
21526                .map(move |range| {
21527                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21528                })
21529                .collect(),
21530        )
21531    }
21532
21533    fn selection_replacement_ranges(
21534        &self,
21535        range: Range<OffsetUtf16>,
21536        cx: &mut App,
21537    ) -> Vec<Range<OffsetUtf16>> {
21538        let selections = self
21539            .selections
21540            .all::<OffsetUtf16>(&self.display_snapshot(cx));
21541        let newest_selection = selections
21542            .iter()
21543            .max_by_key(|selection| selection.id)
21544            .unwrap();
21545        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21546        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21547        let snapshot = self.buffer.read(cx).read(cx);
21548        selections
21549            .into_iter()
21550            .map(|mut selection| {
21551                selection.start.0 =
21552                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21553                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21554                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21555                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21556            })
21557            .collect()
21558    }
21559
21560    fn report_editor_event(
21561        &self,
21562        reported_event: ReportEditorEvent,
21563        file_extension: Option<String>,
21564        cx: &App,
21565    ) {
21566        if cfg!(any(test, feature = "test-support")) {
21567            return;
21568        }
21569
21570        let Some(project) = &self.project else { return };
21571
21572        // If None, we are in a file without an extension
21573        let file = self
21574            .buffer
21575            .read(cx)
21576            .as_singleton()
21577            .and_then(|b| b.read(cx).file());
21578        let file_extension = file_extension.or(file
21579            .as_ref()
21580            .and_then(|file| Path::new(file.file_name(cx)).extension())
21581            .and_then(|e| e.to_str())
21582            .map(|a| a.to_string()));
21583
21584        let vim_mode = vim_flavor(cx).is_some();
21585
21586        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21587        let copilot_enabled = edit_predictions_provider
21588            == language::language_settings::EditPredictionProvider::Copilot;
21589        let copilot_enabled_for_language = self
21590            .buffer
21591            .read(cx)
21592            .language_settings(cx)
21593            .show_edit_predictions;
21594
21595        let project = project.read(cx);
21596        let event_type = reported_event.event_type();
21597
21598        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21599            telemetry::event!(
21600                event_type,
21601                type = if auto_saved {"autosave"} else {"manual"},
21602                file_extension,
21603                vim_mode,
21604                copilot_enabled,
21605                copilot_enabled_for_language,
21606                edit_predictions_provider,
21607                is_via_ssh = project.is_via_remote_server(),
21608            );
21609        } else {
21610            telemetry::event!(
21611                event_type,
21612                file_extension,
21613                vim_mode,
21614                copilot_enabled,
21615                copilot_enabled_for_language,
21616                edit_predictions_provider,
21617                is_via_ssh = project.is_via_remote_server(),
21618            );
21619        };
21620    }
21621
21622    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21623    /// with each line being an array of {text, highlight} objects.
21624    fn copy_highlight_json(
21625        &mut self,
21626        _: &CopyHighlightJson,
21627        window: &mut Window,
21628        cx: &mut Context<Self>,
21629    ) {
21630        #[derive(Serialize)]
21631        struct Chunk<'a> {
21632            text: String,
21633            highlight: Option<&'a str>,
21634        }
21635
21636        let snapshot = self.buffer.read(cx).snapshot(cx);
21637        let range = self
21638            .selected_text_range(false, window, cx)
21639            .and_then(|selection| {
21640                if selection.range.is_empty() {
21641                    None
21642                } else {
21643                    Some(
21644                        snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.start))
21645                            ..snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.end)),
21646                    )
21647                }
21648            })
21649            .unwrap_or_else(|| 0..snapshot.len());
21650
21651        let chunks = snapshot.chunks(range, true);
21652        let mut lines = Vec::new();
21653        let mut line: VecDeque<Chunk> = VecDeque::new();
21654
21655        let Some(style) = self.style.as_ref() else {
21656            return;
21657        };
21658
21659        for chunk in chunks {
21660            let highlight = chunk
21661                .syntax_highlight_id
21662                .and_then(|id| id.name(&style.syntax));
21663            let mut chunk_lines = chunk.text.split('\n').peekable();
21664            while let Some(text) = chunk_lines.next() {
21665                let mut merged_with_last_token = false;
21666                if let Some(last_token) = line.back_mut()
21667                    && last_token.highlight == highlight
21668                {
21669                    last_token.text.push_str(text);
21670                    merged_with_last_token = true;
21671                }
21672
21673                if !merged_with_last_token {
21674                    line.push_back(Chunk {
21675                        text: text.into(),
21676                        highlight,
21677                    });
21678                }
21679
21680                if chunk_lines.peek().is_some() {
21681                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21682                        line.pop_front();
21683                    }
21684                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21685                        line.pop_back();
21686                    }
21687
21688                    lines.push(mem::take(&mut line));
21689                }
21690            }
21691        }
21692
21693        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21694            return;
21695        };
21696        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21697    }
21698
21699    pub fn open_context_menu(
21700        &mut self,
21701        _: &OpenContextMenu,
21702        window: &mut Window,
21703        cx: &mut Context<Self>,
21704    ) {
21705        self.request_autoscroll(Autoscroll::newest(), cx);
21706        let position = self
21707            .selections
21708            .newest_display(&self.display_snapshot(cx))
21709            .start;
21710        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21711    }
21712
21713    pub fn replay_insert_event(
21714        &mut self,
21715        text: &str,
21716        relative_utf16_range: Option<Range<isize>>,
21717        window: &mut Window,
21718        cx: &mut Context<Self>,
21719    ) {
21720        if !self.input_enabled {
21721            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21722            return;
21723        }
21724        if let Some(relative_utf16_range) = relative_utf16_range {
21725            let selections = self
21726                .selections
21727                .all::<OffsetUtf16>(&self.display_snapshot(cx));
21728            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21729                let new_ranges = selections.into_iter().map(|range| {
21730                    let start = OffsetUtf16(
21731                        range
21732                            .head()
21733                            .0
21734                            .saturating_add_signed(relative_utf16_range.start),
21735                    );
21736                    let end = OffsetUtf16(
21737                        range
21738                            .head()
21739                            .0
21740                            .saturating_add_signed(relative_utf16_range.end),
21741                    );
21742                    start..end
21743                });
21744                s.select_ranges(new_ranges);
21745            });
21746        }
21747
21748        self.handle_input(text, window, cx);
21749    }
21750
21751    pub fn is_focused(&self, window: &Window) -> bool {
21752        self.focus_handle.is_focused(window)
21753    }
21754
21755    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21756        cx.emit(EditorEvent::Focused);
21757
21758        if let Some(descendant) = self
21759            .last_focused_descendant
21760            .take()
21761            .and_then(|descendant| descendant.upgrade())
21762        {
21763            window.focus(&descendant);
21764        } else {
21765            if let Some(blame) = self.blame.as_ref() {
21766                blame.update(cx, GitBlame::focus)
21767            }
21768
21769            self.blink_manager.update(cx, BlinkManager::enable);
21770            self.show_cursor_names(window, cx);
21771            self.buffer.update(cx, |buffer, cx| {
21772                buffer.finalize_last_transaction(cx);
21773                if self.leader_id.is_none() {
21774                    buffer.set_active_selections(
21775                        &self.selections.disjoint_anchors_arc(),
21776                        self.selections.line_mode(),
21777                        self.cursor_shape,
21778                        cx,
21779                    );
21780                }
21781            });
21782        }
21783    }
21784
21785    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21786        cx.emit(EditorEvent::FocusedIn)
21787    }
21788
21789    fn handle_focus_out(
21790        &mut self,
21791        event: FocusOutEvent,
21792        _window: &mut Window,
21793        cx: &mut Context<Self>,
21794    ) {
21795        if event.blurred != self.focus_handle {
21796            self.last_focused_descendant = Some(event.blurred);
21797        }
21798        self.selection_drag_state = SelectionDragState::None;
21799        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21800    }
21801
21802    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21803        self.blink_manager.update(cx, BlinkManager::disable);
21804        self.buffer
21805            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21806
21807        if let Some(blame) = self.blame.as_ref() {
21808            blame.update(cx, GitBlame::blur)
21809        }
21810        if !self.hover_state.focused(window, cx) {
21811            hide_hover(self, cx);
21812        }
21813        if !self
21814            .context_menu
21815            .borrow()
21816            .as_ref()
21817            .is_some_and(|context_menu| context_menu.focused(window, cx))
21818        {
21819            self.hide_context_menu(window, cx);
21820        }
21821        self.take_active_edit_prediction(cx);
21822        cx.emit(EditorEvent::Blurred);
21823        cx.notify();
21824    }
21825
21826    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21827        let mut pending: String = window
21828            .pending_input_keystrokes()
21829            .into_iter()
21830            .flatten()
21831            .filter_map(|keystroke| {
21832                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21833                    keystroke.key_char.clone()
21834                } else {
21835                    None
21836                }
21837            })
21838            .collect();
21839
21840        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21841            pending = "".to_string();
21842        }
21843
21844        let existing_pending = self
21845            .text_highlights::<PendingInput>(cx)
21846            .map(|(_, ranges)| ranges.to_vec());
21847        if existing_pending.is_none() && pending.is_empty() {
21848            return;
21849        }
21850        let transaction =
21851            self.transact(window, cx, |this, window, cx| {
21852                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
21853                let edits = selections
21854                    .iter()
21855                    .map(|selection| (selection.end..selection.end, pending.clone()));
21856                this.edit(edits, cx);
21857                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21858                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21859                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21860                    }));
21861                });
21862                if let Some(existing_ranges) = existing_pending {
21863                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21864                    this.edit(edits, cx);
21865                }
21866            });
21867
21868        let snapshot = self.snapshot(window, cx);
21869        let ranges = self
21870            .selections
21871            .all::<usize>(&snapshot.display_snapshot)
21872            .into_iter()
21873            .map(|selection| {
21874                snapshot.buffer_snapshot().anchor_after(selection.end)
21875                    ..snapshot
21876                        .buffer_snapshot()
21877                        .anchor_before(selection.end + pending.len())
21878            })
21879            .collect();
21880
21881        if pending.is_empty() {
21882            self.clear_highlights::<PendingInput>(cx);
21883        } else {
21884            self.highlight_text::<PendingInput>(
21885                ranges,
21886                HighlightStyle {
21887                    underline: Some(UnderlineStyle {
21888                        thickness: px(1.),
21889                        color: None,
21890                        wavy: false,
21891                    }),
21892                    ..Default::default()
21893                },
21894                cx,
21895            );
21896        }
21897
21898        self.ime_transaction = self.ime_transaction.or(transaction);
21899        if let Some(transaction) = self.ime_transaction {
21900            self.buffer.update(cx, |buffer, cx| {
21901                buffer.group_until_transaction(transaction, cx);
21902            });
21903        }
21904
21905        if self.text_highlights::<PendingInput>(cx).is_none() {
21906            self.ime_transaction.take();
21907        }
21908    }
21909
21910    pub fn register_action_renderer(
21911        &mut self,
21912        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21913    ) -> Subscription {
21914        let id = self.next_editor_action_id.post_inc();
21915        self.editor_actions
21916            .borrow_mut()
21917            .insert(id, Box::new(listener));
21918
21919        let editor_actions = self.editor_actions.clone();
21920        Subscription::new(move || {
21921            editor_actions.borrow_mut().remove(&id);
21922        })
21923    }
21924
21925    pub fn register_action<A: Action>(
21926        &mut self,
21927        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21928    ) -> Subscription {
21929        let id = self.next_editor_action_id.post_inc();
21930        let listener = Arc::new(listener);
21931        self.editor_actions.borrow_mut().insert(
21932            id,
21933            Box::new(move |_, window, _| {
21934                let listener = listener.clone();
21935                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21936                    let action = action.downcast_ref().unwrap();
21937                    if phase == DispatchPhase::Bubble {
21938                        listener(action, window, cx)
21939                    }
21940                })
21941            }),
21942        );
21943
21944        let editor_actions = self.editor_actions.clone();
21945        Subscription::new(move || {
21946            editor_actions.borrow_mut().remove(&id);
21947        })
21948    }
21949
21950    pub fn file_header_size(&self) -> u32 {
21951        FILE_HEADER_HEIGHT
21952    }
21953
21954    pub fn restore(
21955        &mut self,
21956        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21957        window: &mut Window,
21958        cx: &mut Context<Self>,
21959    ) {
21960        let workspace = self.workspace();
21961        let project = self.project();
21962        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21963            let mut tasks = Vec::new();
21964            for (buffer_id, changes) in revert_changes {
21965                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21966                    buffer.update(cx, |buffer, cx| {
21967                        buffer.edit(
21968                            changes
21969                                .into_iter()
21970                                .map(|(range, text)| (range, text.to_string())),
21971                            None,
21972                            cx,
21973                        );
21974                    });
21975
21976                    if let Some(project) =
21977                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21978                    {
21979                        project.update(cx, |project, cx| {
21980                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21981                        })
21982                    }
21983                }
21984            }
21985            tasks
21986        });
21987        cx.spawn_in(window, async move |_, cx| {
21988            for (buffer, task) in save_tasks {
21989                let result = task.await;
21990                if result.is_err() {
21991                    let Some(path) = buffer
21992                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21993                        .ok()
21994                    else {
21995                        continue;
21996                    };
21997                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21998                        let Some(task) = cx
21999                            .update_window_entity(workspace, |workspace, window, cx| {
22000                                workspace
22001                                    .open_path_preview(path, None, false, false, false, window, cx)
22002                            })
22003                            .ok()
22004                        else {
22005                            continue;
22006                        };
22007                        task.await.log_err();
22008                    }
22009                }
22010            }
22011        })
22012        .detach();
22013        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22014            selections.refresh()
22015        });
22016    }
22017
22018    pub fn to_pixel_point(
22019        &self,
22020        source: multi_buffer::Anchor,
22021        editor_snapshot: &EditorSnapshot,
22022        window: &mut Window,
22023    ) -> Option<gpui::Point<Pixels>> {
22024        let source_point = source.to_display_point(editor_snapshot);
22025        self.display_to_pixel_point(source_point, editor_snapshot, window)
22026    }
22027
22028    pub fn display_to_pixel_point(
22029        &self,
22030        source: DisplayPoint,
22031        editor_snapshot: &EditorSnapshot,
22032        window: &mut Window,
22033    ) -> Option<gpui::Point<Pixels>> {
22034        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
22035        let text_layout_details = self.text_layout_details(window);
22036        let scroll_top = text_layout_details
22037            .scroll_anchor
22038            .scroll_position(editor_snapshot)
22039            .y;
22040
22041        if source.row().as_f64() < scroll_top.floor() {
22042            return None;
22043        }
22044        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
22045        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
22046        Some(gpui::Point::new(source_x, source_y))
22047    }
22048
22049    pub fn has_visible_completions_menu(&self) -> bool {
22050        !self.edit_prediction_preview_is_active()
22051            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
22052                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
22053            })
22054    }
22055
22056    pub fn register_addon<T: Addon>(&mut self, instance: T) {
22057        if self.mode.is_minimap() {
22058            return;
22059        }
22060        self.addons
22061            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
22062    }
22063
22064    pub fn unregister_addon<T: Addon>(&mut self) {
22065        self.addons.remove(&std::any::TypeId::of::<T>());
22066    }
22067
22068    pub fn addon<T: Addon>(&self) -> Option<&T> {
22069        let type_id = std::any::TypeId::of::<T>();
22070        self.addons
22071            .get(&type_id)
22072            .and_then(|item| item.to_any().downcast_ref::<T>())
22073    }
22074
22075    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
22076        let type_id = std::any::TypeId::of::<T>();
22077        self.addons
22078            .get_mut(&type_id)
22079            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
22080    }
22081
22082    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
22083        let text_layout_details = self.text_layout_details(window);
22084        let style = &text_layout_details.editor_style;
22085        let font_id = window.text_system().resolve_font(&style.text.font());
22086        let font_size = style.text.font_size.to_pixels(window.rem_size());
22087        let line_height = style.text.line_height_in_pixels(window.rem_size());
22088        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
22089        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
22090
22091        CharacterDimensions {
22092            em_width,
22093            em_advance,
22094            line_height,
22095        }
22096    }
22097
22098    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
22099        self.load_diff_task.clone()
22100    }
22101
22102    fn read_metadata_from_db(
22103        &mut self,
22104        item_id: u64,
22105        workspace_id: WorkspaceId,
22106        window: &mut Window,
22107        cx: &mut Context<Editor>,
22108    ) {
22109        if self.buffer_kind(cx) == ItemBufferKind::Singleton
22110            && !self.mode.is_minimap()
22111            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
22112        {
22113            let buffer_snapshot = OnceCell::new();
22114
22115            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
22116                && !folds.is_empty()
22117            {
22118                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22119                self.fold_ranges(
22120                    folds
22121                        .into_iter()
22122                        .map(|(start, end)| {
22123                            snapshot.clip_offset(start, Bias::Left)
22124                                ..snapshot.clip_offset(end, Bias::Right)
22125                        })
22126                        .collect(),
22127                    false,
22128                    window,
22129                    cx,
22130                );
22131            }
22132
22133            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
22134                && !selections.is_empty()
22135            {
22136                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22137                // skip adding the initial selection to selection history
22138                self.selection_history.mode = SelectionHistoryMode::Skipping;
22139                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22140                    s.select_ranges(selections.into_iter().map(|(start, end)| {
22141                        snapshot.clip_offset(start, Bias::Left)
22142                            ..snapshot.clip_offset(end, Bias::Right)
22143                    }));
22144                });
22145                self.selection_history.mode = SelectionHistoryMode::Normal;
22146            };
22147        }
22148
22149        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22150    }
22151
22152    fn update_lsp_data(
22153        &mut self,
22154        for_buffer: Option<BufferId>,
22155        window: &mut Window,
22156        cx: &mut Context<'_, Self>,
22157    ) {
22158        self.pull_diagnostics(for_buffer, window, cx);
22159        self.refresh_colors_for_visible_range(for_buffer, window, cx);
22160    }
22161
22162    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
22163        if self.ignore_lsp_data() {
22164            return;
22165        }
22166        for (_, (visible_buffer, _, _)) in self.visible_excerpts(cx) {
22167            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
22168        }
22169    }
22170
22171    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
22172        if !self.registered_buffers.contains_key(&buffer_id)
22173            && let Some(project) = self.project.as_ref()
22174        {
22175            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
22176                project.update(cx, |project, cx| {
22177                    self.registered_buffers.insert(
22178                        buffer_id,
22179                        project.register_buffer_with_language_servers(&buffer, cx),
22180                    );
22181                });
22182            } else {
22183                self.registered_buffers.remove(&buffer_id);
22184            }
22185        }
22186    }
22187
22188    fn ignore_lsp_data(&self) -> bool {
22189        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
22190        // skip any LSP updates for it.
22191        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
22192    }
22193}
22194
22195fn edit_for_markdown_paste<'a>(
22196    buffer: &MultiBufferSnapshot,
22197    range: Range<usize>,
22198    to_insert: &'a str,
22199    url: Option<url::Url>,
22200) -> (Range<usize>, Cow<'a, str>) {
22201    if url.is_none() {
22202        return (range, Cow::Borrowed(to_insert));
22203    };
22204
22205    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22206
22207    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22208        Cow::Borrowed(to_insert)
22209    } else {
22210        Cow::Owned(format!("[{old_text}]({to_insert})"))
22211    };
22212    (range, new_text)
22213}
22214
22215#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
22216pub enum VimFlavor {
22217    Vim,
22218    Helix,
22219}
22220
22221pub fn vim_flavor(cx: &App) -> Option<VimFlavor> {
22222    if vim_mode_setting::HelixModeSetting::try_get(cx)
22223        .map(|helix_mode| helix_mode.0)
22224        .unwrap_or(false)
22225    {
22226        Some(VimFlavor::Helix)
22227    } else if vim_mode_setting::VimModeSetting::try_get(cx)
22228        .map(|vim_mode| vim_mode.0)
22229        .unwrap_or(false)
22230    {
22231        Some(VimFlavor::Vim)
22232    } else {
22233        None // neither vim nor helix mode
22234    }
22235}
22236
22237fn process_completion_for_edit(
22238    completion: &Completion,
22239    intent: CompletionIntent,
22240    buffer: &Entity<Buffer>,
22241    cursor_position: &text::Anchor,
22242    cx: &mut Context<Editor>,
22243) -> CompletionEdit {
22244    let buffer = buffer.read(cx);
22245    let buffer_snapshot = buffer.snapshot();
22246    let (snippet, new_text) = if completion.is_snippet() {
22247        let mut snippet_source = completion.new_text.clone();
22248        // Workaround for typescript language server issues so that methods don't expand within
22249        // strings and functions with type expressions. The previous point is used because the query
22250        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22251        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22252        let previous_point = if previous_point.column > 0 {
22253            cursor_position.to_previous_offset(&buffer_snapshot)
22254        } else {
22255            cursor_position.to_offset(&buffer_snapshot)
22256        };
22257        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22258            && scope.prefers_label_for_snippet_in_completion()
22259            && let Some(label) = completion.label()
22260            && matches!(
22261                completion.kind(),
22262                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22263            )
22264        {
22265            snippet_source = label;
22266        }
22267        match Snippet::parse(&snippet_source).log_err() {
22268            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22269            None => (None, completion.new_text.clone()),
22270        }
22271    } else {
22272        (None, completion.new_text.clone())
22273    };
22274
22275    let mut range_to_replace = {
22276        let replace_range = &completion.replace_range;
22277        if let CompletionSource::Lsp {
22278            insert_range: Some(insert_range),
22279            ..
22280        } = &completion.source
22281        {
22282            debug_assert_eq!(
22283                insert_range.start, replace_range.start,
22284                "insert_range and replace_range should start at the same position"
22285            );
22286            debug_assert!(
22287                insert_range
22288                    .start
22289                    .cmp(cursor_position, &buffer_snapshot)
22290                    .is_le(),
22291                "insert_range should start before or at cursor position"
22292            );
22293            debug_assert!(
22294                replace_range
22295                    .start
22296                    .cmp(cursor_position, &buffer_snapshot)
22297                    .is_le(),
22298                "replace_range should start before or at cursor position"
22299            );
22300
22301            let should_replace = match intent {
22302                CompletionIntent::CompleteWithInsert => false,
22303                CompletionIntent::CompleteWithReplace => true,
22304                CompletionIntent::Complete | CompletionIntent::Compose => {
22305                    let insert_mode =
22306                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22307                            .completions
22308                            .lsp_insert_mode;
22309                    match insert_mode {
22310                        LspInsertMode::Insert => false,
22311                        LspInsertMode::Replace => true,
22312                        LspInsertMode::ReplaceSubsequence => {
22313                            let mut text_to_replace = buffer.chars_for_range(
22314                                buffer.anchor_before(replace_range.start)
22315                                    ..buffer.anchor_after(replace_range.end),
22316                            );
22317                            let mut current_needle = text_to_replace.next();
22318                            for haystack_ch in completion.label.text.chars() {
22319                                if let Some(needle_ch) = current_needle
22320                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22321                                {
22322                                    current_needle = text_to_replace.next();
22323                                }
22324                            }
22325                            current_needle.is_none()
22326                        }
22327                        LspInsertMode::ReplaceSuffix => {
22328                            if replace_range
22329                                .end
22330                                .cmp(cursor_position, &buffer_snapshot)
22331                                .is_gt()
22332                            {
22333                                let range_after_cursor = *cursor_position..replace_range.end;
22334                                let text_after_cursor = buffer
22335                                    .text_for_range(
22336                                        buffer.anchor_before(range_after_cursor.start)
22337                                            ..buffer.anchor_after(range_after_cursor.end),
22338                                    )
22339                                    .collect::<String>()
22340                                    .to_ascii_lowercase();
22341                                completion
22342                                    .label
22343                                    .text
22344                                    .to_ascii_lowercase()
22345                                    .ends_with(&text_after_cursor)
22346                            } else {
22347                                true
22348                            }
22349                        }
22350                    }
22351                }
22352            };
22353
22354            if should_replace {
22355                replace_range.clone()
22356            } else {
22357                insert_range.clone()
22358            }
22359        } else {
22360            replace_range.clone()
22361        }
22362    };
22363
22364    if range_to_replace
22365        .end
22366        .cmp(cursor_position, &buffer_snapshot)
22367        .is_lt()
22368    {
22369        range_to_replace.end = *cursor_position;
22370    }
22371
22372    CompletionEdit {
22373        new_text,
22374        replace_range: range_to_replace.to_offset(buffer),
22375        snippet,
22376    }
22377}
22378
22379struct CompletionEdit {
22380    new_text: String,
22381    replace_range: Range<usize>,
22382    snippet: Option<Snippet>,
22383}
22384
22385fn insert_extra_newline_brackets(
22386    buffer: &MultiBufferSnapshot,
22387    range: Range<usize>,
22388    language: &language::LanguageScope,
22389) -> bool {
22390    let leading_whitespace_len = buffer
22391        .reversed_chars_at(range.start)
22392        .take_while(|c| c.is_whitespace() && *c != '\n')
22393        .map(|c| c.len_utf8())
22394        .sum::<usize>();
22395    let trailing_whitespace_len = buffer
22396        .chars_at(range.end)
22397        .take_while(|c| c.is_whitespace() && *c != '\n')
22398        .map(|c| c.len_utf8())
22399        .sum::<usize>();
22400    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22401
22402    language.brackets().any(|(pair, enabled)| {
22403        let pair_start = pair.start.trim_end();
22404        let pair_end = pair.end.trim_start();
22405
22406        enabled
22407            && pair.newline
22408            && buffer.contains_str_at(range.end, pair_end)
22409            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22410    })
22411}
22412
22413fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22414    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22415        [(buffer, range, _)] => (*buffer, range.clone()),
22416        _ => return false,
22417    };
22418    let pair = {
22419        let mut result: Option<BracketMatch> = None;
22420
22421        for pair in buffer
22422            .all_bracket_ranges(range.clone())
22423            .filter(move |pair| {
22424                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22425            })
22426        {
22427            let len = pair.close_range.end - pair.open_range.start;
22428
22429            if let Some(existing) = &result {
22430                let existing_len = existing.close_range.end - existing.open_range.start;
22431                if len > existing_len {
22432                    continue;
22433                }
22434            }
22435
22436            result = Some(pair);
22437        }
22438
22439        result
22440    };
22441    let Some(pair) = pair else {
22442        return false;
22443    };
22444    pair.newline_only
22445        && buffer
22446            .chars_for_range(pair.open_range.end..range.start)
22447            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22448            .all(|c| c.is_whitespace() && c != '\n')
22449}
22450
22451fn update_uncommitted_diff_for_buffer(
22452    editor: Entity<Editor>,
22453    project: &Entity<Project>,
22454    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22455    buffer: Entity<MultiBuffer>,
22456    cx: &mut App,
22457) -> Task<()> {
22458    let mut tasks = Vec::new();
22459    project.update(cx, |project, cx| {
22460        for buffer in buffers {
22461            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22462                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22463            }
22464        }
22465    });
22466    cx.spawn(async move |cx| {
22467        let diffs = future::join_all(tasks).await;
22468        if editor
22469            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22470            .unwrap_or(false)
22471        {
22472            return;
22473        }
22474
22475        buffer
22476            .update(cx, |buffer, cx| {
22477                for diff in diffs.into_iter().flatten() {
22478                    buffer.add_diff(diff, cx);
22479                }
22480            })
22481            .ok();
22482    })
22483}
22484
22485fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22486    let tab_size = tab_size.get() as usize;
22487    let mut width = offset;
22488
22489    for ch in text.chars() {
22490        width += if ch == '\t' {
22491            tab_size - (width % tab_size)
22492        } else {
22493            1
22494        };
22495    }
22496
22497    width - offset
22498}
22499
22500#[cfg(test)]
22501mod tests {
22502    use super::*;
22503
22504    #[test]
22505    fn test_string_size_with_expanded_tabs() {
22506        let nz = |val| NonZeroU32::new(val).unwrap();
22507        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22508        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22509        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22510        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22511        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22512        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22513        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22514        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22515    }
22516}
22517
22518/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22519struct WordBreakingTokenizer<'a> {
22520    input: &'a str,
22521}
22522
22523impl<'a> WordBreakingTokenizer<'a> {
22524    fn new(input: &'a str) -> Self {
22525        Self { input }
22526    }
22527}
22528
22529fn is_char_ideographic(ch: char) -> bool {
22530    use unicode_script::Script::*;
22531    use unicode_script::UnicodeScript;
22532    matches!(ch.script(), Han | Tangut | Yi)
22533}
22534
22535fn is_grapheme_ideographic(text: &str) -> bool {
22536    text.chars().any(is_char_ideographic)
22537}
22538
22539fn is_grapheme_whitespace(text: &str) -> bool {
22540    text.chars().any(|x| x.is_whitespace())
22541}
22542
22543fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22544    text.chars()
22545        .next()
22546        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22547}
22548
22549#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22550enum WordBreakToken<'a> {
22551    Word { token: &'a str, grapheme_len: usize },
22552    InlineWhitespace { token: &'a str, grapheme_len: usize },
22553    Newline,
22554}
22555
22556impl<'a> Iterator for WordBreakingTokenizer<'a> {
22557    /// Yields a span, the count of graphemes in the token, and whether it was
22558    /// whitespace. Note that it also breaks at word boundaries.
22559    type Item = WordBreakToken<'a>;
22560
22561    fn next(&mut self) -> Option<Self::Item> {
22562        use unicode_segmentation::UnicodeSegmentation;
22563        if self.input.is_empty() {
22564            return None;
22565        }
22566
22567        let mut iter = self.input.graphemes(true).peekable();
22568        let mut offset = 0;
22569        let mut grapheme_len = 0;
22570        if let Some(first_grapheme) = iter.next() {
22571            let is_newline = first_grapheme == "\n";
22572            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22573            offset += first_grapheme.len();
22574            grapheme_len += 1;
22575            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22576                if let Some(grapheme) = iter.peek().copied()
22577                    && should_stay_with_preceding_ideograph(grapheme)
22578                {
22579                    offset += grapheme.len();
22580                    grapheme_len += 1;
22581                }
22582            } else {
22583                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22584                let mut next_word_bound = words.peek().copied();
22585                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22586                    next_word_bound = words.next();
22587                }
22588                while let Some(grapheme) = iter.peek().copied() {
22589                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22590                        break;
22591                    };
22592                    if is_grapheme_whitespace(grapheme) != is_whitespace
22593                        || (grapheme == "\n") != is_newline
22594                    {
22595                        break;
22596                    };
22597                    offset += grapheme.len();
22598                    grapheme_len += 1;
22599                    iter.next();
22600                }
22601            }
22602            let token = &self.input[..offset];
22603            self.input = &self.input[offset..];
22604            if token == "\n" {
22605                Some(WordBreakToken::Newline)
22606            } else if is_whitespace {
22607                Some(WordBreakToken::InlineWhitespace {
22608                    token,
22609                    grapheme_len,
22610                })
22611            } else {
22612                Some(WordBreakToken::Word {
22613                    token,
22614                    grapheme_len,
22615                })
22616            }
22617        } else {
22618            None
22619        }
22620    }
22621}
22622
22623#[test]
22624fn test_word_breaking_tokenizer() {
22625    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22626        ("", &[]),
22627        ("  ", &[whitespace("  ", 2)]),
22628        ("Ʒ", &[word("Ʒ", 1)]),
22629        ("Ǽ", &[word("Ǽ", 1)]),
22630        ("", &[word("", 1)]),
22631        ("⋑⋑", &[word("⋑⋑", 2)]),
22632        (
22633            "原理,进而",
22634            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22635        ),
22636        (
22637            "hello world",
22638            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22639        ),
22640        (
22641            "hello, world",
22642            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22643        ),
22644        (
22645            "  hello world",
22646            &[
22647                whitespace("  ", 2),
22648                word("hello", 5),
22649                whitespace(" ", 1),
22650                word("world", 5),
22651            ],
22652        ),
22653        (
22654            "这是什么 \n 钢笔",
22655            &[
22656                word("", 1),
22657                word("", 1),
22658                word("", 1),
22659                word("", 1),
22660                whitespace(" ", 1),
22661                newline(),
22662                whitespace(" ", 1),
22663                word("", 1),
22664                word("", 1),
22665            ],
22666        ),
22667        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22668    ];
22669
22670    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22671        WordBreakToken::Word {
22672            token,
22673            grapheme_len,
22674        }
22675    }
22676
22677    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22678        WordBreakToken::InlineWhitespace {
22679            token,
22680            grapheme_len,
22681        }
22682    }
22683
22684    fn newline() -> WordBreakToken<'static> {
22685        WordBreakToken::Newline
22686    }
22687
22688    for (input, result) in tests {
22689        assert_eq!(
22690            WordBreakingTokenizer::new(input)
22691                .collect::<Vec<_>>()
22692                .as_slice(),
22693            *result,
22694        );
22695    }
22696}
22697
22698fn wrap_with_prefix(
22699    first_line_prefix: String,
22700    subsequent_lines_prefix: String,
22701    unwrapped_text: String,
22702    wrap_column: usize,
22703    tab_size: NonZeroU32,
22704    preserve_existing_whitespace: bool,
22705) -> String {
22706    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22707    let subsequent_lines_prefix_len =
22708        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22709    let mut wrapped_text = String::new();
22710    let mut current_line = first_line_prefix;
22711    let mut is_first_line = true;
22712
22713    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22714    let mut current_line_len = first_line_prefix_len;
22715    let mut in_whitespace = false;
22716    for token in tokenizer {
22717        let have_preceding_whitespace = in_whitespace;
22718        match token {
22719            WordBreakToken::Word {
22720                token,
22721                grapheme_len,
22722            } => {
22723                in_whitespace = false;
22724                let current_prefix_len = if is_first_line {
22725                    first_line_prefix_len
22726                } else {
22727                    subsequent_lines_prefix_len
22728                };
22729                if current_line_len + grapheme_len > wrap_column
22730                    && current_line_len != current_prefix_len
22731                {
22732                    wrapped_text.push_str(current_line.trim_end());
22733                    wrapped_text.push('\n');
22734                    is_first_line = false;
22735                    current_line = subsequent_lines_prefix.clone();
22736                    current_line_len = subsequent_lines_prefix_len;
22737                }
22738                current_line.push_str(token);
22739                current_line_len += grapheme_len;
22740            }
22741            WordBreakToken::InlineWhitespace {
22742                mut token,
22743                mut grapheme_len,
22744            } => {
22745                in_whitespace = true;
22746                if have_preceding_whitespace && !preserve_existing_whitespace {
22747                    continue;
22748                }
22749                if !preserve_existing_whitespace {
22750                    // Keep a single whitespace grapheme as-is
22751                    if let Some(first) =
22752                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
22753                    {
22754                        token = first;
22755                    } else {
22756                        token = " ";
22757                    }
22758                    grapheme_len = 1;
22759                }
22760                let current_prefix_len = if is_first_line {
22761                    first_line_prefix_len
22762                } else {
22763                    subsequent_lines_prefix_len
22764                };
22765                if current_line_len + grapheme_len > wrap_column {
22766                    wrapped_text.push_str(current_line.trim_end());
22767                    wrapped_text.push('\n');
22768                    is_first_line = false;
22769                    current_line = subsequent_lines_prefix.clone();
22770                    current_line_len = subsequent_lines_prefix_len;
22771                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22772                    current_line.push_str(token);
22773                    current_line_len += grapheme_len;
22774                }
22775            }
22776            WordBreakToken::Newline => {
22777                in_whitespace = true;
22778                let current_prefix_len = if is_first_line {
22779                    first_line_prefix_len
22780                } else {
22781                    subsequent_lines_prefix_len
22782                };
22783                if preserve_existing_whitespace {
22784                    wrapped_text.push_str(current_line.trim_end());
22785                    wrapped_text.push('\n');
22786                    is_first_line = false;
22787                    current_line = subsequent_lines_prefix.clone();
22788                    current_line_len = subsequent_lines_prefix_len;
22789                } else if have_preceding_whitespace {
22790                    continue;
22791                } else if current_line_len + 1 > wrap_column
22792                    && current_line_len != current_prefix_len
22793                {
22794                    wrapped_text.push_str(current_line.trim_end());
22795                    wrapped_text.push('\n');
22796                    is_first_line = false;
22797                    current_line = subsequent_lines_prefix.clone();
22798                    current_line_len = subsequent_lines_prefix_len;
22799                } else if current_line_len != current_prefix_len {
22800                    current_line.push(' ');
22801                    current_line_len += 1;
22802                }
22803            }
22804        }
22805    }
22806
22807    if !current_line.is_empty() {
22808        wrapped_text.push_str(&current_line);
22809    }
22810    wrapped_text
22811}
22812
22813#[test]
22814fn test_wrap_with_prefix() {
22815    assert_eq!(
22816        wrap_with_prefix(
22817            "# ".to_string(),
22818            "# ".to_string(),
22819            "abcdefg".to_string(),
22820            4,
22821            NonZeroU32::new(4).unwrap(),
22822            false,
22823        ),
22824        "# abcdefg"
22825    );
22826    assert_eq!(
22827        wrap_with_prefix(
22828            "".to_string(),
22829            "".to_string(),
22830            "\thello world".to_string(),
22831            8,
22832            NonZeroU32::new(4).unwrap(),
22833            false,
22834        ),
22835        "hello\nworld"
22836    );
22837    assert_eq!(
22838        wrap_with_prefix(
22839            "// ".to_string(),
22840            "// ".to_string(),
22841            "xx \nyy zz aa bb cc".to_string(),
22842            12,
22843            NonZeroU32::new(4).unwrap(),
22844            false,
22845        ),
22846        "// xx yy zz\n// aa bb cc"
22847    );
22848    assert_eq!(
22849        wrap_with_prefix(
22850            String::new(),
22851            String::new(),
22852            "这是什么 \n 钢笔".to_string(),
22853            3,
22854            NonZeroU32::new(4).unwrap(),
22855            false,
22856        ),
22857        "这是什\n么 钢\n"
22858    );
22859    assert_eq!(
22860        wrap_with_prefix(
22861            String::new(),
22862            String::new(),
22863            format!("foo{}bar", '\u{2009}'), // thin space
22864            80,
22865            NonZeroU32::new(4).unwrap(),
22866            false,
22867        ),
22868        format!("foo{}bar", '\u{2009}')
22869    );
22870}
22871
22872pub trait CollaborationHub {
22873    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22874    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22875    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22876}
22877
22878impl CollaborationHub for Entity<Project> {
22879    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22880        self.read(cx).collaborators()
22881    }
22882
22883    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22884        self.read(cx).user_store().read(cx).participant_indices()
22885    }
22886
22887    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22888        let this = self.read(cx);
22889        let user_ids = this.collaborators().values().map(|c| c.user_id);
22890        this.user_store().read(cx).participant_names(user_ids, cx)
22891    }
22892}
22893
22894pub trait SemanticsProvider {
22895    fn hover(
22896        &self,
22897        buffer: &Entity<Buffer>,
22898        position: text::Anchor,
22899        cx: &mut App,
22900    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22901
22902    fn inline_values(
22903        &self,
22904        buffer_handle: Entity<Buffer>,
22905        range: Range<text::Anchor>,
22906        cx: &mut App,
22907    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22908
22909    fn applicable_inlay_chunks(
22910        &self,
22911        buffer: &Entity<Buffer>,
22912        ranges: &[Range<text::Anchor>],
22913        cx: &mut App,
22914    ) -> Vec<Range<BufferRow>>;
22915
22916    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
22917
22918    fn inlay_hints(
22919        &self,
22920        invalidate: InvalidationStrategy,
22921        buffer: Entity<Buffer>,
22922        ranges: Vec<Range<text::Anchor>>,
22923        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
22924        cx: &mut App,
22925    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
22926
22927    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22928
22929    fn document_highlights(
22930        &self,
22931        buffer: &Entity<Buffer>,
22932        position: text::Anchor,
22933        cx: &mut App,
22934    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22935
22936    fn definitions(
22937        &self,
22938        buffer: &Entity<Buffer>,
22939        position: text::Anchor,
22940        kind: GotoDefinitionKind,
22941        cx: &mut App,
22942    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22943
22944    fn range_for_rename(
22945        &self,
22946        buffer: &Entity<Buffer>,
22947        position: text::Anchor,
22948        cx: &mut App,
22949    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22950
22951    fn perform_rename(
22952        &self,
22953        buffer: &Entity<Buffer>,
22954        position: text::Anchor,
22955        new_name: String,
22956        cx: &mut App,
22957    ) -> Option<Task<Result<ProjectTransaction>>>;
22958}
22959
22960pub trait CompletionProvider {
22961    fn completions(
22962        &self,
22963        excerpt_id: ExcerptId,
22964        buffer: &Entity<Buffer>,
22965        buffer_position: text::Anchor,
22966        trigger: CompletionContext,
22967        window: &mut Window,
22968        cx: &mut Context<Editor>,
22969    ) -> Task<Result<Vec<CompletionResponse>>>;
22970
22971    fn resolve_completions(
22972        &self,
22973        _buffer: Entity<Buffer>,
22974        _completion_indices: Vec<usize>,
22975        _completions: Rc<RefCell<Box<[Completion]>>>,
22976        _cx: &mut Context<Editor>,
22977    ) -> Task<Result<bool>> {
22978        Task::ready(Ok(false))
22979    }
22980
22981    fn apply_additional_edits_for_completion(
22982        &self,
22983        _buffer: Entity<Buffer>,
22984        _completions: Rc<RefCell<Box<[Completion]>>>,
22985        _completion_index: usize,
22986        _push_to_history: bool,
22987        _cx: &mut Context<Editor>,
22988    ) -> Task<Result<Option<language::Transaction>>> {
22989        Task::ready(Ok(None))
22990    }
22991
22992    fn is_completion_trigger(
22993        &self,
22994        buffer: &Entity<Buffer>,
22995        position: language::Anchor,
22996        text: &str,
22997        trigger_in_words: bool,
22998        menu_is_open: bool,
22999        cx: &mut Context<Editor>,
23000    ) -> bool;
23001
23002    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
23003
23004    fn sort_completions(&self) -> bool {
23005        true
23006    }
23007
23008    fn filter_completions(&self) -> bool {
23009        true
23010    }
23011}
23012
23013pub trait CodeActionProvider {
23014    fn id(&self) -> Arc<str>;
23015
23016    fn code_actions(
23017        &self,
23018        buffer: &Entity<Buffer>,
23019        range: Range<text::Anchor>,
23020        window: &mut Window,
23021        cx: &mut App,
23022    ) -> Task<Result<Vec<CodeAction>>>;
23023
23024    fn apply_code_action(
23025        &self,
23026        buffer_handle: Entity<Buffer>,
23027        action: CodeAction,
23028        excerpt_id: ExcerptId,
23029        push_to_history: bool,
23030        window: &mut Window,
23031        cx: &mut App,
23032    ) -> Task<Result<ProjectTransaction>>;
23033}
23034
23035impl CodeActionProvider for Entity<Project> {
23036    fn id(&self) -> Arc<str> {
23037        "project".into()
23038    }
23039
23040    fn code_actions(
23041        &self,
23042        buffer: &Entity<Buffer>,
23043        range: Range<text::Anchor>,
23044        _window: &mut Window,
23045        cx: &mut App,
23046    ) -> Task<Result<Vec<CodeAction>>> {
23047        self.update(cx, |project, cx| {
23048            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
23049            let code_actions = project.code_actions(buffer, range, None, cx);
23050            cx.background_spawn(async move {
23051                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
23052                Ok(code_lens_actions
23053                    .context("code lens fetch")?
23054                    .into_iter()
23055                    .flatten()
23056                    .chain(
23057                        code_actions
23058                            .context("code action fetch")?
23059                            .into_iter()
23060                            .flatten(),
23061                    )
23062                    .collect())
23063            })
23064        })
23065    }
23066
23067    fn apply_code_action(
23068        &self,
23069        buffer_handle: Entity<Buffer>,
23070        action: CodeAction,
23071        _excerpt_id: ExcerptId,
23072        push_to_history: bool,
23073        _window: &mut Window,
23074        cx: &mut App,
23075    ) -> Task<Result<ProjectTransaction>> {
23076        self.update(cx, |project, cx| {
23077            project.apply_code_action(buffer_handle, action, push_to_history, cx)
23078        })
23079    }
23080}
23081
23082fn snippet_completions(
23083    project: &Project,
23084    buffer: &Entity<Buffer>,
23085    buffer_position: text::Anchor,
23086    cx: &mut App,
23087) -> Task<Result<CompletionResponse>> {
23088    let languages = buffer.read(cx).languages_at(buffer_position);
23089    let snippet_store = project.snippets().read(cx);
23090
23091    let scopes: Vec<_> = languages
23092        .iter()
23093        .filter_map(|language| {
23094            let language_name = language.lsp_id();
23095            let snippets = snippet_store.snippets_for(Some(language_name), cx);
23096
23097            if snippets.is_empty() {
23098                None
23099            } else {
23100                Some((language.default_scope(), snippets))
23101            }
23102        })
23103        .collect();
23104
23105    if scopes.is_empty() {
23106        return Task::ready(Ok(CompletionResponse {
23107            completions: vec![],
23108            display_options: CompletionDisplayOptions::default(),
23109            is_incomplete: false,
23110        }));
23111    }
23112
23113    let snapshot = buffer.read(cx).text_snapshot();
23114    let executor = cx.background_executor().clone();
23115
23116    cx.background_spawn(async move {
23117        let mut is_incomplete = false;
23118        let mut completions: Vec<Completion> = Vec::new();
23119        for (scope, snippets) in scopes.into_iter() {
23120            let classifier =
23121                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
23122
23123            const MAX_WORD_PREFIX_LEN: usize = 128;
23124            let last_word: String = snapshot
23125                .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
23126                .take(MAX_WORD_PREFIX_LEN)
23127                .take_while(|c| classifier.is_word(*c))
23128                .collect::<String>()
23129                .chars()
23130                .rev()
23131                .collect();
23132
23133            if last_word.is_empty() {
23134                return Ok(CompletionResponse {
23135                    completions: vec![],
23136                    display_options: CompletionDisplayOptions::default(),
23137                    is_incomplete: true,
23138                });
23139            }
23140
23141            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
23142            let to_lsp = |point: &text::Anchor| {
23143                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
23144                point_to_lsp(end)
23145            };
23146            let lsp_end = to_lsp(&buffer_position);
23147
23148            let candidates = snippets
23149                .iter()
23150                .enumerate()
23151                .flat_map(|(ix, snippet)| {
23152                    snippet
23153                        .prefix
23154                        .iter()
23155                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
23156                })
23157                .collect::<Vec<StringMatchCandidate>>();
23158
23159            const MAX_RESULTS: usize = 100;
23160            let mut matches = fuzzy::match_strings(
23161                &candidates,
23162                &last_word,
23163                last_word.chars().any(|c| c.is_uppercase()),
23164                true,
23165                MAX_RESULTS,
23166                &Default::default(),
23167                executor.clone(),
23168            )
23169            .await;
23170
23171            if matches.len() >= MAX_RESULTS {
23172                is_incomplete = true;
23173            }
23174
23175            // Remove all candidates where the query's start does not match the start of any word in the candidate
23176            if let Some(query_start) = last_word.chars().next() {
23177                matches.retain(|string_match| {
23178                    split_words(&string_match.string).any(|word| {
23179                        // Check that the first codepoint of the word as lowercase matches the first
23180                        // codepoint of the query as lowercase
23181                        word.chars()
23182                            .flat_map(|codepoint| codepoint.to_lowercase())
23183                            .zip(query_start.to_lowercase())
23184                            .all(|(word_cp, query_cp)| word_cp == query_cp)
23185                    })
23186                });
23187            }
23188
23189            let matched_strings = matches
23190                .into_iter()
23191                .map(|m| m.string)
23192                .collect::<HashSet<_>>();
23193
23194            completions.extend(snippets.iter().filter_map(|snippet| {
23195                let matching_prefix = snippet
23196                    .prefix
23197                    .iter()
23198                    .find(|prefix| matched_strings.contains(*prefix))?;
23199                let start = as_offset - last_word.len();
23200                let start = snapshot.anchor_before(start);
23201                let range = start..buffer_position;
23202                let lsp_start = to_lsp(&start);
23203                let lsp_range = lsp::Range {
23204                    start: lsp_start,
23205                    end: lsp_end,
23206                };
23207                Some(Completion {
23208                    replace_range: range,
23209                    new_text: snippet.body.clone(),
23210                    source: CompletionSource::Lsp {
23211                        insert_range: None,
23212                        server_id: LanguageServerId(usize::MAX),
23213                        resolved: true,
23214                        lsp_completion: Box::new(lsp::CompletionItem {
23215                            label: snippet.prefix.first().unwrap().clone(),
23216                            kind: Some(CompletionItemKind::SNIPPET),
23217                            label_details: snippet.description.as_ref().map(|description| {
23218                                lsp::CompletionItemLabelDetails {
23219                                    detail: Some(description.clone()),
23220                                    description: None,
23221                                }
23222                            }),
23223                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23224                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23225                                lsp::InsertReplaceEdit {
23226                                    new_text: snippet.body.clone(),
23227                                    insert: lsp_range,
23228                                    replace: lsp_range,
23229                                },
23230                            )),
23231                            filter_text: Some(snippet.body.clone()),
23232                            sort_text: Some(char::MAX.to_string()),
23233                            ..lsp::CompletionItem::default()
23234                        }),
23235                        lsp_defaults: None,
23236                    },
23237                    label: CodeLabel::plain(matching_prefix.clone(), None),
23238                    icon_path: None,
23239                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23240                        single_line: snippet.name.clone().into(),
23241                        plain_text: snippet
23242                            .description
23243                            .clone()
23244                            .map(|description| description.into()),
23245                    }),
23246                    insert_text_mode: None,
23247                    confirm: None,
23248                })
23249            }))
23250        }
23251
23252        Ok(CompletionResponse {
23253            completions,
23254            display_options: CompletionDisplayOptions::default(),
23255            is_incomplete,
23256        })
23257    })
23258}
23259
23260impl CompletionProvider for Entity<Project> {
23261    fn completions(
23262        &self,
23263        _excerpt_id: ExcerptId,
23264        buffer: &Entity<Buffer>,
23265        buffer_position: text::Anchor,
23266        options: CompletionContext,
23267        _window: &mut Window,
23268        cx: &mut Context<Editor>,
23269    ) -> Task<Result<Vec<CompletionResponse>>> {
23270        self.update(cx, |project, cx| {
23271            let snippets = snippet_completions(project, buffer, buffer_position, cx);
23272            let project_completions = project.completions(buffer, buffer_position, options, cx);
23273            cx.background_spawn(async move {
23274                let mut responses = project_completions.await?;
23275                let snippets = snippets.await?;
23276                if !snippets.completions.is_empty() {
23277                    responses.push(snippets);
23278                }
23279                Ok(responses)
23280            })
23281        })
23282    }
23283
23284    fn resolve_completions(
23285        &self,
23286        buffer: Entity<Buffer>,
23287        completion_indices: Vec<usize>,
23288        completions: Rc<RefCell<Box<[Completion]>>>,
23289        cx: &mut Context<Editor>,
23290    ) -> Task<Result<bool>> {
23291        self.update(cx, |project, cx| {
23292            project.lsp_store().update(cx, |lsp_store, cx| {
23293                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23294            })
23295        })
23296    }
23297
23298    fn apply_additional_edits_for_completion(
23299        &self,
23300        buffer: Entity<Buffer>,
23301        completions: Rc<RefCell<Box<[Completion]>>>,
23302        completion_index: usize,
23303        push_to_history: bool,
23304        cx: &mut Context<Editor>,
23305    ) -> Task<Result<Option<language::Transaction>>> {
23306        self.update(cx, |project, cx| {
23307            project.lsp_store().update(cx, |lsp_store, cx| {
23308                lsp_store.apply_additional_edits_for_completion(
23309                    buffer,
23310                    completions,
23311                    completion_index,
23312                    push_to_history,
23313                    cx,
23314                )
23315            })
23316        })
23317    }
23318
23319    fn is_completion_trigger(
23320        &self,
23321        buffer: &Entity<Buffer>,
23322        position: language::Anchor,
23323        text: &str,
23324        trigger_in_words: bool,
23325        menu_is_open: bool,
23326        cx: &mut Context<Editor>,
23327    ) -> bool {
23328        let mut chars = text.chars();
23329        let char = if let Some(char) = chars.next() {
23330            char
23331        } else {
23332            return false;
23333        };
23334        if chars.next().is_some() {
23335            return false;
23336        }
23337
23338        let buffer = buffer.read(cx);
23339        let snapshot = buffer.snapshot();
23340        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23341            return false;
23342        }
23343        let classifier = snapshot
23344            .char_classifier_at(position)
23345            .scope_context(Some(CharScopeContext::Completion));
23346        if trigger_in_words && classifier.is_word(char) {
23347            return true;
23348        }
23349
23350        buffer.completion_triggers().contains(text)
23351    }
23352}
23353
23354impl SemanticsProvider for Entity<Project> {
23355    fn hover(
23356        &self,
23357        buffer: &Entity<Buffer>,
23358        position: text::Anchor,
23359        cx: &mut App,
23360    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23361        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23362    }
23363
23364    fn document_highlights(
23365        &self,
23366        buffer: &Entity<Buffer>,
23367        position: text::Anchor,
23368        cx: &mut App,
23369    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23370        Some(self.update(cx, |project, cx| {
23371            project.document_highlights(buffer, position, cx)
23372        }))
23373    }
23374
23375    fn definitions(
23376        &self,
23377        buffer: &Entity<Buffer>,
23378        position: text::Anchor,
23379        kind: GotoDefinitionKind,
23380        cx: &mut App,
23381    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23382        Some(self.update(cx, |project, cx| match kind {
23383            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23384            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23385            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23386            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23387        }))
23388    }
23389
23390    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23391        self.update(cx, |project, cx| {
23392            if project
23393                .active_debug_session(cx)
23394                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23395            {
23396                return true;
23397            }
23398
23399            buffer.update(cx, |buffer, cx| {
23400                project.any_language_server_supports_inlay_hints(buffer, cx)
23401            })
23402        })
23403    }
23404
23405    fn inline_values(
23406        &self,
23407        buffer_handle: Entity<Buffer>,
23408        range: Range<text::Anchor>,
23409        cx: &mut App,
23410    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23411        self.update(cx, |project, cx| {
23412            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23413
23414            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23415        })
23416    }
23417
23418    fn applicable_inlay_chunks(
23419        &self,
23420        buffer: &Entity<Buffer>,
23421        ranges: &[Range<text::Anchor>],
23422        cx: &mut App,
23423    ) -> Vec<Range<BufferRow>> {
23424        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23425            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
23426        })
23427    }
23428
23429    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
23430        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
23431            lsp_store.invalidate_inlay_hints(for_buffers)
23432        });
23433    }
23434
23435    fn inlay_hints(
23436        &self,
23437        invalidate: InvalidationStrategy,
23438        buffer: Entity<Buffer>,
23439        ranges: Vec<Range<text::Anchor>>,
23440        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23441        cx: &mut App,
23442    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
23443        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23444            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
23445        }))
23446    }
23447
23448    fn range_for_rename(
23449        &self,
23450        buffer: &Entity<Buffer>,
23451        position: text::Anchor,
23452        cx: &mut App,
23453    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23454        Some(self.update(cx, |project, cx| {
23455            let buffer = buffer.clone();
23456            let task = project.prepare_rename(buffer.clone(), position, cx);
23457            cx.spawn(async move |_, cx| {
23458                Ok(match task.await? {
23459                    PrepareRenameResponse::Success(range) => Some(range),
23460                    PrepareRenameResponse::InvalidPosition => None,
23461                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23462                        // Fallback on using TreeSitter info to determine identifier range
23463                        buffer.read_with(cx, |buffer, _| {
23464                            let snapshot = buffer.snapshot();
23465                            let (range, kind) = snapshot.surrounding_word(position, None);
23466                            if kind != Some(CharKind::Word) {
23467                                return None;
23468                            }
23469                            Some(
23470                                snapshot.anchor_before(range.start)
23471                                    ..snapshot.anchor_after(range.end),
23472                            )
23473                        })?
23474                    }
23475                })
23476            })
23477        }))
23478    }
23479
23480    fn perform_rename(
23481        &self,
23482        buffer: &Entity<Buffer>,
23483        position: text::Anchor,
23484        new_name: String,
23485        cx: &mut App,
23486    ) -> Option<Task<Result<ProjectTransaction>>> {
23487        Some(self.update(cx, |project, cx| {
23488            project.perform_rename(buffer.clone(), position, new_name, cx)
23489        }))
23490    }
23491}
23492
23493fn consume_contiguous_rows(
23494    contiguous_row_selections: &mut Vec<Selection<Point>>,
23495    selection: &Selection<Point>,
23496    display_map: &DisplaySnapshot,
23497    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23498) -> (MultiBufferRow, MultiBufferRow) {
23499    contiguous_row_selections.push(selection.clone());
23500    let start_row = starting_row(selection, display_map);
23501    let mut end_row = ending_row(selection, display_map);
23502
23503    while let Some(next_selection) = selections.peek() {
23504        if next_selection.start.row <= end_row.0 {
23505            end_row = ending_row(next_selection, display_map);
23506            contiguous_row_selections.push(selections.next().unwrap().clone());
23507        } else {
23508            break;
23509        }
23510    }
23511    (start_row, end_row)
23512}
23513
23514fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23515    if selection.start.column > 0 {
23516        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23517    } else {
23518        MultiBufferRow(selection.start.row)
23519    }
23520}
23521
23522fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23523    if next_selection.end.column > 0 || next_selection.is_empty() {
23524        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23525    } else {
23526        MultiBufferRow(next_selection.end.row)
23527    }
23528}
23529
23530impl EditorSnapshot {
23531    pub fn remote_selections_in_range<'a>(
23532        &'a self,
23533        range: &'a Range<Anchor>,
23534        collaboration_hub: &dyn CollaborationHub,
23535        cx: &'a App,
23536    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23537        let participant_names = collaboration_hub.user_names(cx);
23538        let participant_indices = collaboration_hub.user_participant_indices(cx);
23539        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23540        let collaborators_by_replica_id = collaborators_by_peer_id
23541            .values()
23542            .map(|collaborator| (collaborator.replica_id, collaborator))
23543            .collect::<HashMap<_, _>>();
23544        self.buffer_snapshot()
23545            .selections_in_range(range, false)
23546            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23547                if replica_id == ReplicaId::AGENT {
23548                    Some(RemoteSelection {
23549                        replica_id,
23550                        selection,
23551                        cursor_shape,
23552                        line_mode,
23553                        collaborator_id: CollaboratorId::Agent,
23554                        user_name: Some("Agent".into()),
23555                        color: cx.theme().players().agent(),
23556                    })
23557                } else {
23558                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23559                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23560                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23561                    Some(RemoteSelection {
23562                        replica_id,
23563                        selection,
23564                        cursor_shape,
23565                        line_mode,
23566                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23567                        user_name,
23568                        color: if let Some(index) = participant_index {
23569                            cx.theme().players().color_for_participant(index.0)
23570                        } else {
23571                            cx.theme().players().absent()
23572                        },
23573                    })
23574                }
23575            })
23576    }
23577
23578    pub fn hunks_for_ranges(
23579        &self,
23580        ranges: impl IntoIterator<Item = Range<Point>>,
23581    ) -> Vec<MultiBufferDiffHunk> {
23582        let mut hunks = Vec::new();
23583        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23584            HashMap::default();
23585        for query_range in ranges {
23586            let query_rows =
23587                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23588            for hunk in self.buffer_snapshot().diff_hunks_in_range(
23589                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23590            ) {
23591                // Include deleted hunks that are adjacent to the query range, because
23592                // otherwise they would be missed.
23593                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23594                if hunk.status().is_deleted() {
23595                    intersects_range |= hunk.row_range.start == query_rows.end;
23596                    intersects_range |= hunk.row_range.end == query_rows.start;
23597                }
23598                if intersects_range {
23599                    if !processed_buffer_rows
23600                        .entry(hunk.buffer_id)
23601                        .or_default()
23602                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23603                    {
23604                        continue;
23605                    }
23606                    hunks.push(hunk);
23607                }
23608            }
23609        }
23610
23611        hunks
23612    }
23613
23614    fn display_diff_hunks_for_rows<'a>(
23615        &'a self,
23616        display_rows: Range<DisplayRow>,
23617        folded_buffers: &'a HashSet<BufferId>,
23618    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23619        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23620        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23621
23622        self.buffer_snapshot()
23623            .diff_hunks_in_range(buffer_start..buffer_end)
23624            .filter_map(|hunk| {
23625                if folded_buffers.contains(&hunk.buffer_id) {
23626                    return None;
23627                }
23628
23629                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23630                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23631
23632                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23633                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23634
23635                let display_hunk = if hunk_display_start.column() != 0 {
23636                    DisplayDiffHunk::Folded {
23637                        display_row: hunk_display_start.row(),
23638                    }
23639                } else {
23640                    let mut end_row = hunk_display_end.row();
23641                    if hunk_display_end.column() > 0 {
23642                        end_row.0 += 1;
23643                    }
23644                    let is_created_file = hunk.is_created_file();
23645                    DisplayDiffHunk::Unfolded {
23646                        status: hunk.status(),
23647                        diff_base_byte_range: hunk.diff_base_byte_range,
23648                        display_row_range: hunk_display_start.row()..end_row,
23649                        multi_buffer_range: Anchor::range_in_buffer(
23650                            hunk.excerpt_id,
23651                            hunk.buffer_id,
23652                            hunk.buffer_range,
23653                        ),
23654                        is_created_file,
23655                    }
23656                };
23657
23658                Some(display_hunk)
23659            })
23660    }
23661
23662    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23663        self.display_snapshot
23664            .buffer_snapshot()
23665            .language_at(position)
23666    }
23667
23668    pub fn is_focused(&self) -> bool {
23669        self.is_focused
23670    }
23671
23672    pub fn placeholder_text(&self) -> Option<String> {
23673        self.placeholder_display_snapshot
23674            .as_ref()
23675            .map(|display_map| display_map.text())
23676    }
23677
23678    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
23679        self.scroll_anchor.scroll_position(&self.display_snapshot)
23680    }
23681
23682    fn gutter_dimensions(
23683        &self,
23684        font_id: FontId,
23685        font_size: Pixels,
23686        max_line_number_width: Pixels,
23687        cx: &App,
23688    ) -> Option<GutterDimensions> {
23689        if !self.show_gutter {
23690            return None;
23691        }
23692
23693        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23694        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23695
23696        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23697            matches!(
23698                ProjectSettings::get_global(cx).git.git_gutter,
23699                GitGutterSetting::TrackedFiles
23700            )
23701        });
23702        let gutter_settings = EditorSettings::get_global(cx).gutter;
23703        let show_line_numbers = self
23704            .show_line_numbers
23705            .unwrap_or(gutter_settings.line_numbers);
23706        let line_gutter_width = if show_line_numbers {
23707            // Avoid flicker-like gutter resizes when the line number gains another digit by
23708            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23709            let min_width_for_number_on_gutter =
23710                ch_advance * gutter_settings.min_line_number_digits as f32;
23711            max_line_number_width.max(min_width_for_number_on_gutter)
23712        } else {
23713            0.0.into()
23714        };
23715
23716        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23717        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23718
23719        let git_blame_entries_width =
23720            self.git_blame_gutter_max_author_length
23721                .map(|max_author_length| {
23722                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23723                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23724
23725                    /// The number of characters to dedicate to gaps and margins.
23726                    const SPACING_WIDTH: usize = 4;
23727
23728                    let max_char_count = max_author_length.min(renderer.max_author_length())
23729                        + ::git::SHORT_SHA_LENGTH
23730                        + MAX_RELATIVE_TIMESTAMP.len()
23731                        + SPACING_WIDTH;
23732
23733                    ch_advance * max_char_count
23734                });
23735
23736        let is_singleton = self.buffer_snapshot().is_singleton();
23737
23738        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23739        left_padding += if !is_singleton {
23740            ch_width * 4.0
23741        } else if show_runnables || show_breakpoints {
23742            ch_width * 3.0
23743        } else if show_git_gutter && show_line_numbers {
23744            ch_width * 2.0
23745        } else if show_git_gutter || show_line_numbers {
23746            ch_width
23747        } else {
23748            px(0.)
23749        };
23750
23751        let shows_folds = is_singleton && gutter_settings.folds;
23752
23753        let right_padding = if shows_folds && show_line_numbers {
23754            ch_width * 4.0
23755        } else if shows_folds || (!is_singleton && show_line_numbers) {
23756            ch_width * 3.0
23757        } else if show_line_numbers {
23758            ch_width
23759        } else {
23760            px(0.)
23761        };
23762
23763        Some(GutterDimensions {
23764            left_padding,
23765            right_padding,
23766            width: line_gutter_width + left_padding + right_padding,
23767            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23768            git_blame_entries_width,
23769        })
23770    }
23771
23772    pub fn render_crease_toggle(
23773        &self,
23774        buffer_row: MultiBufferRow,
23775        row_contains_cursor: bool,
23776        editor: Entity<Editor>,
23777        window: &mut Window,
23778        cx: &mut App,
23779    ) -> Option<AnyElement> {
23780        let folded = self.is_line_folded(buffer_row);
23781        let mut is_foldable = false;
23782
23783        if let Some(crease) = self
23784            .crease_snapshot
23785            .query_row(buffer_row, self.buffer_snapshot())
23786        {
23787            is_foldable = true;
23788            match crease {
23789                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23790                    if let Some(render_toggle) = render_toggle {
23791                        let toggle_callback =
23792                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23793                                if folded {
23794                                    editor.update(cx, |editor, cx| {
23795                                        editor.fold_at(buffer_row, window, cx)
23796                                    });
23797                                } else {
23798                                    editor.update(cx, |editor, cx| {
23799                                        editor.unfold_at(buffer_row, window, cx)
23800                                    });
23801                                }
23802                            });
23803                        return Some((render_toggle)(
23804                            buffer_row,
23805                            folded,
23806                            toggle_callback,
23807                            window,
23808                            cx,
23809                        ));
23810                    }
23811                }
23812            }
23813        }
23814
23815        is_foldable |= self.starts_indent(buffer_row);
23816
23817        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23818            Some(
23819                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23820                    .toggle_state(folded)
23821                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23822                        if folded {
23823                            this.unfold_at(buffer_row, window, cx);
23824                        } else {
23825                            this.fold_at(buffer_row, window, cx);
23826                        }
23827                    }))
23828                    .into_any_element(),
23829            )
23830        } else {
23831            None
23832        }
23833    }
23834
23835    pub fn render_crease_trailer(
23836        &self,
23837        buffer_row: MultiBufferRow,
23838        window: &mut Window,
23839        cx: &mut App,
23840    ) -> Option<AnyElement> {
23841        let folded = self.is_line_folded(buffer_row);
23842        if let Crease::Inline { render_trailer, .. } = self
23843            .crease_snapshot
23844            .query_row(buffer_row, self.buffer_snapshot())?
23845        {
23846            let render_trailer = render_trailer.as_ref()?;
23847            Some(render_trailer(buffer_row, folded, window, cx))
23848        } else {
23849            None
23850        }
23851    }
23852}
23853
23854impl Deref for EditorSnapshot {
23855    type Target = DisplaySnapshot;
23856
23857    fn deref(&self) -> &Self::Target {
23858        &self.display_snapshot
23859    }
23860}
23861
23862#[derive(Clone, Debug, PartialEq, Eq)]
23863pub enum EditorEvent {
23864    InputIgnored {
23865        text: Arc<str>,
23866    },
23867    InputHandled {
23868        utf16_range_to_replace: Option<Range<isize>>,
23869        text: Arc<str>,
23870    },
23871    ExcerptsAdded {
23872        buffer: Entity<Buffer>,
23873        predecessor: ExcerptId,
23874        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23875    },
23876    ExcerptsRemoved {
23877        ids: Vec<ExcerptId>,
23878        removed_buffer_ids: Vec<BufferId>,
23879    },
23880    BufferFoldToggled {
23881        ids: Vec<ExcerptId>,
23882        folded: bool,
23883    },
23884    ExcerptsEdited {
23885        ids: Vec<ExcerptId>,
23886    },
23887    ExcerptsExpanded {
23888        ids: Vec<ExcerptId>,
23889    },
23890    BufferEdited,
23891    Edited {
23892        transaction_id: clock::Lamport,
23893    },
23894    Reparsed(BufferId),
23895    Focused,
23896    FocusedIn,
23897    Blurred,
23898    DirtyChanged,
23899    Saved,
23900    TitleChanged,
23901    SelectionsChanged {
23902        local: bool,
23903    },
23904    ScrollPositionChanged {
23905        local: bool,
23906        autoscroll: bool,
23907    },
23908    TransactionUndone {
23909        transaction_id: clock::Lamport,
23910    },
23911    TransactionBegun {
23912        transaction_id: clock::Lamport,
23913    },
23914    CursorShapeChanged,
23915    BreadcrumbsChanged,
23916    PushedToNavHistory {
23917        anchor: Anchor,
23918        is_deactivate: bool,
23919    },
23920}
23921
23922impl EventEmitter<EditorEvent> for Editor {}
23923
23924impl Focusable for Editor {
23925    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23926        self.focus_handle.clone()
23927    }
23928}
23929
23930impl Render for Editor {
23931    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23932        let settings = ThemeSettings::get_global(cx);
23933
23934        let mut text_style = match self.mode {
23935            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23936                color: cx.theme().colors().editor_foreground,
23937                font_family: settings.ui_font.family.clone(),
23938                font_features: settings.ui_font.features.clone(),
23939                font_fallbacks: settings.ui_font.fallbacks.clone(),
23940                font_size: rems(0.875).into(),
23941                font_weight: settings.ui_font.weight,
23942                line_height: relative(settings.buffer_line_height.value()),
23943                ..Default::default()
23944            },
23945            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23946                color: cx.theme().colors().editor_foreground,
23947                font_family: settings.buffer_font.family.clone(),
23948                font_features: settings.buffer_font.features.clone(),
23949                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23950                font_size: settings.buffer_font_size(cx).into(),
23951                font_weight: settings.buffer_font.weight,
23952                line_height: relative(settings.buffer_line_height.value()),
23953                ..Default::default()
23954            },
23955        };
23956        if let Some(text_style_refinement) = &self.text_style_refinement {
23957            text_style.refine(text_style_refinement)
23958        }
23959
23960        let background = match self.mode {
23961            EditorMode::SingleLine => cx.theme().system().transparent,
23962            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23963            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23964            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23965        };
23966
23967        EditorElement::new(
23968            &cx.entity(),
23969            EditorStyle {
23970                background,
23971                border: cx.theme().colors().border,
23972                local_player: cx.theme().players().local(),
23973                text: text_style,
23974                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23975                syntax: cx.theme().syntax().clone(),
23976                status: cx.theme().status().clone(),
23977                inlay_hints_style: make_inlay_hints_style(cx),
23978                edit_prediction_styles: make_suggestion_styles(cx),
23979                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23980                show_underlines: self.diagnostics_enabled(),
23981            },
23982        )
23983    }
23984}
23985
23986impl EntityInputHandler for Editor {
23987    fn text_for_range(
23988        &mut self,
23989        range_utf16: Range<usize>,
23990        adjusted_range: &mut Option<Range<usize>>,
23991        _: &mut Window,
23992        cx: &mut Context<Self>,
23993    ) -> Option<String> {
23994        let snapshot = self.buffer.read(cx).read(cx);
23995        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23996        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23997        if (start.0..end.0) != range_utf16 {
23998            adjusted_range.replace(start.0..end.0);
23999        }
24000        Some(snapshot.text_for_range(start..end).collect())
24001    }
24002
24003    fn selected_text_range(
24004        &mut self,
24005        ignore_disabled_input: bool,
24006        _: &mut Window,
24007        cx: &mut Context<Self>,
24008    ) -> Option<UTF16Selection> {
24009        // Prevent the IME menu from appearing when holding down an alphabetic key
24010        // while input is disabled.
24011        if !ignore_disabled_input && !self.input_enabled {
24012            return None;
24013        }
24014
24015        let selection = self
24016            .selections
24017            .newest::<OffsetUtf16>(&self.display_snapshot(cx));
24018        let range = selection.range();
24019
24020        Some(UTF16Selection {
24021            range: range.start.0..range.end.0,
24022            reversed: selection.reversed,
24023        })
24024    }
24025
24026    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
24027        let snapshot = self.buffer.read(cx).read(cx);
24028        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
24029        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
24030    }
24031
24032    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
24033        self.clear_highlights::<InputComposition>(cx);
24034        self.ime_transaction.take();
24035    }
24036
24037    fn replace_text_in_range(
24038        &mut self,
24039        range_utf16: Option<Range<usize>>,
24040        text: &str,
24041        window: &mut Window,
24042        cx: &mut Context<Self>,
24043    ) {
24044        if !self.input_enabled {
24045            cx.emit(EditorEvent::InputIgnored { text: text.into() });
24046            return;
24047        }
24048
24049        self.transact(window, cx, |this, window, cx| {
24050            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
24051                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
24052                Some(this.selection_replacement_ranges(range_utf16, cx))
24053            } else {
24054                this.marked_text_ranges(cx)
24055            };
24056
24057            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
24058                let newest_selection_id = this.selections.newest_anchor().id;
24059                this.selections
24060                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
24061                    .iter()
24062                    .zip(ranges_to_replace.iter())
24063                    .find_map(|(selection, range)| {
24064                        if selection.id == newest_selection_id {
24065                            Some(
24066                                (range.start.0 as isize - selection.head().0 as isize)
24067                                    ..(range.end.0 as isize - selection.head().0 as isize),
24068                            )
24069                        } else {
24070                            None
24071                        }
24072                    })
24073            });
24074
24075            cx.emit(EditorEvent::InputHandled {
24076                utf16_range_to_replace: range_to_replace,
24077                text: text.into(),
24078            });
24079
24080            if let Some(new_selected_ranges) = new_selected_ranges {
24081                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24082                    selections.select_ranges(new_selected_ranges)
24083                });
24084                this.backspace(&Default::default(), window, cx);
24085            }
24086
24087            this.handle_input(text, window, cx);
24088        });
24089
24090        if let Some(transaction) = self.ime_transaction {
24091            self.buffer.update(cx, |buffer, cx| {
24092                buffer.group_until_transaction(transaction, cx);
24093            });
24094        }
24095
24096        self.unmark_text(window, cx);
24097    }
24098
24099    fn replace_and_mark_text_in_range(
24100        &mut self,
24101        range_utf16: Option<Range<usize>>,
24102        text: &str,
24103        new_selected_range_utf16: Option<Range<usize>>,
24104        window: &mut Window,
24105        cx: &mut Context<Self>,
24106    ) {
24107        if !self.input_enabled {
24108            return;
24109        }
24110
24111        let transaction = self.transact(window, cx, |this, window, cx| {
24112            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
24113                let snapshot = this.buffer.read(cx).read(cx);
24114                if let Some(relative_range_utf16) = range_utf16.as_ref() {
24115                    for marked_range in &mut marked_ranges {
24116                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
24117                        marked_range.start.0 += relative_range_utf16.start;
24118                        marked_range.start =
24119                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
24120                        marked_range.end =
24121                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
24122                    }
24123                }
24124                Some(marked_ranges)
24125            } else if let Some(range_utf16) = range_utf16 {
24126                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
24127                Some(this.selection_replacement_ranges(range_utf16, cx))
24128            } else {
24129                None
24130            };
24131
24132            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
24133                let newest_selection_id = this.selections.newest_anchor().id;
24134                this.selections
24135                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
24136                    .iter()
24137                    .zip(ranges_to_replace.iter())
24138                    .find_map(|(selection, range)| {
24139                        if selection.id == newest_selection_id {
24140                            Some(
24141                                (range.start.0 as isize - selection.head().0 as isize)
24142                                    ..(range.end.0 as isize - selection.head().0 as isize),
24143                            )
24144                        } else {
24145                            None
24146                        }
24147                    })
24148            });
24149
24150            cx.emit(EditorEvent::InputHandled {
24151                utf16_range_to_replace: range_to_replace,
24152                text: text.into(),
24153            });
24154
24155            if let Some(ranges) = ranges_to_replace {
24156                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24157                    s.select_ranges(ranges)
24158                });
24159            }
24160
24161            let marked_ranges = {
24162                let snapshot = this.buffer.read(cx).read(cx);
24163                this.selections
24164                    .disjoint_anchors_arc()
24165                    .iter()
24166                    .map(|selection| {
24167                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
24168                    })
24169                    .collect::<Vec<_>>()
24170            };
24171
24172            if text.is_empty() {
24173                this.unmark_text(window, cx);
24174            } else {
24175                this.highlight_text::<InputComposition>(
24176                    marked_ranges.clone(),
24177                    HighlightStyle {
24178                        underline: Some(UnderlineStyle {
24179                            thickness: px(1.),
24180                            color: None,
24181                            wavy: false,
24182                        }),
24183                        ..Default::default()
24184                    },
24185                    cx,
24186                );
24187            }
24188
24189            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
24190            let use_autoclose = this.use_autoclose;
24191            let use_auto_surround = this.use_auto_surround;
24192            this.set_use_autoclose(false);
24193            this.set_use_auto_surround(false);
24194            this.handle_input(text, window, cx);
24195            this.set_use_autoclose(use_autoclose);
24196            this.set_use_auto_surround(use_auto_surround);
24197
24198            if let Some(new_selected_range) = new_selected_range_utf16 {
24199                let snapshot = this.buffer.read(cx).read(cx);
24200                let new_selected_ranges = marked_ranges
24201                    .into_iter()
24202                    .map(|marked_range| {
24203                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24204                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
24205                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
24206                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24207                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24208                    })
24209                    .collect::<Vec<_>>();
24210
24211                drop(snapshot);
24212                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24213                    selections.select_ranges(new_selected_ranges)
24214                });
24215            }
24216        });
24217
24218        self.ime_transaction = self.ime_transaction.or(transaction);
24219        if let Some(transaction) = self.ime_transaction {
24220            self.buffer.update(cx, |buffer, cx| {
24221                buffer.group_until_transaction(transaction, cx);
24222            });
24223        }
24224
24225        if self.text_highlights::<InputComposition>(cx).is_none() {
24226            self.ime_transaction.take();
24227        }
24228    }
24229
24230    fn bounds_for_range(
24231        &mut self,
24232        range_utf16: Range<usize>,
24233        element_bounds: gpui::Bounds<Pixels>,
24234        window: &mut Window,
24235        cx: &mut Context<Self>,
24236    ) -> Option<gpui::Bounds<Pixels>> {
24237        let text_layout_details = self.text_layout_details(window);
24238        let CharacterDimensions {
24239            em_width,
24240            em_advance,
24241            line_height,
24242        } = self.character_dimensions(window);
24243
24244        let snapshot = self.snapshot(window, cx);
24245        let scroll_position = snapshot.scroll_position();
24246        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24247
24248        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
24249        let x = Pixels::from(
24250            ScrollOffset::from(
24251                snapshot.x_for_display_point(start, &text_layout_details)
24252                    + self.gutter_dimensions.full_width(),
24253            ) - scroll_left,
24254        );
24255        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24256
24257        Some(Bounds {
24258            origin: element_bounds.origin + point(x, y),
24259            size: size(em_width, line_height),
24260        })
24261    }
24262
24263    fn character_index_for_point(
24264        &mut self,
24265        point: gpui::Point<Pixels>,
24266        _window: &mut Window,
24267        _cx: &mut Context<Self>,
24268    ) -> Option<usize> {
24269        let position_map = self.last_position_map.as_ref()?;
24270        if !position_map.text_hitbox.contains(&point) {
24271            return None;
24272        }
24273        let display_point = position_map.point_for_position(point).previous_valid;
24274        let anchor = position_map
24275            .snapshot
24276            .display_point_to_anchor(display_point, Bias::Left);
24277        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24278        Some(utf16_offset.0)
24279    }
24280
24281    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
24282        self.input_enabled
24283    }
24284}
24285
24286trait SelectionExt {
24287    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24288    fn spanned_rows(
24289        &self,
24290        include_end_if_at_line_start: bool,
24291        map: &DisplaySnapshot,
24292    ) -> Range<MultiBufferRow>;
24293}
24294
24295impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24296    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24297        let start = self
24298            .start
24299            .to_point(map.buffer_snapshot())
24300            .to_display_point(map);
24301        let end = self
24302            .end
24303            .to_point(map.buffer_snapshot())
24304            .to_display_point(map);
24305        if self.reversed {
24306            end..start
24307        } else {
24308            start..end
24309        }
24310    }
24311
24312    fn spanned_rows(
24313        &self,
24314        include_end_if_at_line_start: bool,
24315        map: &DisplaySnapshot,
24316    ) -> Range<MultiBufferRow> {
24317        let start = self.start.to_point(map.buffer_snapshot());
24318        let mut end = self.end.to_point(map.buffer_snapshot());
24319        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24320            end.row -= 1;
24321        }
24322
24323        let buffer_start = map.prev_line_boundary(start).0;
24324        let buffer_end = map.next_line_boundary(end).0;
24325        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24326    }
24327}
24328
24329impl<T: InvalidationRegion> InvalidationStack<T> {
24330    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24331    where
24332        S: Clone + ToOffset,
24333    {
24334        while let Some(region) = self.last() {
24335            let all_selections_inside_invalidation_ranges =
24336                if selections.len() == region.ranges().len() {
24337                    selections
24338                        .iter()
24339                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24340                        .all(|(selection, invalidation_range)| {
24341                            let head = selection.head().to_offset(buffer);
24342                            invalidation_range.start <= head && invalidation_range.end >= head
24343                        })
24344                } else {
24345                    false
24346                };
24347
24348            if all_selections_inside_invalidation_ranges {
24349                break;
24350            } else {
24351                self.pop();
24352            }
24353        }
24354    }
24355}
24356
24357impl<T> Default for InvalidationStack<T> {
24358    fn default() -> Self {
24359        Self(Default::default())
24360    }
24361}
24362
24363impl<T> Deref for InvalidationStack<T> {
24364    type Target = Vec<T>;
24365
24366    fn deref(&self) -> &Self::Target {
24367        &self.0
24368    }
24369}
24370
24371impl<T> DerefMut for InvalidationStack<T> {
24372    fn deref_mut(&mut self) -> &mut Self::Target {
24373        &mut self.0
24374    }
24375}
24376
24377impl InvalidationRegion for SnippetState {
24378    fn ranges(&self) -> &[Range<Anchor>] {
24379        &self.ranges[self.active_index]
24380    }
24381}
24382
24383fn edit_prediction_edit_text(
24384    current_snapshot: &BufferSnapshot,
24385    edits: &[(Range<Anchor>, impl AsRef<str>)],
24386    edit_preview: &EditPreview,
24387    include_deletions: bool,
24388    cx: &App,
24389) -> HighlightedText {
24390    let edits = edits
24391        .iter()
24392        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
24393        .collect::<Vec<_>>();
24394
24395    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24396}
24397
24398fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
24399    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24400    // Just show the raw edit text with basic styling
24401    let mut text = String::new();
24402    let mut highlights = Vec::new();
24403
24404    let insertion_highlight_style = HighlightStyle {
24405        color: Some(cx.theme().colors().text),
24406        ..Default::default()
24407    };
24408
24409    for (_, edit_text) in edits {
24410        let start_offset = text.len();
24411        text.push_str(edit_text);
24412        let end_offset = text.len();
24413
24414        if start_offset < end_offset {
24415            highlights.push((start_offset..end_offset, insertion_highlight_style));
24416        }
24417    }
24418
24419    HighlightedText {
24420        text: text.into(),
24421        highlights,
24422    }
24423}
24424
24425pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24426    match severity {
24427        lsp::DiagnosticSeverity::ERROR => colors.error,
24428        lsp::DiagnosticSeverity::WARNING => colors.warning,
24429        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24430        lsp::DiagnosticSeverity::HINT => colors.info,
24431        _ => colors.ignored,
24432    }
24433}
24434
24435pub fn styled_runs_for_code_label<'a>(
24436    label: &'a CodeLabel,
24437    syntax_theme: &'a theme::SyntaxTheme,
24438) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24439    let fade_out = HighlightStyle {
24440        fade_out: Some(0.35),
24441        ..Default::default()
24442    };
24443
24444    let mut prev_end = label.filter_range.end;
24445    label
24446        .runs
24447        .iter()
24448        .enumerate()
24449        .flat_map(move |(ix, (range, highlight_id))| {
24450            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24451                style
24452            } else {
24453                return Default::default();
24454            };
24455            let muted_style = style.highlight(fade_out);
24456
24457            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24458            if range.start >= label.filter_range.end {
24459                if range.start > prev_end {
24460                    runs.push((prev_end..range.start, fade_out));
24461                }
24462                runs.push((range.clone(), muted_style));
24463            } else if range.end <= label.filter_range.end {
24464                runs.push((range.clone(), style));
24465            } else {
24466                runs.push((range.start..label.filter_range.end, style));
24467                runs.push((label.filter_range.end..range.end, muted_style));
24468            }
24469            prev_end = cmp::max(prev_end, range.end);
24470
24471            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24472                runs.push((prev_end..label.text.len(), fade_out));
24473            }
24474
24475            runs
24476        })
24477}
24478
24479pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24480    let mut prev_index = 0;
24481    let mut prev_codepoint: Option<char> = None;
24482    text.char_indices()
24483        .chain([(text.len(), '\0')])
24484        .filter_map(move |(index, codepoint)| {
24485            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24486            let is_boundary = index == text.len()
24487                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24488                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24489            if is_boundary {
24490                let chunk = &text[prev_index..index];
24491                prev_index = index;
24492                Some(chunk)
24493            } else {
24494                None
24495            }
24496        })
24497}
24498
24499pub trait RangeToAnchorExt: Sized {
24500    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24501
24502    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24503        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
24504        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24505    }
24506}
24507
24508impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24509    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24510        let start_offset = self.start.to_offset(snapshot);
24511        let end_offset = self.end.to_offset(snapshot);
24512        if start_offset == end_offset {
24513            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24514        } else {
24515            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24516        }
24517    }
24518}
24519
24520pub trait RowExt {
24521    fn as_f64(&self) -> f64;
24522
24523    fn next_row(&self) -> Self;
24524
24525    fn previous_row(&self) -> Self;
24526
24527    fn minus(&self, other: Self) -> u32;
24528}
24529
24530impl RowExt for DisplayRow {
24531    fn as_f64(&self) -> f64 {
24532        self.0 as _
24533    }
24534
24535    fn next_row(&self) -> Self {
24536        Self(self.0 + 1)
24537    }
24538
24539    fn previous_row(&self) -> Self {
24540        Self(self.0.saturating_sub(1))
24541    }
24542
24543    fn minus(&self, other: Self) -> u32 {
24544        self.0 - other.0
24545    }
24546}
24547
24548impl RowExt for MultiBufferRow {
24549    fn as_f64(&self) -> f64 {
24550        self.0 as _
24551    }
24552
24553    fn next_row(&self) -> Self {
24554        Self(self.0 + 1)
24555    }
24556
24557    fn previous_row(&self) -> Self {
24558        Self(self.0.saturating_sub(1))
24559    }
24560
24561    fn minus(&self, other: Self) -> u32 {
24562        self.0 - other.0
24563    }
24564}
24565
24566trait RowRangeExt {
24567    type Row;
24568
24569    fn len(&self) -> usize;
24570
24571    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24572}
24573
24574impl RowRangeExt for Range<MultiBufferRow> {
24575    type Row = MultiBufferRow;
24576
24577    fn len(&self) -> usize {
24578        (self.end.0 - self.start.0) as usize
24579    }
24580
24581    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24582        (self.start.0..self.end.0).map(MultiBufferRow)
24583    }
24584}
24585
24586impl RowRangeExt for Range<DisplayRow> {
24587    type Row = DisplayRow;
24588
24589    fn len(&self) -> usize {
24590        (self.end.0 - self.start.0) as usize
24591    }
24592
24593    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24594        (self.start.0..self.end.0).map(DisplayRow)
24595    }
24596}
24597
24598/// If select range has more than one line, we
24599/// just point the cursor to range.start.
24600fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24601    if range.start.row == range.end.row {
24602        range
24603    } else {
24604        range.start..range.start
24605    }
24606}
24607pub struct KillRing(ClipboardItem);
24608impl Global for KillRing {}
24609
24610const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24611
24612enum BreakpointPromptEditAction {
24613    Log,
24614    Condition,
24615    HitCondition,
24616}
24617
24618struct BreakpointPromptEditor {
24619    pub(crate) prompt: Entity<Editor>,
24620    editor: WeakEntity<Editor>,
24621    breakpoint_anchor: Anchor,
24622    breakpoint: Breakpoint,
24623    edit_action: BreakpointPromptEditAction,
24624    block_ids: HashSet<CustomBlockId>,
24625    editor_margins: Arc<Mutex<EditorMargins>>,
24626    _subscriptions: Vec<Subscription>,
24627}
24628
24629impl BreakpointPromptEditor {
24630    const MAX_LINES: u8 = 4;
24631
24632    fn new(
24633        editor: WeakEntity<Editor>,
24634        breakpoint_anchor: Anchor,
24635        breakpoint: Breakpoint,
24636        edit_action: BreakpointPromptEditAction,
24637        window: &mut Window,
24638        cx: &mut Context<Self>,
24639    ) -> Self {
24640        let base_text = match edit_action {
24641            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24642            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24643            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24644        }
24645        .map(|msg| msg.to_string())
24646        .unwrap_or_default();
24647
24648        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24649        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24650
24651        let prompt = cx.new(|cx| {
24652            let mut prompt = Editor::new(
24653                EditorMode::AutoHeight {
24654                    min_lines: 1,
24655                    max_lines: Some(Self::MAX_LINES as usize),
24656                },
24657                buffer,
24658                None,
24659                window,
24660                cx,
24661            );
24662            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24663            prompt.set_show_cursor_when_unfocused(false, cx);
24664            prompt.set_placeholder_text(
24665                match edit_action {
24666                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24667                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24668                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24669                },
24670                window,
24671                cx,
24672            );
24673
24674            prompt
24675        });
24676
24677        Self {
24678            prompt,
24679            editor,
24680            breakpoint_anchor,
24681            breakpoint,
24682            edit_action,
24683            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24684            block_ids: Default::default(),
24685            _subscriptions: vec![],
24686        }
24687    }
24688
24689    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24690        self.block_ids.extend(block_ids)
24691    }
24692
24693    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24694        if let Some(editor) = self.editor.upgrade() {
24695            let message = self
24696                .prompt
24697                .read(cx)
24698                .buffer
24699                .read(cx)
24700                .as_singleton()
24701                .expect("A multi buffer in breakpoint prompt isn't possible")
24702                .read(cx)
24703                .as_rope()
24704                .to_string();
24705
24706            editor.update(cx, |editor, cx| {
24707                editor.edit_breakpoint_at_anchor(
24708                    self.breakpoint_anchor,
24709                    self.breakpoint.clone(),
24710                    match self.edit_action {
24711                        BreakpointPromptEditAction::Log => {
24712                            BreakpointEditAction::EditLogMessage(message.into())
24713                        }
24714                        BreakpointPromptEditAction::Condition => {
24715                            BreakpointEditAction::EditCondition(message.into())
24716                        }
24717                        BreakpointPromptEditAction::HitCondition => {
24718                            BreakpointEditAction::EditHitCondition(message.into())
24719                        }
24720                    },
24721                    cx,
24722                );
24723
24724                editor.remove_blocks(self.block_ids.clone(), None, cx);
24725                cx.focus_self(window);
24726            });
24727        }
24728    }
24729
24730    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24731        self.editor
24732            .update(cx, |editor, cx| {
24733                editor.remove_blocks(self.block_ids.clone(), None, cx);
24734                window.focus(&editor.focus_handle);
24735            })
24736            .log_err();
24737    }
24738
24739    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24740        let settings = ThemeSettings::get_global(cx);
24741        let text_style = TextStyle {
24742            color: if self.prompt.read(cx).read_only(cx) {
24743                cx.theme().colors().text_disabled
24744            } else {
24745                cx.theme().colors().text
24746            },
24747            font_family: settings.buffer_font.family.clone(),
24748            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24749            font_size: settings.buffer_font_size(cx).into(),
24750            font_weight: settings.buffer_font.weight,
24751            line_height: relative(settings.buffer_line_height.value()),
24752            ..Default::default()
24753        };
24754        EditorElement::new(
24755            &self.prompt,
24756            EditorStyle {
24757                background: cx.theme().colors().editor_background,
24758                local_player: cx.theme().players().local(),
24759                text: text_style,
24760                ..Default::default()
24761            },
24762        )
24763    }
24764}
24765
24766impl Render for BreakpointPromptEditor {
24767    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24768        let editor_margins = *self.editor_margins.lock();
24769        let gutter_dimensions = editor_margins.gutter;
24770        h_flex()
24771            .key_context("Editor")
24772            .bg(cx.theme().colors().editor_background)
24773            .border_y_1()
24774            .border_color(cx.theme().status().info_border)
24775            .size_full()
24776            .py(window.line_height() / 2.5)
24777            .on_action(cx.listener(Self::confirm))
24778            .on_action(cx.listener(Self::cancel))
24779            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24780            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24781    }
24782}
24783
24784impl Focusable for BreakpointPromptEditor {
24785    fn focus_handle(&self, cx: &App) -> FocusHandle {
24786        self.prompt.focus_handle(cx)
24787    }
24788}
24789
24790fn all_edits_insertions_or_deletions(
24791    edits: &Vec<(Range<Anchor>, Arc<str>)>,
24792    snapshot: &MultiBufferSnapshot,
24793) -> bool {
24794    let mut all_insertions = true;
24795    let mut all_deletions = true;
24796
24797    for (range, new_text) in edits.iter() {
24798        let range_is_empty = range.to_offset(snapshot).is_empty();
24799        let text_is_empty = new_text.is_empty();
24800
24801        if range_is_empty != text_is_empty {
24802            if range_is_empty {
24803                all_deletions = false;
24804            } else {
24805                all_insertions = false;
24806            }
24807        } else {
24808            return false;
24809        }
24810
24811        if !all_insertions && !all_deletions {
24812            return false;
24813        }
24814    }
24815    all_insertions || all_deletions
24816}
24817
24818struct MissingEditPredictionKeybindingTooltip;
24819
24820impl Render for MissingEditPredictionKeybindingTooltip {
24821    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24822        ui::tooltip_container(cx, |container, cx| {
24823            container
24824                .flex_shrink_0()
24825                .max_w_80()
24826                .min_h(rems_from_px(124.))
24827                .justify_between()
24828                .child(
24829                    v_flex()
24830                        .flex_1()
24831                        .text_ui_sm(cx)
24832                        .child(Label::new("Conflict with Accept Keybinding"))
24833                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24834                )
24835                .child(
24836                    h_flex()
24837                        .pb_1()
24838                        .gap_1()
24839                        .items_end()
24840                        .w_full()
24841                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24842                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
24843                        }))
24844                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24845                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24846                        })),
24847                )
24848        })
24849    }
24850}
24851
24852#[derive(Debug, Clone, Copy, PartialEq)]
24853pub struct LineHighlight {
24854    pub background: Background,
24855    pub border: Option<gpui::Hsla>,
24856    pub include_gutter: bool,
24857    pub type_id: Option<TypeId>,
24858}
24859
24860struct LineManipulationResult {
24861    pub new_text: String,
24862    pub line_count_before: usize,
24863    pub line_count_after: usize,
24864}
24865
24866fn render_diff_hunk_controls(
24867    row: u32,
24868    status: &DiffHunkStatus,
24869    hunk_range: Range<Anchor>,
24870    is_created_file: bool,
24871    line_height: Pixels,
24872    editor: &Entity<Editor>,
24873    _window: &mut Window,
24874    cx: &mut App,
24875) -> AnyElement {
24876    h_flex()
24877        .h(line_height)
24878        .mr_1()
24879        .gap_1()
24880        .px_0p5()
24881        .pb_1()
24882        .border_x_1()
24883        .border_b_1()
24884        .border_color(cx.theme().colors().border_variant)
24885        .rounded_b_lg()
24886        .bg(cx.theme().colors().editor_background)
24887        .gap_1()
24888        .block_mouse_except_scroll()
24889        .shadow_md()
24890        .child(if status.has_secondary_hunk() {
24891            Button::new(("stage", row as u64), "Stage")
24892                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24893                .tooltip({
24894                    let focus_handle = editor.focus_handle(cx);
24895                    move |_window, cx| {
24896                        Tooltip::for_action_in(
24897                            "Stage Hunk",
24898                            &::git::ToggleStaged,
24899                            &focus_handle,
24900                            cx,
24901                        )
24902                    }
24903                })
24904                .on_click({
24905                    let editor = editor.clone();
24906                    move |_event, _window, cx| {
24907                        editor.update(cx, |editor, cx| {
24908                            editor.stage_or_unstage_diff_hunks(
24909                                true,
24910                                vec![hunk_range.start..hunk_range.start],
24911                                cx,
24912                            );
24913                        });
24914                    }
24915                })
24916        } else {
24917            Button::new(("unstage", row as u64), "Unstage")
24918                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24919                .tooltip({
24920                    let focus_handle = editor.focus_handle(cx);
24921                    move |_window, cx| {
24922                        Tooltip::for_action_in(
24923                            "Unstage Hunk",
24924                            &::git::ToggleStaged,
24925                            &focus_handle,
24926                            cx,
24927                        )
24928                    }
24929                })
24930                .on_click({
24931                    let editor = editor.clone();
24932                    move |_event, _window, cx| {
24933                        editor.update(cx, |editor, cx| {
24934                            editor.stage_or_unstage_diff_hunks(
24935                                false,
24936                                vec![hunk_range.start..hunk_range.start],
24937                                cx,
24938                            );
24939                        });
24940                    }
24941                })
24942        })
24943        .child(
24944            Button::new(("restore", row as u64), "Restore")
24945                .tooltip({
24946                    let focus_handle = editor.focus_handle(cx);
24947                    move |_window, cx| {
24948                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
24949                    }
24950                })
24951                .on_click({
24952                    let editor = editor.clone();
24953                    move |_event, window, cx| {
24954                        editor.update(cx, |editor, cx| {
24955                            let snapshot = editor.snapshot(window, cx);
24956                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
24957                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24958                        });
24959                    }
24960                })
24961                .disabled(is_created_file),
24962        )
24963        .when(
24964            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24965            |el| {
24966                el.child(
24967                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24968                        .shape(IconButtonShape::Square)
24969                        .icon_size(IconSize::Small)
24970                        // .disabled(!has_multiple_hunks)
24971                        .tooltip({
24972                            let focus_handle = editor.focus_handle(cx);
24973                            move |_window, cx| {
24974                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
24975                            }
24976                        })
24977                        .on_click({
24978                            let editor = editor.clone();
24979                            move |_event, window, cx| {
24980                                editor.update(cx, |editor, cx| {
24981                                    let snapshot = editor.snapshot(window, cx);
24982                                    let position =
24983                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
24984                                    editor.go_to_hunk_before_or_after_position(
24985                                        &snapshot,
24986                                        position,
24987                                        Direction::Next,
24988                                        window,
24989                                        cx,
24990                                    );
24991                                    editor.expand_selected_diff_hunks(cx);
24992                                });
24993                            }
24994                        }),
24995                )
24996                .child(
24997                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24998                        .shape(IconButtonShape::Square)
24999                        .icon_size(IconSize::Small)
25000                        // .disabled(!has_multiple_hunks)
25001                        .tooltip({
25002                            let focus_handle = editor.focus_handle(cx);
25003                            move |_window, cx| {
25004                                Tooltip::for_action_in(
25005                                    "Previous Hunk",
25006                                    &GoToPreviousHunk,
25007                                    &focus_handle,
25008                                    cx,
25009                                )
25010                            }
25011                        })
25012                        .on_click({
25013                            let editor = editor.clone();
25014                            move |_event, window, cx| {
25015                                editor.update(cx, |editor, cx| {
25016                                    let snapshot = editor.snapshot(window, cx);
25017                                    let point =
25018                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
25019                                    editor.go_to_hunk_before_or_after_position(
25020                                        &snapshot,
25021                                        point,
25022                                        Direction::Prev,
25023                                        window,
25024                                        cx,
25025                                    );
25026                                    editor.expand_selected_diff_hunks(cx);
25027                                });
25028                            }
25029                        }),
25030                )
25031            },
25032        )
25033        .into_any_element()
25034}
25035
25036pub fn multibuffer_context_lines(cx: &App) -> u32 {
25037    EditorSettings::try_get(cx)
25038        .map(|settings| settings.excerpt_context_lines)
25039        .unwrap_or(2)
25040        .min(32)
25041}