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();
 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.display_map.update(cx, |map, cx| map.snapshot(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        assert_eq!(self.buffer(), other.read(cx).buffer());
 3370        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3371        if !other_selections.is_empty() {
 3372            self.selections
 3373                .change_with(&self.display_snapshot(cx), |selections| {
 3374                    selections.select_anchors(other_selections);
 3375                });
 3376        }
 3377
 3378        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3379            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3380                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3381                if other_selections.is_empty() {
 3382                    return;
 3383                }
 3384                let snapshot = this.display_snapshot(cx);
 3385                this.selections.change_with(&snapshot, |selections| {
 3386                    selections.select_anchors(other_selections);
 3387                });
 3388            }
 3389        });
 3390
 3391        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3392            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3393                let these_selections = this.selections.disjoint_anchors().to_vec();
 3394                if these_selections.is_empty() {
 3395                    return;
 3396                }
 3397                other.update(cx, |other_editor, cx| {
 3398                    let snapshot = other_editor.display_snapshot(cx);
 3399                    other_editor
 3400                        .selections
 3401                        .change_with(&snapshot, |selections| {
 3402                            selections.select_anchors(these_selections);
 3403                        })
 3404                });
 3405            }
 3406        });
 3407
 3408        Subscription::join(other_subscription, this_subscription)
 3409    }
 3410
 3411    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3412    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3413    /// effects of selection change occur at the end of the transaction.
 3414    pub fn change_selections<R>(
 3415        &mut self,
 3416        effects: SelectionEffects,
 3417        window: &mut Window,
 3418        cx: &mut Context<Self>,
 3419        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 3420    ) -> R {
 3421        let snapshot = self.display_snapshot(cx);
 3422        if let Some(state) = &mut self.deferred_selection_effects_state {
 3423            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3424            state.effects.completions = effects.completions;
 3425            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3426            let (changed, result) = self.selections.change_with(&snapshot, change);
 3427            state.changed |= changed;
 3428            return result;
 3429        }
 3430        let mut state = DeferredSelectionEffectsState {
 3431            changed: false,
 3432            effects,
 3433            old_cursor_position: self.selections.newest_anchor().head(),
 3434            history_entry: SelectionHistoryEntry {
 3435                selections: self.selections.disjoint_anchors_arc(),
 3436                select_next_state: self.select_next_state.clone(),
 3437                select_prev_state: self.select_prev_state.clone(),
 3438                add_selections_state: self.add_selections_state.clone(),
 3439            },
 3440        };
 3441        let (changed, result) = self.selections.change_with(&snapshot, change);
 3442        state.changed = state.changed || changed;
 3443        if self.defer_selection_effects {
 3444            self.deferred_selection_effects_state = Some(state);
 3445        } else {
 3446            self.apply_selection_effects(state, window, cx);
 3447        }
 3448        result
 3449    }
 3450
 3451    /// Defers the effects of selection change, so that the effects of multiple calls to
 3452    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3453    /// to selection history and the state of popovers based on selection position aren't
 3454    /// erroneously updated.
 3455    pub fn with_selection_effects_deferred<R>(
 3456        &mut self,
 3457        window: &mut Window,
 3458        cx: &mut Context<Self>,
 3459        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3460    ) -> R {
 3461        let already_deferred = self.defer_selection_effects;
 3462        self.defer_selection_effects = true;
 3463        let result = update(self, window, cx);
 3464        if !already_deferred {
 3465            self.defer_selection_effects = false;
 3466            if let Some(state) = self.deferred_selection_effects_state.take() {
 3467                self.apply_selection_effects(state, window, cx);
 3468            }
 3469        }
 3470        result
 3471    }
 3472
 3473    fn apply_selection_effects(
 3474        &mut self,
 3475        state: DeferredSelectionEffectsState,
 3476        window: &mut Window,
 3477        cx: &mut Context<Self>,
 3478    ) {
 3479        if state.changed {
 3480            self.selection_history.push(state.history_entry);
 3481
 3482            if let Some(autoscroll) = state.effects.scroll {
 3483                self.request_autoscroll(autoscroll, cx);
 3484            }
 3485
 3486            let old_cursor_position = &state.old_cursor_position;
 3487
 3488            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3489
 3490            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3491                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3492            }
 3493        }
 3494    }
 3495
 3496    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3497    where
 3498        I: IntoIterator<Item = (Range<S>, T)>,
 3499        S: ToOffset,
 3500        T: Into<Arc<str>>,
 3501    {
 3502        if self.read_only(cx) {
 3503            return;
 3504        }
 3505
 3506        self.buffer
 3507            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3508    }
 3509
 3510    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3511    where
 3512        I: IntoIterator<Item = (Range<S>, T)>,
 3513        S: ToOffset,
 3514        T: Into<Arc<str>>,
 3515    {
 3516        if self.read_only(cx) {
 3517            return;
 3518        }
 3519
 3520        self.buffer.update(cx, |buffer, cx| {
 3521            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3522        });
 3523    }
 3524
 3525    pub fn edit_with_block_indent<I, S, T>(
 3526        &mut self,
 3527        edits: I,
 3528        original_indent_columns: Vec<Option<u32>>,
 3529        cx: &mut Context<Self>,
 3530    ) where
 3531        I: IntoIterator<Item = (Range<S>, T)>,
 3532        S: ToOffset,
 3533        T: Into<Arc<str>>,
 3534    {
 3535        if self.read_only(cx) {
 3536            return;
 3537        }
 3538
 3539        self.buffer.update(cx, |buffer, cx| {
 3540            buffer.edit(
 3541                edits,
 3542                Some(AutoindentMode::Block {
 3543                    original_indent_columns,
 3544                }),
 3545                cx,
 3546            )
 3547        });
 3548    }
 3549
 3550    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3551        self.hide_context_menu(window, cx);
 3552
 3553        match phase {
 3554            SelectPhase::Begin {
 3555                position,
 3556                add,
 3557                click_count,
 3558            } => self.begin_selection(position, add, click_count, window, cx),
 3559            SelectPhase::BeginColumnar {
 3560                position,
 3561                goal_column,
 3562                reset,
 3563                mode,
 3564            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3565            SelectPhase::Extend {
 3566                position,
 3567                click_count,
 3568            } => self.extend_selection(position, click_count, window, cx),
 3569            SelectPhase::Update {
 3570                position,
 3571                goal_column,
 3572                scroll_delta,
 3573            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3574            SelectPhase::End => self.end_selection(window, cx),
 3575        }
 3576    }
 3577
 3578    fn extend_selection(
 3579        &mut self,
 3580        position: DisplayPoint,
 3581        click_count: usize,
 3582        window: &mut Window,
 3583        cx: &mut Context<Self>,
 3584    ) {
 3585        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3586        let tail = self.selections.newest::<usize>(&display_map).tail();
 3587        let click_count = click_count.max(match self.selections.select_mode() {
 3588            SelectMode::Character => 1,
 3589            SelectMode::Word(_) => 2,
 3590            SelectMode::Line(_) => 3,
 3591            SelectMode::All => 4,
 3592        });
 3593        self.begin_selection(position, false, click_count, window, cx);
 3594
 3595        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3596
 3597        let current_selection = match self.selections.select_mode() {
 3598            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3599            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3600        };
 3601
 3602        let mut pending_selection = self
 3603            .selections
 3604            .pending_anchor()
 3605            .cloned()
 3606            .expect("extend_selection not called with pending selection");
 3607
 3608        if pending_selection
 3609            .start
 3610            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3611            == Ordering::Greater
 3612        {
 3613            pending_selection.start = current_selection.start;
 3614        }
 3615        if pending_selection
 3616            .end
 3617            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3618            == Ordering::Less
 3619        {
 3620            pending_selection.end = current_selection.end;
 3621            pending_selection.reversed = true;
 3622        }
 3623
 3624        let mut pending_mode = self.selections.pending_mode().unwrap();
 3625        match &mut pending_mode {
 3626            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3627            _ => {}
 3628        }
 3629
 3630        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3631            SelectionEffects::scroll(Autoscroll::fit())
 3632        } else {
 3633            SelectionEffects::no_scroll()
 3634        };
 3635
 3636        self.change_selections(effects, window, cx, |s| {
 3637            s.set_pending(pending_selection.clone(), pending_mode);
 3638            s.set_is_extending(true);
 3639        });
 3640    }
 3641
 3642    fn begin_selection(
 3643        &mut self,
 3644        position: DisplayPoint,
 3645        add: bool,
 3646        click_count: usize,
 3647        window: &mut Window,
 3648        cx: &mut Context<Self>,
 3649    ) {
 3650        if !self.focus_handle.is_focused(window) {
 3651            self.last_focused_descendant = None;
 3652            window.focus(&self.focus_handle);
 3653        }
 3654
 3655        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3656        let buffer = display_map.buffer_snapshot();
 3657        let position = display_map.clip_point(position, Bias::Left);
 3658
 3659        let start;
 3660        let end;
 3661        let mode;
 3662        let mut auto_scroll;
 3663        match click_count {
 3664            1 => {
 3665                start = buffer.anchor_before(position.to_point(&display_map));
 3666                end = start;
 3667                mode = SelectMode::Character;
 3668                auto_scroll = true;
 3669            }
 3670            2 => {
 3671                let position = display_map
 3672                    .clip_point(position, Bias::Left)
 3673                    .to_offset(&display_map, Bias::Left);
 3674                let (range, _) = buffer.surrounding_word(position, None);
 3675                start = buffer.anchor_before(range.start);
 3676                end = buffer.anchor_before(range.end);
 3677                mode = SelectMode::Word(start..end);
 3678                auto_scroll = true;
 3679            }
 3680            3 => {
 3681                let position = display_map
 3682                    .clip_point(position, Bias::Left)
 3683                    .to_point(&display_map);
 3684                let line_start = display_map.prev_line_boundary(position).0;
 3685                let next_line_start = buffer.clip_point(
 3686                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3687                    Bias::Left,
 3688                );
 3689                start = buffer.anchor_before(line_start);
 3690                end = buffer.anchor_before(next_line_start);
 3691                mode = SelectMode::Line(start..end);
 3692                auto_scroll = true;
 3693            }
 3694            _ => {
 3695                start = buffer.anchor_before(0);
 3696                end = buffer.anchor_before(buffer.len());
 3697                mode = SelectMode::All;
 3698                auto_scroll = false;
 3699            }
 3700        }
 3701        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3702
 3703        let point_to_delete: Option<usize> = {
 3704            let selected_points: Vec<Selection<Point>> =
 3705                self.selections.disjoint_in_range(start..end, &display_map);
 3706
 3707            if !add || click_count > 1 {
 3708                None
 3709            } else if !selected_points.is_empty() {
 3710                Some(selected_points[0].id)
 3711            } else {
 3712                let clicked_point_already_selected =
 3713                    self.selections.disjoint_anchors().iter().find(|selection| {
 3714                        selection.start.to_point(buffer) == start.to_point(buffer)
 3715                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3716                    });
 3717
 3718                clicked_point_already_selected.map(|selection| selection.id)
 3719            }
 3720        };
 3721
 3722        let selections_count = self.selections.count();
 3723        let effects = if auto_scroll {
 3724            SelectionEffects::default()
 3725        } else {
 3726            SelectionEffects::no_scroll()
 3727        };
 3728
 3729        self.change_selections(effects, window, cx, |s| {
 3730            if let Some(point_to_delete) = point_to_delete {
 3731                s.delete(point_to_delete);
 3732
 3733                if selections_count == 1 {
 3734                    s.set_pending_anchor_range(start..end, mode);
 3735                }
 3736            } else {
 3737                if !add {
 3738                    s.clear_disjoint();
 3739                }
 3740
 3741                s.set_pending_anchor_range(start..end, mode);
 3742            }
 3743        });
 3744    }
 3745
 3746    fn begin_columnar_selection(
 3747        &mut self,
 3748        position: DisplayPoint,
 3749        goal_column: u32,
 3750        reset: bool,
 3751        mode: ColumnarMode,
 3752        window: &mut Window,
 3753        cx: &mut Context<Self>,
 3754    ) {
 3755        if !self.focus_handle.is_focused(window) {
 3756            self.last_focused_descendant = None;
 3757            window.focus(&self.focus_handle);
 3758        }
 3759
 3760        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3761
 3762        if reset {
 3763            let pointer_position = display_map
 3764                .buffer_snapshot()
 3765                .anchor_before(position.to_point(&display_map));
 3766
 3767            self.change_selections(
 3768                SelectionEffects::scroll(Autoscroll::newest()),
 3769                window,
 3770                cx,
 3771                |s| {
 3772                    s.clear_disjoint();
 3773                    s.set_pending_anchor_range(
 3774                        pointer_position..pointer_position,
 3775                        SelectMode::Character,
 3776                    );
 3777                },
 3778            );
 3779        };
 3780
 3781        let tail = self.selections.newest::<Point>(&display_map).tail();
 3782        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3783        self.columnar_selection_state = match mode {
 3784            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3785                selection_tail: selection_anchor,
 3786                display_point: if reset {
 3787                    if position.column() != goal_column {
 3788                        Some(DisplayPoint::new(position.row(), goal_column))
 3789                    } else {
 3790                        None
 3791                    }
 3792                } else {
 3793                    None
 3794                },
 3795            }),
 3796            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3797                selection_tail: selection_anchor,
 3798            }),
 3799        };
 3800
 3801        if !reset {
 3802            self.select_columns(position, goal_column, &display_map, window, cx);
 3803        }
 3804    }
 3805
 3806    fn update_selection(
 3807        &mut self,
 3808        position: DisplayPoint,
 3809        goal_column: u32,
 3810        scroll_delta: gpui::Point<f32>,
 3811        window: &mut Window,
 3812        cx: &mut Context<Self>,
 3813    ) {
 3814        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3815
 3816        if self.columnar_selection_state.is_some() {
 3817            self.select_columns(position, goal_column, &display_map, window, cx);
 3818        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3819            let buffer = display_map.buffer_snapshot();
 3820            let head;
 3821            let tail;
 3822            let mode = self.selections.pending_mode().unwrap();
 3823            match &mode {
 3824                SelectMode::Character => {
 3825                    head = position.to_point(&display_map);
 3826                    tail = pending.tail().to_point(buffer);
 3827                }
 3828                SelectMode::Word(original_range) => {
 3829                    let offset = display_map
 3830                        .clip_point(position, Bias::Left)
 3831                        .to_offset(&display_map, Bias::Left);
 3832                    let original_range = original_range.to_offset(buffer);
 3833
 3834                    let head_offset = if buffer.is_inside_word(offset, None)
 3835                        || original_range.contains(&offset)
 3836                    {
 3837                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3838                        if word_range.start < original_range.start {
 3839                            word_range.start
 3840                        } else {
 3841                            word_range.end
 3842                        }
 3843                    } else {
 3844                        offset
 3845                    };
 3846
 3847                    head = head_offset.to_point(buffer);
 3848                    if head_offset <= original_range.start {
 3849                        tail = original_range.end.to_point(buffer);
 3850                    } else {
 3851                        tail = original_range.start.to_point(buffer);
 3852                    }
 3853                }
 3854                SelectMode::Line(original_range) => {
 3855                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3856
 3857                    let position = display_map
 3858                        .clip_point(position, Bias::Left)
 3859                        .to_point(&display_map);
 3860                    let line_start = display_map.prev_line_boundary(position).0;
 3861                    let next_line_start = buffer.clip_point(
 3862                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3863                        Bias::Left,
 3864                    );
 3865
 3866                    if line_start < original_range.start {
 3867                        head = line_start
 3868                    } else {
 3869                        head = next_line_start
 3870                    }
 3871
 3872                    if head <= original_range.start {
 3873                        tail = original_range.end;
 3874                    } else {
 3875                        tail = original_range.start;
 3876                    }
 3877                }
 3878                SelectMode::All => {
 3879                    return;
 3880                }
 3881            };
 3882
 3883            if head < tail {
 3884                pending.start = buffer.anchor_before(head);
 3885                pending.end = buffer.anchor_before(tail);
 3886                pending.reversed = true;
 3887            } else {
 3888                pending.start = buffer.anchor_before(tail);
 3889                pending.end = buffer.anchor_before(head);
 3890                pending.reversed = false;
 3891            }
 3892
 3893            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3894                s.set_pending(pending.clone(), mode);
 3895            });
 3896        } else {
 3897            log::error!("update_selection dispatched with no pending selection");
 3898            return;
 3899        }
 3900
 3901        self.apply_scroll_delta(scroll_delta, window, cx);
 3902        cx.notify();
 3903    }
 3904
 3905    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3906        self.columnar_selection_state.take();
 3907        if let Some(pending_mode) = self.selections.pending_mode() {
 3908            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3909            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3910                s.select(selections);
 3911                s.clear_pending();
 3912                if s.is_extending() {
 3913                    s.set_is_extending(false);
 3914                } else {
 3915                    s.set_select_mode(pending_mode);
 3916                }
 3917            });
 3918        }
 3919    }
 3920
 3921    fn select_columns(
 3922        &mut self,
 3923        head: DisplayPoint,
 3924        goal_column: u32,
 3925        display_map: &DisplaySnapshot,
 3926        window: &mut Window,
 3927        cx: &mut Context<Self>,
 3928    ) {
 3929        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3930            return;
 3931        };
 3932
 3933        let tail = match columnar_state {
 3934            ColumnarSelectionState::FromMouse {
 3935                selection_tail,
 3936                display_point,
 3937            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3938            ColumnarSelectionState::FromSelection { selection_tail } => {
 3939                selection_tail.to_display_point(display_map)
 3940            }
 3941        };
 3942
 3943        let start_row = cmp::min(tail.row(), head.row());
 3944        let end_row = cmp::max(tail.row(), head.row());
 3945        let start_column = cmp::min(tail.column(), goal_column);
 3946        let end_column = cmp::max(tail.column(), goal_column);
 3947        let reversed = start_column < tail.column();
 3948
 3949        let selection_ranges = (start_row.0..=end_row.0)
 3950            .map(DisplayRow)
 3951            .filter_map(|row| {
 3952                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3953                    || start_column <= display_map.line_len(row))
 3954                    && !display_map.is_block_line(row)
 3955                {
 3956                    let start = display_map
 3957                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3958                        .to_point(display_map);
 3959                    let end = display_map
 3960                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3961                        .to_point(display_map);
 3962                    if reversed {
 3963                        Some(end..start)
 3964                    } else {
 3965                        Some(start..end)
 3966                    }
 3967                } else {
 3968                    None
 3969                }
 3970            })
 3971            .collect::<Vec<_>>();
 3972        if selection_ranges.is_empty() {
 3973            return;
 3974        }
 3975
 3976        let ranges = match columnar_state {
 3977            ColumnarSelectionState::FromMouse { .. } => {
 3978                let mut non_empty_ranges = selection_ranges
 3979                    .iter()
 3980                    .filter(|selection_range| selection_range.start != selection_range.end)
 3981                    .peekable();
 3982                if non_empty_ranges.peek().is_some() {
 3983                    non_empty_ranges.cloned().collect()
 3984                } else {
 3985                    selection_ranges
 3986                }
 3987            }
 3988            _ => selection_ranges,
 3989        };
 3990
 3991        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3992            s.select_ranges(ranges);
 3993        });
 3994        cx.notify();
 3995    }
 3996
 3997    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 3998        self.selections
 3999            .all_adjusted(snapshot)
 4000            .iter()
 4001            .any(|selection| !selection.is_empty())
 4002    }
 4003
 4004    pub fn has_pending_nonempty_selection(&self) -> bool {
 4005        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4006            Some(Selection { start, end, .. }) => start != end,
 4007            None => false,
 4008        };
 4009
 4010        pending_nonempty_selection
 4011            || (self.columnar_selection_state.is_some()
 4012                && self.selections.disjoint_anchors().len() > 1)
 4013    }
 4014
 4015    pub fn has_pending_selection(&self) -> bool {
 4016        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4017    }
 4018
 4019    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4020        self.selection_mark_mode = false;
 4021        self.selection_drag_state = SelectionDragState::None;
 4022
 4023        if self.clear_expanded_diff_hunks(cx) {
 4024            cx.notify();
 4025            return;
 4026        }
 4027        if self.dismiss_menus_and_popups(true, window, cx) {
 4028            return;
 4029        }
 4030
 4031        if self.mode.is_full()
 4032            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4033        {
 4034            return;
 4035        }
 4036
 4037        cx.propagate();
 4038    }
 4039
 4040    pub fn dismiss_menus_and_popups(
 4041        &mut self,
 4042        is_user_requested: bool,
 4043        window: &mut Window,
 4044        cx: &mut Context<Self>,
 4045    ) -> bool {
 4046        if self.take_rename(false, window, cx).is_some() {
 4047            return true;
 4048        }
 4049
 4050        if self.hide_blame_popover(true, cx) {
 4051            return true;
 4052        }
 4053
 4054        if hide_hover(self, cx) {
 4055            return true;
 4056        }
 4057
 4058        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 4059            return true;
 4060        }
 4061
 4062        if self.hide_context_menu(window, cx).is_some() {
 4063            return true;
 4064        }
 4065
 4066        if self.mouse_context_menu.take().is_some() {
 4067            return true;
 4068        }
 4069
 4070        if is_user_requested && self.discard_edit_prediction(true, cx) {
 4071            return true;
 4072        }
 4073
 4074        if self.snippet_stack.pop().is_some() {
 4075            return true;
 4076        }
 4077
 4078        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4079            self.dismiss_diagnostics(cx);
 4080            return true;
 4081        }
 4082
 4083        false
 4084    }
 4085
 4086    fn linked_editing_ranges_for(
 4087        &self,
 4088        selection: Range<text::Anchor>,
 4089        cx: &App,
 4090    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4091        if self.linked_edit_ranges.is_empty() {
 4092            return None;
 4093        }
 4094        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4095            selection.end.buffer_id.and_then(|end_buffer_id| {
 4096                if selection.start.buffer_id != Some(end_buffer_id) {
 4097                    return None;
 4098                }
 4099                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4100                let snapshot = buffer.read(cx).snapshot();
 4101                self.linked_edit_ranges
 4102                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4103                    .map(|ranges| (ranges, snapshot, buffer))
 4104            })?;
 4105        use text::ToOffset as TO;
 4106        // find offset from the start of current range to current cursor position
 4107        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4108
 4109        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4110        let start_difference = start_offset - start_byte_offset;
 4111        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4112        let end_difference = end_offset - start_byte_offset;
 4113        // Current range has associated linked ranges.
 4114        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4115        for range in linked_ranges.iter() {
 4116            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4117            let end_offset = start_offset + end_difference;
 4118            let start_offset = start_offset + start_difference;
 4119            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4120                continue;
 4121            }
 4122            if self.selections.disjoint_anchor_ranges().any(|s| {
 4123                if s.start.buffer_id != selection.start.buffer_id
 4124                    || s.end.buffer_id != selection.end.buffer_id
 4125                {
 4126                    return false;
 4127                }
 4128                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4129                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4130            }) {
 4131                continue;
 4132            }
 4133            let start = buffer_snapshot.anchor_after(start_offset);
 4134            let end = buffer_snapshot.anchor_after(end_offset);
 4135            linked_edits
 4136                .entry(buffer.clone())
 4137                .or_default()
 4138                .push(start..end);
 4139        }
 4140        Some(linked_edits)
 4141    }
 4142
 4143    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4144        let text: Arc<str> = text.into();
 4145
 4146        if self.read_only(cx) {
 4147            return;
 4148        }
 4149
 4150        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4151
 4152        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4153        let mut bracket_inserted = false;
 4154        let mut edits = Vec::new();
 4155        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4156        let mut new_selections = Vec::with_capacity(selections.len());
 4157        let mut new_autoclose_regions = Vec::new();
 4158        let snapshot = self.buffer.read(cx).read(cx);
 4159        let mut clear_linked_edit_ranges = false;
 4160
 4161        for (selection, autoclose_region) in
 4162            self.selections_with_autoclose_regions(selections, &snapshot)
 4163        {
 4164            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4165                // Determine if the inserted text matches the opening or closing
 4166                // bracket of any of this language's bracket pairs.
 4167                let mut bracket_pair = None;
 4168                let mut is_bracket_pair_start = false;
 4169                let mut is_bracket_pair_end = false;
 4170                if !text.is_empty() {
 4171                    let mut bracket_pair_matching_end = None;
 4172                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4173                    //  and they are removing the character that triggered IME popup.
 4174                    for (pair, enabled) in scope.brackets() {
 4175                        if !pair.close && !pair.surround {
 4176                            continue;
 4177                        }
 4178
 4179                        if enabled && pair.start.ends_with(text.as_ref()) {
 4180                            let prefix_len = pair.start.len() - text.len();
 4181                            let preceding_text_matches_prefix = prefix_len == 0
 4182                                || (selection.start.column >= (prefix_len as u32)
 4183                                    && snapshot.contains_str_at(
 4184                                        Point::new(
 4185                                            selection.start.row,
 4186                                            selection.start.column - (prefix_len as u32),
 4187                                        ),
 4188                                        &pair.start[..prefix_len],
 4189                                    ));
 4190                            if preceding_text_matches_prefix {
 4191                                bracket_pair = Some(pair.clone());
 4192                                is_bracket_pair_start = true;
 4193                                break;
 4194                            }
 4195                        }
 4196                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4197                        {
 4198                            // take first bracket pair matching end, but don't break in case a later bracket
 4199                            // pair matches start
 4200                            bracket_pair_matching_end = Some(pair.clone());
 4201                        }
 4202                    }
 4203                    if let Some(end) = bracket_pair_matching_end
 4204                        && bracket_pair.is_none()
 4205                    {
 4206                        bracket_pair = Some(end);
 4207                        is_bracket_pair_end = true;
 4208                    }
 4209                }
 4210
 4211                if let Some(bracket_pair) = bracket_pair {
 4212                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4213                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4214                    let auto_surround =
 4215                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4216                    if selection.is_empty() {
 4217                        if is_bracket_pair_start {
 4218                            // If the inserted text is a suffix of an opening bracket and the
 4219                            // selection is preceded by the rest of the opening bracket, then
 4220                            // insert the closing bracket.
 4221                            let following_text_allows_autoclose = snapshot
 4222                                .chars_at(selection.start)
 4223                                .next()
 4224                                .is_none_or(|c| scope.should_autoclose_before(c));
 4225
 4226                            let preceding_text_allows_autoclose = selection.start.column == 0
 4227                                || snapshot
 4228                                    .reversed_chars_at(selection.start)
 4229                                    .next()
 4230                                    .is_none_or(|c| {
 4231                                        bracket_pair.start != bracket_pair.end
 4232                                            || !snapshot
 4233                                                .char_classifier_at(selection.start)
 4234                                                .is_word(c)
 4235                                    });
 4236
 4237                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4238                                && bracket_pair.start.len() == 1
 4239                            {
 4240                                let target = bracket_pair.start.chars().next().unwrap();
 4241                                let current_line_count = snapshot
 4242                                    .reversed_chars_at(selection.start)
 4243                                    .take_while(|&c| c != '\n')
 4244                                    .filter(|&c| c == target)
 4245                                    .count();
 4246                                current_line_count % 2 == 1
 4247                            } else {
 4248                                false
 4249                            };
 4250
 4251                            if autoclose
 4252                                && bracket_pair.close
 4253                                && following_text_allows_autoclose
 4254                                && preceding_text_allows_autoclose
 4255                                && !is_closing_quote
 4256                            {
 4257                                let anchor = snapshot.anchor_before(selection.end);
 4258                                new_selections.push((selection.map(|_| anchor), text.len()));
 4259                                new_autoclose_regions.push((
 4260                                    anchor,
 4261                                    text.len(),
 4262                                    selection.id,
 4263                                    bracket_pair.clone(),
 4264                                ));
 4265                                edits.push((
 4266                                    selection.range(),
 4267                                    format!("{}{}", text, bracket_pair.end).into(),
 4268                                ));
 4269                                bracket_inserted = true;
 4270                                continue;
 4271                            }
 4272                        }
 4273
 4274                        if let Some(region) = autoclose_region {
 4275                            // If the selection is followed by an auto-inserted closing bracket,
 4276                            // then don't insert that closing bracket again; just move the selection
 4277                            // past the closing bracket.
 4278                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4279                                && text.as_ref() == region.pair.end.as_str()
 4280                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4281                            if should_skip {
 4282                                let anchor = snapshot.anchor_after(selection.end);
 4283                                new_selections
 4284                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4285                                continue;
 4286                            }
 4287                        }
 4288
 4289                        let always_treat_brackets_as_autoclosed = snapshot
 4290                            .language_settings_at(selection.start, cx)
 4291                            .always_treat_brackets_as_autoclosed;
 4292                        if always_treat_brackets_as_autoclosed
 4293                            && is_bracket_pair_end
 4294                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4295                        {
 4296                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4297                            // and the inserted text is a closing bracket and the selection is followed
 4298                            // by the closing bracket then move the selection past the closing bracket.
 4299                            let anchor = snapshot.anchor_after(selection.end);
 4300                            new_selections.push((selection.map(|_| anchor), text.len()));
 4301                            continue;
 4302                        }
 4303                    }
 4304                    // If an opening bracket is 1 character long and is typed while
 4305                    // text is selected, then surround that text with the bracket pair.
 4306                    else if auto_surround
 4307                        && bracket_pair.surround
 4308                        && is_bracket_pair_start
 4309                        && bracket_pair.start.chars().count() == 1
 4310                    {
 4311                        edits.push((selection.start..selection.start, text.clone()));
 4312                        edits.push((
 4313                            selection.end..selection.end,
 4314                            bracket_pair.end.as_str().into(),
 4315                        ));
 4316                        bracket_inserted = true;
 4317                        new_selections.push((
 4318                            Selection {
 4319                                id: selection.id,
 4320                                start: snapshot.anchor_after(selection.start),
 4321                                end: snapshot.anchor_before(selection.end),
 4322                                reversed: selection.reversed,
 4323                                goal: selection.goal,
 4324                            },
 4325                            0,
 4326                        ));
 4327                        continue;
 4328                    }
 4329                }
 4330            }
 4331
 4332            if self.auto_replace_emoji_shortcode
 4333                && selection.is_empty()
 4334                && text.as_ref().ends_with(':')
 4335                && let Some(possible_emoji_short_code) =
 4336                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4337                && !possible_emoji_short_code.is_empty()
 4338                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4339            {
 4340                let emoji_shortcode_start = Point::new(
 4341                    selection.start.row,
 4342                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4343                );
 4344
 4345                // Remove shortcode from buffer
 4346                edits.push((
 4347                    emoji_shortcode_start..selection.start,
 4348                    "".to_string().into(),
 4349                ));
 4350                new_selections.push((
 4351                    Selection {
 4352                        id: selection.id,
 4353                        start: snapshot.anchor_after(emoji_shortcode_start),
 4354                        end: snapshot.anchor_before(selection.start),
 4355                        reversed: selection.reversed,
 4356                        goal: selection.goal,
 4357                    },
 4358                    0,
 4359                ));
 4360
 4361                // Insert emoji
 4362                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4363                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4364                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4365
 4366                continue;
 4367            }
 4368
 4369            // If not handling any auto-close operation, then just replace the selected
 4370            // text with the given input and move the selection to the end of the
 4371            // newly inserted text.
 4372            let anchor = snapshot.anchor_after(selection.end);
 4373            if !self.linked_edit_ranges.is_empty() {
 4374                let start_anchor = snapshot.anchor_before(selection.start);
 4375
 4376                let is_word_char = text.chars().next().is_none_or(|char| {
 4377                    let classifier = snapshot
 4378                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4379                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4380                    classifier.is_word(char)
 4381                });
 4382
 4383                if is_word_char {
 4384                    if let Some(ranges) = self
 4385                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4386                    {
 4387                        for (buffer, edits) in ranges {
 4388                            linked_edits
 4389                                .entry(buffer.clone())
 4390                                .or_default()
 4391                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4392                        }
 4393                    }
 4394                } else {
 4395                    clear_linked_edit_ranges = true;
 4396                }
 4397            }
 4398
 4399            new_selections.push((selection.map(|_| anchor), 0));
 4400            edits.push((selection.start..selection.end, text.clone()));
 4401        }
 4402
 4403        drop(snapshot);
 4404
 4405        self.transact(window, cx, |this, window, cx| {
 4406            if clear_linked_edit_ranges {
 4407                this.linked_edit_ranges.clear();
 4408            }
 4409            let initial_buffer_versions =
 4410                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4411
 4412            this.buffer.update(cx, |buffer, cx| {
 4413                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4414            });
 4415            for (buffer, edits) in linked_edits {
 4416                buffer.update(cx, |buffer, cx| {
 4417                    let snapshot = buffer.snapshot();
 4418                    let edits = edits
 4419                        .into_iter()
 4420                        .map(|(range, text)| {
 4421                            use text::ToPoint as TP;
 4422                            let end_point = TP::to_point(&range.end, &snapshot);
 4423                            let start_point = TP::to_point(&range.start, &snapshot);
 4424                            (start_point..end_point, text)
 4425                        })
 4426                        .sorted_by_key(|(range, _)| range.start);
 4427                    buffer.edit(edits, None, cx);
 4428                })
 4429            }
 4430            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4431            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4432            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4433            let new_selections =
 4434                resolve_selections_wrapping_blocks::<usize, _>(new_anchor_selections, &map)
 4435                    .zip(new_selection_deltas)
 4436                    .map(|(selection, delta)| Selection {
 4437                        id: selection.id,
 4438                        start: selection.start + delta,
 4439                        end: selection.end + delta,
 4440                        reversed: selection.reversed,
 4441                        goal: SelectionGoal::None,
 4442                    })
 4443                    .collect::<Vec<_>>();
 4444
 4445            let mut i = 0;
 4446            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4447                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4448                let start = map.buffer_snapshot().anchor_before(position);
 4449                let end = map.buffer_snapshot().anchor_after(position);
 4450                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4451                    match existing_state
 4452                        .range
 4453                        .start
 4454                        .cmp(&start, map.buffer_snapshot())
 4455                    {
 4456                        Ordering::Less => i += 1,
 4457                        Ordering::Greater => break,
 4458                        Ordering::Equal => {
 4459                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4460                                Ordering::Less => i += 1,
 4461                                Ordering::Equal => break,
 4462                                Ordering::Greater => break,
 4463                            }
 4464                        }
 4465                    }
 4466                }
 4467                this.autoclose_regions.insert(
 4468                    i,
 4469                    AutocloseRegion {
 4470                        selection_id,
 4471                        range: start..end,
 4472                        pair,
 4473                    },
 4474                );
 4475            }
 4476
 4477            let had_active_edit_prediction = this.has_active_edit_prediction();
 4478            this.change_selections(
 4479                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4480                window,
 4481                cx,
 4482                |s| s.select(new_selections),
 4483            );
 4484
 4485            if !bracket_inserted
 4486                && let Some(on_type_format_task) =
 4487                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4488            {
 4489                on_type_format_task.detach_and_log_err(cx);
 4490            }
 4491
 4492            let editor_settings = EditorSettings::get_global(cx);
 4493            if bracket_inserted
 4494                && (editor_settings.auto_signature_help
 4495                    || editor_settings.show_signature_help_after_edits)
 4496            {
 4497                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4498            }
 4499
 4500            let trigger_in_words =
 4501                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4502            if this.hard_wrap.is_some() {
 4503                let latest: Range<Point> = this.selections.newest(&map).range();
 4504                if latest.is_empty()
 4505                    && this
 4506                        .buffer()
 4507                        .read(cx)
 4508                        .snapshot(cx)
 4509                        .line_len(MultiBufferRow(latest.start.row))
 4510                        == latest.start.column
 4511                {
 4512                    this.rewrap_impl(
 4513                        RewrapOptions {
 4514                            override_language_settings: true,
 4515                            preserve_existing_whitespace: true,
 4516                        },
 4517                        cx,
 4518                    )
 4519                }
 4520            }
 4521            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4522            refresh_linked_ranges(this, window, cx);
 4523            this.refresh_edit_prediction(true, false, window, cx);
 4524            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4525        });
 4526    }
 4527
 4528    fn find_possible_emoji_shortcode_at_position(
 4529        snapshot: &MultiBufferSnapshot,
 4530        position: Point,
 4531    ) -> Option<String> {
 4532        let mut chars = Vec::new();
 4533        let mut found_colon = false;
 4534        for char in snapshot.reversed_chars_at(position).take(100) {
 4535            // Found a possible emoji shortcode in the middle of the buffer
 4536            if found_colon {
 4537                if char.is_whitespace() {
 4538                    chars.reverse();
 4539                    return Some(chars.iter().collect());
 4540                }
 4541                // If the previous character is not a whitespace, we are in the middle of a word
 4542                // and we only want to complete the shortcode if the word is made up of other emojis
 4543                let mut containing_word = String::new();
 4544                for ch in snapshot
 4545                    .reversed_chars_at(position)
 4546                    .skip(chars.len() + 1)
 4547                    .take(100)
 4548                {
 4549                    if ch.is_whitespace() {
 4550                        break;
 4551                    }
 4552                    containing_word.push(ch);
 4553                }
 4554                let containing_word = containing_word.chars().rev().collect::<String>();
 4555                if util::word_consists_of_emojis(containing_word.as_str()) {
 4556                    chars.reverse();
 4557                    return Some(chars.iter().collect());
 4558                }
 4559            }
 4560
 4561            if char.is_whitespace() || !char.is_ascii() {
 4562                return None;
 4563            }
 4564            if char == ':' {
 4565                found_colon = true;
 4566            } else {
 4567                chars.push(char);
 4568            }
 4569        }
 4570        // Found a possible emoji shortcode at the beginning of the buffer
 4571        chars.reverse();
 4572        Some(chars.iter().collect())
 4573    }
 4574
 4575    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4576        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4577        self.transact(window, cx, |this, window, cx| {
 4578            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4579                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
 4580                let multi_buffer = this.buffer.read(cx);
 4581                let buffer = multi_buffer.snapshot(cx);
 4582                selections
 4583                    .iter()
 4584                    .map(|selection| {
 4585                        let start_point = selection.start.to_point(&buffer);
 4586                        let mut existing_indent =
 4587                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4588                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4589                        let start = selection.start;
 4590                        let end = selection.end;
 4591                        let selection_is_empty = start == end;
 4592                        let language_scope = buffer.language_scope_at(start);
 4593                        let (
 4594                            comment_delimiter,
 4595                            doc_delimiter,
 4596                            insert_extra_newline,
 4597                            indent_on_newline,
 4598                            indent_on_extra_newline,
 4599                        ) = if let Some(language) = &language_scope {
 4600                            let mut insert_extra_newline =
 4601                                insert_extra_newline_brackets(&buffer, start..end, language)
 4602                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4603
 4604                            // Comment extension on newline is allowed only for cursor selections
 4605                            let comment_delimiter = maybe!({
 4606                                if !selection_is_empty {
 4607                                    return None;
 4608                                }
 4609
 4610                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4611                                    return None;
 4612                                }
 4613
 4614                                let delimiters = language.line_comment_prefixes();
 4615                                let max_len_of_delimiter =
 4616                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4617                                let (snapshot, range) =
 4618                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4619
 4620                                let num_of_whitespaces = snapshot
 4621                                    .chars_for_range(range.clone())
 4622                                    .take_while(|c| c.is_whitespace())
 4623                                    .count();
 4624                                let comment_candidate = snapshot
 4625                                    .chars_for_range(range.clone())
 4626                                    .skip(num_of_whitespaces)
 4627                                    .take(max_len_of_delimiter)
 4628                                    .collect::<String>();
 4629                                let (delimiter, trimmed_len) = delimiters
 4630                                    .iter()
 4631                                    .filter_map(|delimiter| {
 4632                                        let prefix = delimiter.trim_end();
 4633                                        if comment_candidate.starts_with(prefix) {
 4634                                            Some((delimiter, prefix.len()))
 4635                                        } else {
 4636                                            None
 4637                                        }
 4638                                    })
 4639                                    .max_by_key(|(_, len)| *len)?;
 4640
 4641                                if let Some(BlockCommentConfig {
 4642                                    start: block_start, ..
 4643                                }) = language.block_comment()
 4644                                {
 4645                                    let block_start_trimmed = block_start.trim_end();
 4646                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4647                                        let line_content = snapshot
 4648                                            .chars_for_range(range)
 4649                                            .skip(num_of_whitespaces)
 4650                                            .take(block_start_trimmed.len())
 4651                                            .collect::<String>();
 4652
 4653                                        if line_content.starts_with(block_start_trimmed) {
 4654                                            return None;
 4655                                        }
 4656                                    }
 4657                                }
 4658
 4659                                let cursor_is_placed_after_comment_marker =
 4660                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4661                                if cursor_is_placed_after_comment_marker {
 4662                                    Some(delimiter.clone())
 4663                                } else {
 4664                                    None
 4665                                }
 4666                            });
 4667
 4668                            let mut indent_on_newline = IndentSize::spaces(0);
 4669                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4670
 4671                            let doc_delimiter = maybe!({
 4672                                if !selection_is_empty {
 4673                                    return None;
 4674                                }
 4675
 4676                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4677                                    return None;
 4678                                }
 4679
 4680                                let BlockCommentConfig {
 4681                                    start: start_tag,
 4682                                    end: end_tag,
 4683                                    prefix: delimiter,
 4684                                    tab_size: len,
 4685                                } = language.documentation_comment()?;
 4686                                let is_within_block_comment = buffer
 4687                                    .language_scope_at(start_point)
 4688                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4689                                if !is_within_block_comment {
 4690                                    return None;
 4691                                }
 4692
 4693                                let (snapshot, range) =
 4694                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4695
 4696                                let num_of_whitespaces = snapshot
 4697                                    .chars_for_range(range.clone())
 4698                                    .take_while(|c| c.is_whitespace())
 4699                                    .count();
 4700
 4701                                // 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.
 4702                                let column = start_point.column;
 4703                                let cursor_is_after_start_tag = {
 4704                                    let start_tag_len = start_tag.len();
 4705                                    let start_tag_line = snapshot
 4706                                        .chars_for_range(range.clone())
 4707                                        .skip(num_of_whitespaces)
 4708                                        .take(start_tag_len)
 4709                                        .collect::<String>();
 4710                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4711                                        num_of_whitespaces + start_tag_len <= column as usize
 4712                                    } else {
 4713                                        false
 4714                                    }
 4715                                };
 4716
 4717                                let cursor_is_after_delimiter = {
 4718                                    let delimiter_trim = delimiter.trim_end();
 4719                                    let delimiter_line = snapshot
 4720                                        .chars_for_range(range.clone())
 4721                                        .skip(num_of_whitespaces)
 4722                                        .take(delimiter_trim.len())
 4723                                        .collect::<String>();
 4724                                    if delimiter_line.starts_with(delimiter_trim) {
 4725                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4726                                    } else {
 4727                                        false
 4728                                    }
 4729                                };
 4730
 4731                                let cursor_is_before_end_tag_if_exists = {
 4732                                    let mut char_position = 0u32;
 4733                                    let mut end_tag_offset = None;
 4734
 4735                                    'outer: for chunk in snapshot.text_for_range(range) {
 4736                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4737                                            let chars_before_match =
 4738                                                chunk[..byte_pos].chars().count() as u32;
 4739                                            end_tag_offset =
 4740                                                Some(char_position + chars_before_match);
 4741                                            break 'outer;
 4742                                        }
 4743                                        char_position += chunk.chars().count() as u32;
 4744                                    }
 4745
 4746                                    if let Some(end_tag_offset) = end_tag_offset {
 4747                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4748                                        if cursor_is_after_start_tag {
 4749                                            if cursor_is_before_end_tag {
 4750                                                insert_extra_newline = true;
 4751                                            }
 4752                                            let cursor_is_at_start_of_end_tag =
 4753                                                column == end_tag_offset;
 4754                                            if cursor_is_at_start_of_end_tag {
 4755                                                indent_on_extra_newline.len = *len;
 4756                                            }
 4757                                        }
 4758                                        cursor_is_before_end_tag
 4759                                    } else {
 4760                                        true
 4761                                    }
 4762                                };
 4763
 4764                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4765                                    && cursor_is_before_end_tag_if_exists
 4766                                {
 4767                                    if cursor_is_after_start_tag {
 4768                                        indent_on_newline.len = *len;
 4769                                    }
 4770                                    Some(delimiter.clone())
 4771                                } else {
 4772                                    None
 4773                                }
 4774                            });
 4775
 4776                            (
 4777                                comment_delimiter,
 4778                                doc_delimiter,
 4779                                insert_extra_newline,
 4780                                indent_on_newline,
 4781                                indent_on_extra_newline,
 4782                            )
 4783                        } else {
 4784                            (
 4785                                None,
 4786                                None,
 4787                                false,
 4788                                IndentSize::default(),
 4789                                IndentSize::default(),
 4790                            )
 4791                        };
 4792
 4793                        let prevent_auto_indent = doc_delimiter.is_some();
 4794                        let delimiter = comment_delimiter.or(doc_delimiter);
 4795
 4796                        let capacity_for_delimiter =
 4797                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4798                        let mut new_text = String::with_capacity(
 4799                            1 + capacity_for_delimiter
 4800                                + existing_indent.len as usize
 4801                                + indent_on_newline.len as usize
 4802                                + indent_on_extra_newline.len as usize,
 4803                        );
 4804                        new_text.push('\n');
 4805                        new_text.extend(existing_indent.chars());
 4806                        new_text.extend(indent_on_newline.chars());
 4807
 4808                        if let Some(delimiter) = &delimiter {
 4809                            new_text.push_str(delimiter);
 4810                        }
 4811
 4812                        if insert_extra_newline {
 4813                            new_text.push('\n');
 4814                            new_text.extend(existing_indent.chars());
 4815                            new_text.extend(indent_on_extra_newline.chars());
 4816                        }
 4817
 4818                        let anchor = buffer.anchor_after(end);
 4819                        let new_selection = selection.map(|_| anchor);
 4820                        (
 4821                            ((start..end, new_text), prevent_auto_indent),
 4822                            (insert_extra_newline, new_selection),
 4823                        )
 4824                    })
 4825                    .unzip()
 4826            };
 4827
 4828            let mut auto_indent_edits = Vec::new();
 4829            let mut edits = Vec::new();
 4830            for (edit, prevent_auto_indent) in edits_with_flags {
 4831                if prevent_auto_indent {
 4832                    edits.push(edit);
 4833                } else {
 4834                    auto_indent_edits.push(edit);
 4835                }
 4836            }
 4837            if !edits.is_empty() {
 4838                this.edit(edits, cx);
 4839            }
 4840            if !auto_indent_edits.is_empty() {
 4841                this.edit_with_autoindent(auto_indent_edits, cx);
 4842            }
 4843
 4844            let buffer = this.buffer.read(cx).snapshot(cx);
 4845            let new_selections = selection_info
 4846                .into_iter()
 4847                .map(|(extra_newline_inserted, new_selection)| {
 4848                    let mut cursor = new_selection.end.to_point(&buffer);
 4849                    if extra_newline_inserted {
 4850                        cursor.row -= 1;
 4851                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4852                    }
 4853                    new_selection.map(|_| cursor)
 4854                })
 4855                .collect();
 4856
 4857            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4858            this.refresh_edit_prediction(true, false, window, cx);
 4859        });
 4860    }
 4861
 4862    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4863        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4864
 4865        let buffer = self.buffer.read(cx);
 4866        let snapshot = buffer.snapshot(cx);
 4867
 4868        let mut edits = Vec::new();
 4869        let mut rows = Vec::new();
 4870
 4871        for (rows_inserted, selection) in self
 4872            .selections
 4873            .all_adjusted(&self.display_snapshot(cx))
 4874            .into_iter()
 4875            .enumerate()
 4876        {
 4877            let cursor = selection.head();
 4878            let row = cursor.row;
 4879
 4880            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4881
 4882            let newline = "\n".to_string();
 4883            edits.push((start_of_line..start_of_line, newline));
 4884
 4885            rows.push(row + rows_inserted as u32);
 4886        }
 4887
 4888        self.transact(window, cx, |editor, window, cx| {
 4889            editor.edit(edits, cx);
 4890
 4891            editor.change_selections(Default::default(), window, cx, |s| {
 4892                let mut index = 0;
 4893                s.move_cursors_with(|map, _, _| {
 4894                    let row = rows[index];
 4895                    index += 1;
 4896
 4897                    let point = Point::new(row, 0);
 4898                    let boundary = map.next_line_boundary(point).1;
 4899                    let clipped = map.clip_point(boundary, Bias::Left);
 4900
 4901                    (clipped, SelectionGoal::None)
 4902                });
 4903            });
 4904
 4905            let mut indent_edits = Vec::new();
 4906            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4907            for row in rows {
 4908                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4909                for (row, indent) in indents {
 4910                    if indent.len == 0 {
 4911                        continue;
 4912                    }
 4913
 4914                    let text = match indent.kind {
 4915                        IndentKind::Space => " ".repeat(indent.len as usize),
 4916                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4917                    };
 4918                    let point = Point::new(row.0, 0);
 4919                    indent_edits.push((point..point, text));
 4920                }
 4921            }
 4922            editor.edit(indent_edits, cx);
 4923        });
 4924    }
 4925
 4926    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4927        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4928
 4929        let buffer = self.buffer.read(cx);
 4930        let snapshot = buffer.snapshot(cx);
 4931
 4932        let mut edits = Vec::new();
 4933        let mut rows = Vec::new();
 4934        let mut rows_inserted = 0;
 4935
 4936        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 4937            let cursor = selection.head();
 4938            let row = cursor.row;
 4939
 4940            let point = Point::new(row + 1, 0);
 4941            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4942
 4943            let newline = "\n".to_string();
 4944            edits.push((start_of_line..start_of_line, newline));
 4945
 4946            rows_inserted += 1;
 4947            rows.push(row + rows_inserted);
 4948        }
 4949
 4950        self.transact(window, cx, |editor, window, cx| {
 4951            editor.edit(edits, cx);
 4952
 4953            editor.change_selections(Default::default(), window, cx, |s| {
 4954                let mut index = 0;
 4955                s.move_cursors_with(|map, _, _| {
 4956                    let row = rows[index];
 4957                    index += 1;
 4958
 4959                    let point = Point::new(row, 0);
 4960                    let boundary = map.next_line_boundary(point).1;
 4961                    let clipped = map.clip_point(boundary, Bias::Left);
 4962
 4963                    (clipped, SelectionGoal::None)
 4964                });
 4965            });
 4966
 4967            let mut indent_edits = Vec::new();
 4968            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4969            for row in rows {
 4970                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4971                for (row, indent) in indents {
 4972                    if indent.len == 0 {
 4973                        continue;
 4974                    }
 4975
 4976                    let text = match indent.kind {
 4977                        IndentKind::Space => " ".repeat(indent.len as usize),
 4978                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4979                    };
 4980                    let point = Point::new(row.0, 0);
 4981                    indent_edits.push((point..point, text));
 4982                }
 4983            }
 4984            editor.edit(indent_edits, cx);
 4985        });
 4986    }
 4987
 4988    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4989        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4990            original_indent_columns: Vec::new(),
 4991        });
 4992        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4993    }
 4994
 4995    fn insert_with_autoindent_mode(
 4996        &mut self,
 4997        text: &str,
 4998        autoindent_mode: Option<AutoindentMode>,
 4999        window: &mut Window,
 5000        cx: &mut Context<Self>,
 5001    ) {
 5002        if self.read_only(cx) {
 5003            return;
 5004        }
 5005
 5006        let text: Arc<str> = text.into();
 5007        self.transact(window, cx, |this, window, cx| {
 5008            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5009            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5010                let anchors = {
 5011                    let snapshot = buffer.read(cx);
 5012                    old_selections
 5013                        .iter()
 5014                        .map(|s| {
 5015                            let anchor = snapshot.anchor_after(s.head());
 5016                            s.map(|_| anchor)
 5017                        })
 5018                        .collect::<Vec<_>>()
 5019                };
 5020                buffer.edit(
 5021                    old_selections
 5022                        .iter()
 5023                        .map(|s| (s.start..s.end, text.clone())),
 5024                    autoindent_mode,
 5025                    cx,
 5026                );
 5027                anchors
 5028            });
 5029
 5030            this.change_selections(Default::default(), window, cx, |s| {
 5031                s.select_anchors(selection_anchors);
 5032            });
 5033
 5034            cx.notify();
 5035        });
 5036    }
 5037
 5038    fn trigger_completion_on_input(
 5039        &mut self,
 5040        text: &str,
 5041        trigger_in_words: bool,
 5042        window: &mut Window,
 5043        cx: &mut Context<Self>,
 5044    ) {
 5045        let completions_source = self
 5046            .context_menu
 5047            .borrow()
 5048            .as_ref()
 5049            .and_then(|menu| match menu {
 5050                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5051                CodeContextMenu::CodeActions(_) => None,
 5052            });
 5053
 5054        match completions_source {
 5055            Some(CompletionsMenuSource::Words { .. }) => {
 5056                self.open_or_update_completions_menu(
 5057                    Some(CompletionsMenuSource::Words {
 5058                        ignore_threshold: false,
 5059                    }),
 5060                    None,
 5061                    window,
 5062                    cx,
 5063                );
 5064            }
 5065            Some(CompletionsMenuSource::Normal)
 5066            | Some(CompletionsMenuSource::SnippetChoices)
 5067            | None
 5068                if self.is_completion_trigger(
 5069                    text,
 5070                    trigger_in_words,
 5071                    completions_source.is_some(),
 5072                    cx,
 5073                ) =>
 5074            {
 5075                self.show_completions(
 5076                    &ShowCompletions {
 5077                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 5078                    },
 5079                    window,
 5080                    cx,
 5081                )
 5082            }
 5083            _ => {
 5084                self.hide_context_menu(window, cx);
 5085            }
 5086        }
 5087    }
 5088
 5089    fn is_completion_trigger(
 5090        &self,
 5091        text: &str,
 5092        trigger_in_words: bool,
 5093        menu_is_open: bool,
 5094        cx: &mut Context<Self>,
 5095    ) -> bool {
 5096        let position = self.selections.newest_anchor().head();
 5097        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 5098            return false;
 5099        };
 5100
 5101        if let Some(completion_provider) = &self.completion_provider {
 5102            completion_provider.is_completion_trigger(
 5103                &buffer,
 5104                position.text_anchor,
 5105                text,
 5106                trigger_in_words,
 5107                menu_is_open,
 5108                cx,
 5109            )
 5110        } else {
 5111            false
 5112        }
 5113    }
 5114
 5115    /// If any empty selections is touching the start of its innermost containing autoclose
 5116    /// region, expand it to select the brackets.
 5117    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5118        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5119        let buffer = self.buffer.read(cx).read(cx);
 5120        let new_selections = self
 5121            .selections_with_autoclose_regions(selections, &buffer)
 5122            .map(|(mut selection, region)| {
 5123                if !selection.is_empty() {
 5124                    return selection;
 5125                }
 5126
 5127                if let Some(region) = region {
 5128                    let mut range = region.range.to_offset(&buffer);
 5129                    if selection.start == range.start && range.start >= region.pair.start.len() {
 5130                        range.start -= region.pair.start.len();
 5131                        if buffer.contains_str_at(range.start, &region.pair.start)
 5132                            && buffer.contains_str_at(range.end, &region.pair.end)
 5133                        {
 5134                            range.end += region.pair.end.len();
 5135                            selection.start = range.start;
 5136                            selection.end = range.end;
 5137
 5138                            return selection;
 5139                        }
 5140                    }
 5141                }
 5142
 5143                let always_treat_brackets_as_autoclosed = buffer
 5144                    .language_settings_at(selection.start, cx)
 5145                    .always_treat_brackets_as_autoclosed;
 5146
 5147                if !always_treat_brackets_as_autoclosed {
 5148                    return selection;
 5149                }
 5150
 5151                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5152                    for (pair, enabled) in scope.brackets() {
 5153                        if !enabled || !pair.close {
 5154                            continue;
 5155                        }
 5156
 5157                        if buffer.contains_str_at(selection.start, &pair.end) {
 5158                            let pair_start_len = pair.start.len();
 5159                            if buffer.contains_str_at(
 5160                                selection.start.saturating_sub(pair_start_len),
 5161                                &pair.start,
 5162                            ) {
 5163                                selection.start -= pair_start_len;
 5164                                selection.end += pair.end.len();
 5165
 5166                                return selection;
 5167                            }
 5168                        }
 5169                    }
 5170                }
 5171
 5172                selection
 5173            })
 5174            .collect();
 5175
 5176        drop(buffer);
 5177        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5178            selections.select(new_selections)
 5179        });
 5180    }
 5181
 5182    /// Iterate the given selections, and for each one, find the smallest surrounding
 5183    /// autoclose region. This uses the ordering of the selections and the autoclose
 5184    /// regions to avoid repeated comparisons.
 5185    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5186        &'a self,
 5187        selections: impl IntoIterator<Item = Selection<D>>,
 5188        buffer: &'a MultiBufferSnapshot,
 5189    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5190        let mut i = 0;
 5191        let mut regions = self.autoclose_regions.as_slice();
 5192        selections.into_iter().map(move |selection| {
 5193            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5194
 5195            let mut enclosing = None;
 5196            while let Some(pair_state) = regions.get(i) {
 5197                if pair_state.range.end.to_offset(buffer) < range.start {
 5198                    regions = &regions[i + 1..];
 5199                    i = 0;
 5200                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5201                    break;
 5202                } else {
 5203                    if pair_state.selection_id == selection.id {
 5204                        enclosing = Some(pair_state);
 5205                    }
 5206                    i += 1;
 5207                }
 5208            }
 5209
 5210            (selection, enclosing)
 5211        })
 5212    }
 5213
 5214    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5215    fn invalidate_autoclose_regions(
 5216        &mut self,
 5217        mut selections: &[Selection<Anchor>],
 5218        buffer: &MultiBufferSnapshot,
 5219    ) {
 5220        self.autoclose_regions.retain(|state| {
 5221            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5222                return false;
 5223            }
 5224
 5225            let mut i = 0;
 5226            while let Some(selection) = selections.get(i) {
 5227                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5228                    selections = &selections[1..];
 5229                    continue;
 5230                }
 5231                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5232                    break;
 5233                }
 5234                if selection.id == state.selection_id {
 5235                    return true;
 5236                } else {
 5237                    i += 1;
 5238                }
 5239            }
 5240            false
 5241        });
 5242    }
 5243
 5244    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5245        let offset = position.to_offset(buffer);
 5246        let (word_range, kind) =
 5247            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5248        if offset > word_range.start && kind == Some(CharKind::Word) {
 5249            Some(
 5250                buffer
 5251                    .text_for_range(word_range.start..offset)
 5252                    .collect::<String>(),
 5253            )
 5254        } else {
 5255            None
 5256        }
 5257    }
 5258
 5259    pub fn visible_excerpts(
 5260        &self,
 5261        cx: &mut Context<Editor>,
 5262    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5263        let Some(project) = self.project() else {
 5264            return HashMap::default();
 5265        };
 5266        let project = project.read(cx);
 5267        let multi_buffer = self.buffer().read(cx);
 5268        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5269        let multi_buffer_visible_start = self
 5270            .scroll_manager
 5271            .anchor()
 5272            .anchor
 5273            .to_point(&multi_buffer_snapshot);
 5274        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5275            multi_buffer_visible_start
 5276                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5277            Bias::Left,
 5278        );
 5279        multi_buffer_snapshot
 5280            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5281            .into_iter()
 5282            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5283            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5284                let buffer_file = project::File::from_dyn(buffer.file())?;
 5285                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5286                let worktree_entry = buffer_worktree
 5287                    .read(cx)
 5288                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5289                if worktree_entry.is_ignored {
 5290                    None
 5291                } else {
 5292                    Some((
 5293                        excerpt_id,
 5294                        (
 5295                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5296                            buffer.version().clone(),
 5297                            excerpt_visible_range,
 5298                        ),
 5299                    ))
 5300                }
 5301            })
 5302            .collect()
 5303    }
 5304
 5305    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5306        TextLayoutDetails {
 5307            text_system: window.text_system().clone(),
 5308            editor_style: self.style.clone().unwrap(),
 5309            rem_size: window.rem_size(),
 5310            scroll_anchor: self.scroll_manager.anchor(),
 5311            visible_rows: self.visible_line_count(),
 5312            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5313        }
 5314    }
 5315
 5316    fn trigger_on_type_formatting(
 5317        &self,
 5318        input: String,
 5319        window: &mut Window,
 5320        cx: &mut Context<Self>,
 5321    ) -> Option<Task<Result<()>>> {
 5322        if input.len() != 1 {
 5323            return None;
 5324        }
 5325
 5326        let project = self.project()?;
 5327        let position = self.selections.newest_anchor().head();
 5328        let (buffer, buffer_position) = self
 5329            .buffer
 5330            .read(cx)
 5331            .text_anchor_for_position(position, cx)?;
 5332
 5333        let settings = language_settings::language_settings(
 5334            buffer
 5335                .read(cx)
 5336                .language_at(buffer_position)
 5337                .map(|l| l.name()),
 5338            buffer.read(cx).file(),
 5339            cx,
 5340        );
 5341        if !settings.use_on_type_format {
 5342            return None;
 5343        }
 5344
 5345        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5346        // hence we do LSP request & edit on host side only — add formats to host's history.
 5347        let push_to_lsp_host_history = true;
 5348        // If this is not the host, append its history with new edits.
 5349        let push_to_client_history = project.read(cx).is_via_collab();
 5350
 5351        let on_type_formatting = project.update(cx, |project, cx| {
 5352            project.on_type_format(
 5353                buffer.clone(),
 5354                buffer_position,
 5355                input,
 5356                push_to_lsp_host_history,
 5357                cx,
 5358            )
 5359        });
 5360        Some(cx.spawn_in(window, async move |editor, cx| {
 5361            if let Some(transaction) = on_type_formatting.await? {
 5362                if push_to_client_history {
 5363                    buffer
 5364                        .update(cx, |buffer, _| {
 5365                            buffer.push_transaction(transaction, Instant::now());
 5366                            buffer.finalize_last_transaction();
 5367                        })
 5368                        .ok();
 5369                }
 5370                editor.update(cx, |editor, cx| {
 5371                    editor.refresh_document_highlights(cx);
 5372                })?;
 5373            }
 5374            Ok(())
 5375        }))
 5376    }
 5377
 5378    pub fn show_word_completions(
 5379        &mut self,
 5380        _: &ShowWordCompletions,
 5381        window: &mut Window,
 5382        cx: &mut Context<Self>,
 5383    ) {
 5384        self.open_or_update_completions_menu(
 5385            Some(CompletionsMenuSource::Words {
 5386                ignore_threshold: true,
 5387            }),
 5388            None,
 5389            window,
 5390            cx,
 5391        );
 5392    }
 5393
 5394    pub fn show_completions(
 5395        &mut self,
 5396        options: &ShowCompletions,
 5397        window: &mut Window,
 5398        cx: &mut Context<Self>,
 5399    ) {
 5400        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5401    }
 5402
 5403    fn open_or_update_completions_menu(
 5404        &mut self,
 5405        requested_source: Option<CompletionsMenuSource>,
 5406        trigger: Option<&str>,
 5407        window: &mut Window,
 5408        cx: &mut Context<Self>,
 5409    ) {
 5410        if self.pending_rename.is_some() {
 5411            return;
 5412        }
 5413
 5414        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5415
 5416        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5417        // inserted and selected. To handle that case, the start of the selection is used so that
 5418        // the menu starts with all choices.
 5419        let position = self
 5420            .selections
 5421            .newest_anchor()
 5422            .start
 5423            .bias_right(&multibuffer_snapshot);
 5424        if position.diff_base_anchor.is_some() {
 5425            return;
 5426        }
 5427        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5428        let Some(buffer) = buffer_position
 5429            .buffer_id
 5430            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5431        else {
 5432            return;
 5433        };
 5434        let buffer_snapshot = buffer.read(cx).snapshot();
 5435
 5436        let query: Option<Arc<String>> =
 5437            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5438                .map(|query| query.into());
 5439
 5440        drop(multibuffer_snapshot);
 5441
 5442        // Hide the current completions menu when query is empty. Without this, cached
 5443        // completions from before the trigger char may be reused (#32774).
 5444        if query.is_none() {
 5445            let menu_is_open = matches!(
 5446                self.context_menu.borrow().as_ref(),
 5447                Some(CodeContextMenu::Completions(_))
 5448            );
 5449            if menu_is_open {
 5450                self.hide_context_menu(window, cx);
 5451            }
 5452        }
 5453
 5454        let mut ignore_word_threshold = false;
 5455        let provider = match requested_source {
 5456            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5457            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5458                ignore_word_threshold = ignore_threshold;
 5459                None
 5460            }
 5461            Some(CompletionsMenuSource::SnippetChoices) => {
 5462                log::error!("bug: SnippetChoices requested_source is not handled");
 5463                None
 5464            }
 5465        };
 5466
 5467        let sort_completions = provider
 5468            .as_ref()
 5469            .is_some_and(|provider| provider.sort_completions());
 5470
 5471        let filter_completions = provider
 5472            .as_ref()
 5473            .is_none_or(|provider| provider.filter_completions());
 5474
 5475        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5476            if filter_completions {
 5477                menu.filter(query.clone(), provider.clone(), window, cx);
 5478            }
 5479            // When `is_incomplete` is false, no need to re-query completions when the current query
 5480            // is a suffix of the initial query.
 5481            if !menu.is_incomplete {
 5482                // If the new query is a suffix of the old query (typing more characters) and
 5483                // the previous result was complete, the existing completions can be filtered.
 5484                //
 5485                // Note that this is always true for snippet completions.
 5486                let query_matches = match (&menu.initial_query, &query) {
 5487                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5488                    (None, _) => true,
 5489                    _ => false,
 5490                };
 5491                if query_matches {
 5492                    let position_matches = if menu.initial_position == position {
 5493                        true
 5494                    } else {
 5495                        let snapshot = self.buffer.read(cx).read(cx);
 5496                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5497                    };
 5498                    if position_matches {
 5499                        return;
 5500                    }
 5501                }
 5502            }
 5503        };
 5504
 5505        let trigger_kind = match trigger {
 5506            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5507                CompletionTriggerKind::TRIGGER_CHARACTER
 5508            }
 5509            _ => CompletionTriggerKind::INVOKED,
 5510        };
 5511        let completion_context = CompletionContext {
 5512            trigger_character: trigger.and_then(|trigger| {
 5513                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5514                    Some(String::from(trigger))
 5515                } else {
 5516                    None
 5517                }
 5518            }),
 5519            trigger_kind,
 5520        };
 5521
 5522        let Anchor {
 5523            excerpt_id: buffer_excerpt_id,
 5524            text_anchor: buffer_position,
 5525            ..
 5526        } = buffer_position;
 5527
 5528        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5529            buffer_snapshot.surrounding_word(buffer_position, None)
 5530        {
 5531            let word_to_exclude = buffer_snapshot
 5532                .text_for_range(word_range.clone())
 5533                .collect::<String>();
 5534            (
 5535                buffer_snapshot.anchor_before(word_range.start)
 5536                    ..buffer_snapshot.anchor_after(buffer_position),
 5537                Some(word_to_exclude),
 5538            )
 5539        } else {
 5540            (buffer_position..buffer_position, None)
 5541        };
 5542
 5543        let language = buffer_snapshot
 5544            .language_at(buffer_position)
 5545            .map(|language| language.name());
 5546
 5547        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5548            .completions
 5549            .clone();
 5550
 5551        let show_completion_documentation = buffer_snapshot
 5552            .settings_at(buffer_position, cx)
 5553            .show_completion_documentation;
 5554
 5555        // The document can be large, so stay in reasonable bounds when searching for words,
 5556        // otherwise completion pop-up might be slow to appear.
 5557        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5558        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5559        let min_word_search = buffer_snapshot.clip_point(
 5560            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5561            Bias::Left,
 5562        );
 5563        let max_word_search = buffer_snapshot.clip_point(
 5564            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5565            Bias::Right,
 5566        );
 5567        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5568            ..buffer_snapshot.point_to_offset(max_word_search);
 5569
 5570        let skip_digits = query
 5571            .as_ref()
 5572            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5573
 5574        let omit_word_completions = !self.word_completions_enabled
 5575            || (!ignore_word_threshold
 5576                && match &query {
 5577                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5578                    None => completion_settings.words_min_length != 0,
 5579                });
 5580
 5581        let (mut words, provider_responses) = match &provider {
 5582            Some(provider) => {
 5583                let provider_responses = provider.completions(
 5584                    buffer_excerpt_id,
 5585                    &buffer,
 5586                    buffer_position,
 5587                    completion_context,
 5588                    window,
 5589                    cx,
 5590                );
 5591
 5592                let words = match (omit_word_completions, completion_settings.words) {
 5593                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5594                        Task::ready(BTreeMap::default())
 5595                    }
 5596                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5597                        .background_spawn(async move {
 5598                            buffer_snapshot.words_in_range(WordsQuery {
 5599                                fuzzy_contents: None,
 5600                                range: word_search_range,
 5601                                skip_digits,
 5602                            })
 5603                        }),
 5604                };
 5605
 5606                (words, provider_responses)
 5607            }
 5608            None => {
 5609                let words = if omit_word_completions {
 5610                    Task::ready(BTreeMap::default())
 5611                } else {
 5612                    cx.background_spawn(async move {
 5613                        buffer_snapshot.words_in_range(WordsQuery {
 5614                            fuzzy_contents: None,
 5615                            range: word_search_range,
 5616                            skip_digits,
 5617                        })
 5618                    })
 5619                };
 5620                (words, Task::ready(Ok(Vec::new())))
 5621            }
 5622        };
 5623
 5624        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5625
 5626        let id = post_inc(&mut self.next_completion_id);
 5627        let task = cx.spawn_in(window, async move |editor, cx| {
 5628            let Ok(()) = editor.update(cx, |this, _| {
 5629                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5630            }) else {
 5631                return;
 5632            };
 5633
 5634            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5635            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5636            let mut completions = Vec::new();
 5637            let mut is_incomplete = false;
 5638            let mut display_options: Option<CompletionDisplayOptions> = None;
 5639            if let Some(provider_responses) = provider_responses.await.log_err()
 5640                && !provider_responses.is_empty()
 5641            {
 5642                for response in provider_responses {
 5643                    completions.extend(response.completions);
 5644                    is_incomplete = is_incomplete || response.is_incomplete;
 5645                    match display_options.as_mut() {
 5646                        None => {
 5647                            display_options = Some(response.display_options);
 5648                        }
 5649                        Some(options) => options.merge(&response.display_options),
 5650                    }
 5651                }
 5652                if completion_settings.words == WordsCompletionMode::Fallback {
 5653                    words = Task::ready(BTreeMap::default());
 5654                }
 5655            }
 5656            let display_options = display_options.unwrap_or_default();
 5657
 5658            let mut words = words.await;
 5659            if let Some(word_to_exclude) = &word_to_exclude {
 5660                words.remove(word_to_exclude);
 5661            }
 5662            for lsp_completion in &completions {
 5663                words.remove(&lsp_completion.new_text);
 5664            }
 5665            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5666                replace_range: word_replace_range.clone(),
 5667                new_text: word.clone(),
 5668                label: CodeLabel::plain(word, None),
 5669                icon_path: None,
 5670                documentation: None,
 5671                source: CompletionSource::BufferWord {
 5672                    word_range,
 5673                    resolved: false,
 5674                },
 5675                insert_text_mode: Some(InsertTextMode::AS_IS),
 5676                confirm: None,
 5677            }));
 5678
 5679            let menu = if completions.is_empty() {
 5680                None
 5681            } else {
 5682                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5683                    let languages = editor
 5684                        .workspace
 5685                        .as_ref()
 5686                        .and_then(|(workspace, _)| workspace.upgrade())
 5687                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5688                    let menu = CompletionsMenu::new(
 5689                        id,
 5690                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5691                        sort_completions,
 5692                        show_completion_documentation,
 5693                        position,
 5694                        query.clone(),
 5695                        is_incomplete,
 5696                        buffer.clone(),
 5697                        completions.into(),
 5698                        display_options,
 5699                        snippet_sort_order,
 5700                        languages,
 5701                        language,
 5702                        cx,
 5703                    );
 5704
 5705                    let query = if filter_completions { query } else { None };
 5706                    let matches_task = if let Some(query) = query {
 5707                        menu.do_async_filtering(query, cx)
 5708                    } else {
 5709                        Task::ready(menu.unfiltered_matches())
 5710                    };
 5711                    (menu, matches_task)
 5712                }) else {
 5713                    return;
 5714                };
 5715
 5716                let matches = matches_task.await;
 5717
 5718                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5719                    // Newer menu already set, so exit.
 5720                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5721                        editor.context_menu.borrow().as_ref()
 5722                        && prev_menu.id > id
 5723                    {
 5724                        return;
 5725                    };
 5726
 5727                    // Only valid to take prev_menu because it the new menu is immediately set
 5728                    // below, or the menu is hidden.
 5729                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5730                        editor.context_menu.borrow_mut().take()
 5731                    {
 5732                        let position_matches =
 5733                            if prev_menu.initial_position == menu.initial_position {
 5734                                true
 5735                            } else {
 5736                                let snapshot = editor.buffer.read(cx).read(cx);
 5737                                prev_menu.initial_position.to_offset(&snapshot)
 5738                                    == menu.initial_position.to_offset(&snapshot)
 5739                            };
 5740                        if position_matches {
 5741                            // Preserve markdown cache before `set_filter_results` because it will
 5742                            // try to populate the documentation cache.
 5743                            menu.preserve_markdown_cache(prev_menu);
 5744                        }
 5745                    };
 5746
 5747                    menu.set_filter_results(matches, provider, window, cx);
 5748                }) else {
 5749                    return;
 5750                };
 5751
 5752                menu.visible().then_some(menu)
 5753            };
 5754
 5755            editor
 5756                .update_in(cx, |editor, window, cx| {
 5757                    if editor.focus_handle.is_focused(window)
 5758                        && let Some(menu) = menu
 5759                    {
 5760                        *editor.context_menu.borrow_mut() =
 5761                            Some(CodeContextMenu::Completions(menu));
 5762
 5763                        crate::hover_popover::hide_hover(editor, cx);
 5764                        if editor.show_edit_predictions_in_menu() {
 5765                            editor.update_visible_edit_prediction(window, cx);
 5766                        } else {
 5767                            editor.discard_edit_prediction(false, cx);
 5768                        }
 5769
 5770                        cx.notify();
 5771                        return;
 5772                    }
 5773
 5774                    if editor.completion_tasks.len() <= 1 {
 5775                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5776                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5777                        // If it was already hidden and we don't show edit predictions in the menu,
 5778                        // we should also show the edit prediction when available.
 5779                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5780                            editor.update_visible_edit_prediction(window, cx);
 5781                        }
 5782                    }
 5783                })
 5784                .ok();
 5785        });
 5786
 5787        self.completion_tasks.push((id, task));
 5788    }
 5789
 5790    #[cfg(feature = "test-support")]
 5791    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5792        let menu = self.context_menu.borrow();
 5793        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5794            let completions = menu.completions.borrow();
 5795            Some(completions.to_vec())
 5796        } else {
 5797            None
 5798        }
 5799    }
 5800
 5801    pub fn with_completions_menu_matching_id<R>(
 5802        &self,
 5803        id: CompletionId,
 5804        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5805    ) -> R {
 5806        let mut context_menu = self.context_menu.borrow_mut();
 5807        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5808            return f(None);
 5809        };
 5810        if completions_menu.id != id {
 5811            return f(None);
 5812        }
 5813        f(Some(completions_menu))
 5814    }
 5815
 5816    pub fn confirm_completion(
 5817        &mut self,
 5818        action: &ConfirmCompletion,
 5819        window: &mut Window,
 5820        cx: &mut Context<Self>,
 5821    ) -> Option<Task<Result<()>>> {
 5822        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5823        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5824    }
 5825
 5826    pub fn confirm_completion_insert(
 5827        &mut self,
 5828        _: &ConfirmCompletionInsert,
 5829        window: &mut Window,
 5830        cx: &mut Context<Self>,
 5831    ) -> Option<Task<Result<()>>> {
 5832        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5833        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5834    }
 5835
 5836    pub fn confirm_completion_replace(
 5837        &mut self,
 5838        _: &ConfirmCompletionReplace,
 5839        window: &mut Window,
 5840        cx: &mut Context<Self>,
 5841    ) -> Option<Task<Result<()>>> {
 5842        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5843        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5844    }
 5845
 5846    pub fn compose_completion(
 5847        &mut self,
 5848        action: &ComposeCompletion,
 5849        window: &mut Window,
 5850        cx: &mut Context<Self>,
 5851    ) -> Option<Task<Result<()>>> {
 5852        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5853        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5854    }
 5855
 5856    fn do_completion(
 5857        &mut self,
 5858        item_ix: Option<usize>,
 5859        intent: CompletionIntent,
 5860        window: &mut Window,
 5861        cx: &mut Context<Editor>,
 5862    ) -> Option<Task<Result<()>>> {
 5863        use language::ToOffset as _;
 5864
 5865        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5866        else {
 5867            return None;
 5868        };
 5869
 5870        let candidate_id = {
 5871            let entries = completions_menu.entries.borrow();
 5872            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5873            if self.show_edit_predictions_in_menu() {
 5874                self.discard_edit_prediction(true, cx);
 5875            }
 5876            mat.candidate_id
 5877        };
 5878
 5879        let completion = completions_menu
 5880            .completions
 5881            .borrow()
 5882            .get(candidate_id)?
 5883            .clone();
 5884        cx.stop_propagation();
 5885
 5886        let buffer_handle = completions_menu.buffer.clone();
 5887
 5888        let CompletionEdit {
 5889            new_text,
 5890            snippet,
 5891            replace_range,
 5892        } = process_completion_for_edit(
 5893            &completion,
 5894            intent,
 5895            &buffer_handle,
 5896            &completions_menu.initial_position.text_anchor,
 5897            cx,
 5898        );
 5899
 5900        let buffer = buffer_handle.read(cx);
 5901        let snapshot = self.buffer.read(cx).snapshot(cx);
 5902        let newest_anchor = self.selections.newest_anchor();
 5903        let replace_range_multibuffer = {
 5904            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5905            excerpt.map_range_from_buffer(replace_range.clone())
 5906        };
 5907        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5908            return None;
 5909        }
 5910
 5911        let old_text = buffer
 5912            .text_for_range(replace_range.clone())
 5913            .collect::<String>();
 5914        let lookbehind = newest_anchor
 5915            .start
 5916            .text_anchor
 5917            .to_offset(buffer)
 5918            .saturating_sub(replace_range.start);
 5919        let lookahead = replace_range
 5920            .end
 5921            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5922        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5923        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5924
 5925        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5926        let mut ranges = Vec::new();
 5927        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5928
 5929        for selection in &selections {
 5930            let range = if selection.id == newest_anchor.id {
 5931                replace_range_multibuffer.clone()
 5932            } else {
 5933                let mut range = selection.range();
 5934
 5935                // if prefix is present, don't duplicate it
 5936                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5937                    range.start = range.start.saturating_sub(lookbehind);
 5938
 5939                    // if suffix is also present, mimic the newest cursor and replace it
 5940                    if selection.id != newest_anchor.id
 5941                        && snapshot.contains_str_at(range.end, suffix)
 5942                    {
 5943                        range.end += lookahead;
 5944                    }
 5945                }
 5946                range
 5947            };
 5948
 5949            ranges.push(range.clone());
 5950
 5951            if !self.linked_edit_ranges.is_empty() {
 5952                let start_anchor = snapshot.anchor_before(range.start);
 5953                let end_anchor = snapshot.anchor_after(range.end);
 5954                if let Some(ranges) = self
 5955                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5956                {
 5957                    for (buffer, edits) in ranges {
 5958                        linked_edits
 5959                            .entry(buffer.clone())
 5960                            .or_default()
 5961                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5962                    }
 5963                }
 5964            }
 5965        }
 5966
 5967        let common_prefix_len = old_text
 5968            .chars()
 5969            .zip(new_text.chars())
 5970            .take_while(|(a, b)| a == b)
 5971            .map(|(a, _)| a.len_utf8())
 5972            .sum::<usize>();
 5973
 5974        cx.emit(EditorEvent::InputHandled {
 5975            utf16_range_to_replace: None,
 5976            text: new_text[common_prefix_len..].into(),
 5977        });
 5978
 5979        self.transact(window, cx, |editor, window, cx| {
 5980            if let Some(mut snippet) = snippet {
 5981                snippet.text = new_text.to_string();
 5982                editor
 5983                    .insert_snippet(&ranges, snippet, window, cx)
 5984                    .log_err();
 5985            } else {
 5986                editor.buffer.update(cx, |multi_buffer, cx| {
 5987                    let auto_indent = match completion.insert_text_mode {
 5988                        Some(InsertTextMode::AS_IS) => None,
 5989                        _ => editor.autoindent_mode.clone(),
 5990                    };
 5991                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5992                    multi_buffer.edit(edits, auto_indent, cx);
 5993                });
 5994            }
 5995            for (buffer, edits) in linked_edits {
 5996                buffer.update(cx, |buffer, cx| {
 5997                    let snapshot = buffer.snapshot();
 5998                    let edits = edits
 5999                        .into_iter()
 6000                        .map(|(range, text)| {
 6001                            use text::ToPoint as TP;
 6002                            let end_point = TP::to_point(&range.end, &snapshot);
 6003                            let start_point = TP::to_point(&range.start, &snapshot);
 6004                            (start_point..end_point, text)
 6005                        })
 6006                        .sorted_by_key(|(range, _)| range.start);
 6007                    buffer.edit(edits, None, cx);
 6008                })
 6009            }
 6010
 6011            editor.refresh_edit_prediction(true, false, window, cx);
 6012        });
 6013        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6014
 6015        let show_new_completions_on_confirm = completion
 6016            .confirm
 6017            .as_ref()
 6018            .is_some_and(|confirm| confirm(intent, window, cx));
 6019        if show_new_completions_on_confirm {
 6020            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6021        }
 6022
 6023        let provider = self.completion_provider.as_ref()?;
 6024        drop(completion);
 6025        let apply_edits = provider.apply_additional_edits_for_completion(
 6026            buffer_handle,
 6027            completions_menu.completions.clone(),
 6028            candidate_id,
 6029            true,
 6030            cx,
 6031        );
 6032
 6033        let editor_settings = EditorSettings::get_global(cx);
 6034        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6035            // After the code completion is finished, users often want to know what signatures are needed.
 6036            // so we should automatically call signature_help
 6037            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6038        }
 6039
 6040        Some(cx.foreground_executor().spawn(async move {
 6041            apply_edits.await?;
 6042            Ok(())
 6043        }))
 6044    }
 6045
 6046    pub fn toggle_code_actions(
 6047        &mut self,
 6048        action: &ToggleCodeActions,
 6049        window: &mut Window,
 6050        cx: &mut Context<Self>,
 6051    ) {
 6052        let quick_launch = action.quick_launch;
 6053        let mut context_menu = self.context_menu.borrow_mut();
 6054        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6055            if code_actions.deployed_from == action.deployed_from {
 6056                // Toggle if we're selecting the same one
 6057                *context_menu = None;
 6058                cx.notify();
 6059                return;
 6060            } else {
 6061                // Otherwise, clear it and start a new one
 6062                *context_menu = None;
 6063                cx.notify();
 6064            }
 6065        }
 6066        drop(context_menu);
 6067        let snapshot = self.snapshot(window, cx);
 6068        let deployed_from = action.deployed_from.clone();
 6069        let action = action.clone();
 6070        self.completion_tasks.clear();
 6071        self.discard_edit_prediction(false, cx);
 6072
 6073        let multibuffer_point = match &action.deployed_from {
 6074            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6075                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6076            }
 6077            _ => self
 6078                .selections
 6079                .newest::<Point>(&snapshot.display_snapshot)
 6080                .head(),
 6081        };
 6082        let Some((buffer, buffer_row)) = snapshot
 6083            .buffer_snapshot()
 6084            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6085            .and_then(|(buffer_snapshot, range)| {
 6086                self.buffer()
 6087                    .read(cx)
 6088                    .buffer(buffer_snapshot.remote_id())
 6089                    .map(|buffer| (buffer, range.start.row))
 6090            })
 6091        else {
 6092            return;
 6093        };
 6094        let buffer_id = buffer.read(cx).remote_id();
 6095        let tasks = self
 6096            .tasks
 6097            .get(&(buffer_id, buffer_row))
 6098            .map(|t| Arc::new(t.to_owned()));
 6099
 6100        if !self.focus_handle.is_focused(window) {
 6101            return;
 6102        }
 6103        let project = self.project.clone();
 6104
 6105        let code_actions_task = match deployed_from {
 6106            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6107            _ => self.code_actions(buffer_row, window, cx),
 6108        };
 6109
 6110        let runnable_task = match deployed_from {
 6111            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6112            _ => {
 6113                let mut task_context_task = Task::ready(None);
 6114                if let Some(tasks) = &tasks
 6115                    && let Some(project) = project
 6116                {
 6117                    task_context_task =
 6118                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6119                }
 6120
 6121                cx.spawn_in(window, {
 6122                    let buffer = buffer.clone();
 6123                    async move |editor, cx| {
 6124                        let task_context = task_context_task.await;
 6125
 6126                        let resolved_tasks =
 6127                            tasks
 6128                                .zip(task_context.clone())
 6129                                .map(|(tasks, task_context)| ResolvedTasks {
 6130                                    templates: tasks.resolve(&task_context).collect(),
 6131                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6132                                        multibuffer_point.row,
 6133                                        tasks.column,
 6134                                    )),
 6135                                });
 6136                        let debug_scenarios = editor
 6137                            .update(cx, |editor, cx| {
 6138                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6139                            })?
 6140                            .await;
 6141                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6142                    }
 6143                })
 6144            }
 6145        };
 6146
 6147        cx.spawn_in(window, async move |editor, cx| {
 6148            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6149            let code_actions = code_actions_task.await;
 6150            let spawn_straight_away = quick_launch
 6151                && resolved_tasks
 6152                    .as_ref()
 6153                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6154                && code_actions
 6155                    .as_ref()
 6156                    .is_none_or(|actions| actions.is_empty())
 6157                && debug_scenarios.is_empty();
 6158
 6159            editor.update_in(cx, |editor, window, cx| {
 6160                crate::hover_popover::hide_hover(editor, cx);
 6161                let actions = CodeActionContents::new(
 6162                    resolved_tasks,
 6163                    code_actions,
 6164                    debug_scenarios,
 6165                    task_context.unwrap_or_default(),
 6166                );
 6167
 6168                // Don't show the menu if there are no actions available
 6169                if actions.is_empty() {
 6170                    cx.notify();
 6171                    return Task::ready(Ok(()));
 6172                }
 6173
 6174                *editor.context_menu.borrow_mut() =
 6175                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6176                        buffer,
 6177                        actions,
 6178                        selected_item: Default::default(),
 6179                        scroll_handle: UniformListScrollHandle::default(),
 6180                        deployed_from,
 6181                    }));
 6182                cx.notify();
 6183                if spawn_straight_away
 6184                    && let Some(task) = editor.confirm_code_action(
 6185                        &ConfirmCodeAction { item_ix: Some(0) },
 6186                        window,
 6187                        cx,
 6188                    )
 6189                {
 6190                    return task;
 6191                }
 6192
 6193                Task::ready(Ok(()))
 6194            })
 6195        })
 6196        .detach_and_log_err(cx);
 6197    }
 6198
 6199    fn debug_scenarios(
 6200        &mut self,
 6201        resolved_tasks: &Option<ResolvedTasks>,
 6202        buffer: &Entity<Buffer>,
 6203        cx: &mut App,
 6204    ) -> Task<Vec<task::DebugScenario>> {
 6205        maybe!({
 6206            let project = self.project()?;
 6207            let dap_store = project.read(cx).dap_store();
 6208            let mut scenarios = vec![];
 6209            let resolved_tasks = resolved_tasks.as_ref()?;
 6210            let buffer = buffer.read(cx);
 6211            let language = buffer.language()?;
 6212            let file = buffer.file();
 6213            let debug_adapter = language_settings(language.name().into(), file, cx)
 6214                .debuggers
 6215                .first()
 6216                .map(SharedString::from)
 6217                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6218
 6219            dap_store.update(cx, |dap_store, cx| {
 6220                for (_, task) in &resolved_tasks.templates {
 6221                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6222                        task.original_task().clone(),
 6223                        debug_adapter.clone().into(),
 6224                        task.display_label().to_owned().into(),
 6225                        cx,
 6226                    );
 6227                    scenarios.push(maybe_scenario);
 6228                }
 6229            });
 6230            Some(cx.background_spawn(async move {
 6231                futures::future::join_all(scenarios)
 6232                    .await
 6233                    .into_iter()
 6234                    .flatten()
 6235                    .collect::<Vec<_>>()
 6236            }))
 6237        })
 6238        .unwrap_or_else(|| Task::ready(vec![]))
 6239    }
 6240
 6241    fn code_actions(
 6242        &mut self,
 6243        buffer_row: u32,
 6244        window: &mut Window,
 6245        cx: &mut Context<Self>,
 6246    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6247        let mut task = self.code_actions_task.take();
 6248        cx.spawn_in(window, async move |editor, cx| {
 6249            while let Some(prev_task) = task {
 6250                prev_task.await.log_err();
 6251                task = editor
 6252                    .update(cx, |this, _| this.code_actions_task.take())
 6253                    .ok()?;
 6254            }
 6255
 6256            editor
 6257                .update(cx, |editor, cx| {
 6258                    editor
 6259                        .available_code_actions
 6260                        .clone()
 6261                        .and_then(|(location, code_actions)| {
 6262                            let snapshot = location.buffer.read(cx).snapshot();
 6263                            let point_range = location.range.to_point(&snapshot);
 6264                            let point_range = point_range.start.row..=point_range.end.row;
 6265                            if point_range.contains(&buffer_row) {
 6266                                Some(code_actions)
 6267                            } else {
 6268                                None
 6269                            }
 6270                        })
 6271                })
 6272                .ok()
 6273                .flatten()
 6274        })
 6275    }
 6276
 6277    pub fn confirm_code_action(
 6278        &mut self,
 6279        action: &ConfirmCodeAction,
 6280        window: &mut Window,
 6281        cx: &mut Context<Self>,
 6282    ) -> Option<Task<Result<()>>> {
 6283        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6284
 6285        let actions_menu =
 6286            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6287                menu
 6288            } else {
 6289                return None;
 6290            };
 6291
 6292        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6293        let action = actions_menu.actions.get(action_ix)?;
 6294        let title = action.label();
 6295        let buffer = actions_menu.buffer;
 6296        let workspace = self.workspace()?;
 6297
 6298        match action {
 6299            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6300                workspace.update(cx, |workspace, cx| {
 6301                    workspace.schedule_resolved_task(
 6302                        task_source_kind,
 6303                        resolved_task,
 6304                        false,
 6305                        window,
 6306                        cx,
 6307                    );
 6308
 6309                    Some(Task::ready(Ok(())))
 6310                })
 6311            }
 6312            CodeActionsItem::CodeAction {
 6313                excerpt_id,
 6314                action,
 6315                provider,
 6316            } => {
 6317                let apply_code_action =
 6318                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6319                let workspace = workspace.downgrade();
 6320                Some(cx.spawn_in(window, async move |editor, cx| {
 6321                    let project_transaction = apply_code_action.await?;
 6322                    Self::open_project_transaction(
 6323                        &editor,
 6324                        workspace,
 6325                        project_transaction,
 6326                        title,
 6327                        cx,
 6328                    )
 6329                    .await
 6330                }))
 6331            }
 6332            CodeActionsItem::DebugScenario(scenario) => {
 6333                let context = actions_menu.actions.context;
 6334
 6335                workspace.update(cx, |workspace, cx| {
 6336                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6337                    workspace.start_debug_session(
 6338                        scenario,
 6339                        context,
 6340                        Some(buffer),
 6341                        None,
 6342                        window,
 6343                        cx,
 6344                    );
 6345                });
 6346                Some(Task::ready(Ok(())))
 6347            }
 6348        }
 6349    }
 6350
 6351    pub async fn open_project_transaction(
 6352        editor: &WeakEntity<Editor>,
 6353        workspace: WeakEntity<Workspace>,
 6354        transaction: ProjectTransaction,
 6355        title: String,
 6356        cx: &mut AsyncWindowContext,
 6357    ) -> Result<()> {
 6358        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6359        cx.update(|_, cx| {
 6360            entries.sort_unstable_by_key(|(buffer, _)| {
 6361                buffer.read(cx).file().map(|f| f.path().clone())
 6362            });
 6363        })?;
 6364        if entries.is_empty() {
 6365            return Ok(());
 6366        }
 6367
 6368        // If the project transaction's edits are all contained within this editor, then
 6369        // avoid opening a new editor to display them.
 6370
 6371        if let [(buffer, transaction)] = &*entries {
 6372            let excerpt = editor.update(cx, |editor, cx| {
 6373                editor
 6374                    .buffer()
 6375                    .read(cx)
 6376                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6377            })?;
 6378            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6379                && excerpted_buffer == *buffer
 6380            {
 6381                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6382                    let excerpt_range = excerpt_range.to_offset(buffer);
 6383                    buffer
 6384                        .edited_ranges_for_transaction::<usize>(transaction)
 6385                        .all(|range| {
 6386                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6387                        })
 6388                })?;
 6389
 6390                if all_edits_within_excerpt {
 6391                    return Ok(());
 6392                }
 6393            }
 6394        }
 6395
 6396        let mut ranges_to_highlight = Vec::new();
 6397        let excerpt_buffer = cx.new(|cx| {
 6398            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6399            for (buffer_handle, transaction) in &entries {
 6400                let edited_ranges = buffer_handle
 6401                    .read(cx)
 6402                    .edited_ranges_for_transaction::<Point>(transaction)
 6403                    .collect::<Vec<_>>();
 6404                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6405                    PathKey::for_buffer(buffer_handle, cx),
 6406                    buffer_handle.clone(),
 6407                    edited_ranges,
 6408                    multibuffer_context_lines(cx),
 6409                    cx,
 6410                );
 6411
 6412                ranges_to_highlight.extend(ranges);
 6413            }
 6414            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6415            multibuffer
 6416        })?;
 6417
 6418        workspace.update_in(cx, |workspace, window, cx| {
 6419            let project = workspace.project().clone();
 6420            let editor =
 6421                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6422            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6423            editor.update(cx, |editor, cx| {
 6424                editor.highlight_background::<Self>(
 6425                    &ranges_to_highlight,
 6426                    |theme| theme.colors().editor_highlighted_line_background,
 6427                    cx,
 6428                );
 6429            });
 6430        })?;
 6431
 6432        Ok(())
 6433    }
 6434
 6435    pub fn clear_code_action_providers(&mut self) {
 6436        self.code_action_providers.clear();
 6437        self.available_code_actions.take();
 6438    }
 6439
 6440    pub fn add_code_action_provider(
 6441        &mut self,
 6442        provider: Rc<dyn CodeActionProvider>,
 6443        window: &mut Window,
 6444        cx: &mut Context<Self>,
 6445    ) {
 6446        if self
 6447            .code_action_providers
 6448            .iter()
 6449            .any(|existing_provider| existing_provider.id() == provider.id())
 6450        {
 6451            return;
 6452        }
 6453
 6454        self.code_action_providers.push(provider);
 6455        self.refresh_code_actions(window, cx);
 6456    }
 6457
 6458    pub fn remove_code_action_provider(
 6459        &mut self,
 6460        id: Arc<str>,
 6461        window: &mut Window,
 6462        cx: &mut Context<Self>,
 6463    ) {
 6464        self.code_action_providers
 6465            .retain(|provider| provider.id() != id);
 6466        self.refresh_code_actions(window, cx);
 6467    }
 6468
 6469    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6470        !self.code_action_providers.is_empty()
 6471            && EditorSettings::get_global(cx).toolbar.code_actions
 6472    }
 6473
 6474    pub fn has_available_code_actions(&self) -> bool {
 6475        self.available_code_actions
 6476            .as_ref()
 6477            .is_some_and(|(_, actions)| !actions.is_empty())
 6478    }
 6479
 6480    fn render_inline_code_actions(
 6481        &self,
 6482        icon_size: ui::IconSize,
 6483        display_row: DisplayRow,
 6484        is_active: bool,
 6485        cx: &mut Context<Self>,
 6486    ) -> AnyElement {
 6487        let show_tooltip = !self.context_menu_visible();
 6488        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6489            .icon_size(icon_size)
 6490            .shape(ui::IconButtonShape::Square)
 6491            .icon_color(ui::Color::Hidden)
 6492            .toggle_state(is_active)
 6493            .when(show_tooltip, |this| {
 6494                this.tooltip({
 6495                    let focus_handle = self.focus_handle.clone();
 6496                    move |_window, cx| {
 6497                        Tooltip::for_action_in(
 6498                            "Toggle Code Actions",
 6499                            &ToggleCodeActions {
 6500                                deployed_from: None,
 6501                                quick_launch: false,
 6502                            },
 6503                            &focus_handle,
 6504                            cx,
 6505                        )
 6506                    }
 6507                })
 6508            })
 6509            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6510                window.focus(&editor.focus_handle(cx));
 6511                editor.toggle_code_actions(
 6512                    &crate::actions::ToggleCodeActions {
 6513                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6514                            display_row,
 6515                        )),
 6516                        quick_launch: false,
 6517                    },
 6518                    window,
 6519                    cx,
 6520                );
 6521            }))
 6522            .into_any_element()
 6523    }
 6524
 6525    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6526        &self.context_menu
 6527    }
 6528
 6529    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6530        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6531            cx.background_executor()
 6532                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6533                .await;
 6534
 6535            let (start_buffer, start, _, end, newest_selection) = this
 6536                .update(cx, |this, cx| {
 6537                    let newest_selection = this.selections.newest_anchor().clone();
 6538                    if newest_selection.head().diff_base_anchor.is_some() {
 6539                        return None;
 6540                    }
 6541                    let display_snapshot = this.display_snapshot(cx);
 6542                    let newest_selection_adjusted =
 6543                        this.selections.newest_adjusted(&display_snapshot);
 6544                    let buffer = this.buffer.read(cx);
 6545
 6546                    let (start_buffer, start) =
 6547                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6548                    let (end_buffer, end) =
 6549                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6550
 6551                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6552                })?
 6553                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6554                .context(
 6555                    "Expected selection to lie in a single buffer when refreshing code actions",
 6556                )?;
 6557            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6558                let providers = this.code_action_providers.clone();
 6559                let tasks = this
 6560                    .code_action_providers
 6561                    .iter()
 6562                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6563                    .collect::<Vec<_>>();
 6564                (providers, tasks)
 6565            })?;
 6566
 6567            let mut actions = Vec::new();
 6568            for (provider, provider_actions) in
 6569                providers.into_iter().zip(future::join_all(tasks).await)
 6570            {
 6571                if let Some(provider_actions) = provider_actions.log_err() {
 6572                    actions.extend(provider_actions.into_iter().map(|action| {
 6573                        AvailableCodeAction {
 6574                            excerpt_id: newest_selection.start.excerpt_id,
 6575                            action,
 6576                            provider: provider.clone(),
 6577                        }
 6578                    }));
 6579                }
 6580            }
 6581
 6582            this.update(cx, |this, cx| {
 6583                this.available_code_actions = if actions.is_empty() {
 6584                    None
 6585                } else {
 6586                    Some((
 6587                        Location {
 6588                            buffer: start_buffer,
 6589                            range: start..end,
 6590                        },
 6591                        actions.into(),
 6592                    ))
 6593                };
 6594                cx.notify();
 6595            })
 6596        }));
 6597    }
 6598
 6599    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6600        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6601            self.show_git_blame_inline = false;
 6602
 6603            self.show_git_blame_inline_delay_task =
 6604                Some(cx.spawn_in(window, async move |this, cx| {
 6605                    cx.background_executor().timer(delay).await;
 6606
 6607                    this.update(cx, |this, cx| {
 6608                        this.show_git_blame_inline = true;
 6609                        cx.notify();
 6610                    })
 6611                    .log_err();
 6612                }));
 6613        }
 6614    }
 6615
 6616    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6617        let snapshot = self.snapshot(window, cx);
 6618        let cursor = self
 6619            .selections
 6620            .newest::<Point>(&snapshot.display_snapshot)
 6621            .head();
 6622        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6623        else {
 6624            return;
 6625        };
 6626
 6627        let Some(blame) = self.blame.as_ref() else {
 6628            return;
 6629        };
 6630
 6631        let row_info = RowInfo {
 6632            buffer_id: Some(buffer.remote_id()),
 6633            buffer_row: Some(point.row),
 6634            ..Default::default()
 6635        };
 6636        let Some((buffer, blame_entry)) = blame
 6637            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6638            .flatten()
 6639        else {
 6640            return;
 6641        };
 6642
 6643        let anchor = self.selections.newest_anchor().head();
 6644        let position = self.to_pixel_point(anchor, &snapshot, window);
 6645        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6646            self.show_blame_popover(
 6647                buffer,
 6648                &blame_entry,
 6649                position + last_bounds.origin,
 6650                true,
 6651                cx,
 6652            );
 6653        };
 6654    }
 6655
 6656    fn show_blame_popover(
 6657        &mut self,
 6658        buffer: BufferId,
 6659        blame_entry: &BlameEntry,
 6660        position: gpui::Point<Pixels>,
 6661        ignore_timeout: bool,
 6662        cx: &mut Context<Self>,
 6663    ) {
 6664        if let Some(state) = &mut self.inline_blame_popover {
 6665            state.hide_task.take();
 6666        } else {
 6667            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6668            let blame_entry = blame_entry.clone();
 6669            let show_task = cx.spawn(async move |editor, cx| {
 6670                if !ignore_timeout {
 6671                    cx.background_executor()
 6672                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6673                        .await;
 6674                }
 6675                editor
 6676                    .update(cx, |editor, cx| {
 6677                        editor.inline_blame_popover_show_task.take();
 6678                        let Some(blame) = editor.blame.as_ref() else {
 6679                            return;
 6680                        };
 6681                        let blame = blame.read(cx);
 6682                        let details = blame.details_for_entry(buffer, &blame_entry);
 6683                        let markdown = cx.new(|cx| {
 6684                            Markdown::new(
 6685                                details
 6686                                    .as_ref()
 6687                                    .map(|message| message.message.clone())
 6688                                    .unwrap_or_default(),
 6689                                None,
 6690                                None,
 6691                                cx,
 6692                            )
 6693                        });
 6694                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6695                            position,
 6696                            hide_task: None,
 6697                            popover_bounds: None,
 6698                            popover_state: InlineBlamePopoverState {
 6699                                scroll_handle: ScrollHandle::new(),
 6700                                commit_message: details,
 6701                                markdown,
 6702                            },
 6703                            keyboard_grace: ignore_timeout,
 6704                        });
 6705                        cx.notify();
 6706                    })
 6707                    .ok();
 6708            });
 6709            self.inline_blame_popover_show_task = Some(show_task);
 6710        }
 6711    }
 6712
 6713    fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6714        self.inline_blame_popover_show_task.take();
 6715        if let Some(state) = &mut self.inline_blame_popover {
 6716            let hide_task = cx.spawn(async move |editor, cx| {
 6717                if !ignore_timeout {
 6718                    cx.background_executor()
 6719                        .timer(std::time::Duration::from_millis(100))
 6720                        .await;
 6721                }
 6722                editor
 6723                    .update(cx, |editor, cx| {
 6724                        editor.inline_blame_popover.take();
 6725                        cx.notify();
 6726                    })
 6727                    .ok();
 6728            });
 6729            state.hide_task = Some(hide_task);
 6730            true
 6731        } else {
 6732            false
 6733        }
 6734    }
 6735
 6736    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6737        if self.pending_rename.is_some() {
 6738            return None;
 6739        }
 6740
 6741        let provider = self.semantics_provider.clone()?;
 6742        let buffer = self.buffer.read(cx);
 6743        let newest_selection = self.selections.newest_anchor().clone();
 6744        let cursor_position = newest_selection.head();
 6745        let (cursor_buffer, cursor_buffer_position) =
 6746            buffer.text_anchor_for_position(cursor_position, cx)?;
 6747        let (tail_buffer, tail_buffer_position) =
 6748            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6749        if cursor_buffer != tail_buffer {
 6750            return None;
 6751        }
 6752
 6753        let snapshot = cursor_buffer.read(cx).snapshot();
 6754        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6755        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6756        if start_word_range != end_word_range {
 6757            self.document_highlights_task.take();
 6758            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6759            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6760            return None;
 6761        }
 6762
 6763        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 6764        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6765            cx.background_executor()
 6766                .timer(Duration::from_millis(debounce))
 6767                .await;
 6768
 6769            let highlights = if let Some(highlights) = cx
 6770                .update(|cx| {
 6771                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6772                })
 6773                .ok()
 6774                .flatten()
 6775            {
 6776                highlights.await.log_err()
 6777            } else {
 6778                None
 6779            };
 6780
 6781            if let Some(highlights) = highlights {
 6782                this.update(cx, |this, cx| {
 6783                    if this.pending_rename.is_some() {
 6784                        return;
 6785                    }
 6786
 6787                    let buffer = this.buffer.read(cx);
 6788                    if buffer
 6789                        .text_anchor_for_position(cursor_position, cx)
 6790                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6791                    {
 6792                        return;
 6793                    }
 6794
 6795                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6796                    let mut write_ranges = Vec::new();
 6797                    let mut read_ranges = Vec::new();
 6798                    for highlight in highlights {
 6799                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6800                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6801                        {
 6802                            let start = highlight
 6803                                .range
 6804                                .start
 6805                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6806                            let end = highlight
 6807                                .range
 6808                                .end
 6809                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6810                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6811                                continue;
 6812                            }
 6813
 6814                            let range =
 6815                                Anchor::range_in_buffer(excerpt_id, buffer_id, *start..*end);
 6816                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6817                                write_ranges.push(range);
 6818                            } else {
 6819                                read_ranges.push(range);
 6820                            }
 6821                        }
 6822                    }
 6823
 6824                    this.highlight_background::<DocumentHighlightRead>(
 6825                        &read_ranges,
 6826                        |theme| theme.colors().editor_document_highlight_read_background,
 6827                        cx,
 6828                    );
 6829                    this.highlight_background::<DocumentHighlightWrite>(
 6830                        &write_ranges,
 6831                        |theme| theme.colors().editor_document_highlight_write_background,
 6832                        cx,
 6833                    );
 6834                    cx.notify();
 6835                })
 6836                .log_err();
 6837            }
 6838        }));
 6839        None
 6840    }
 6841
 6842    fn prepare_highlight_query_from_selection(
 6843        &mut self,
 6844        window: &Window,
 6845        cx: &mut Context<Editor>,
 6846    ) -> Option<(String, Range<Anchor>)> {
 6847        if matches!(self.mode, EditorMode::SingleLine) {
 6848            return None;
 6849        }
 6850        if !EditorSettings::get_global(cx).selection_highlight {
 6851            return None;
 6852        }
 6853        if self.selections.count() != 1 || self.selections.line_mode() {
 6854            return None;
 6855        }
 6856        let snapshot = self.snapshot(window, cx);
 6857        let selection = self.selections.newest::<Point>(&snapshot);
 6858        // If the selection spans multiple rows OR it is empty
 6859        if selection.start.row != selection.end.row
 6860            || selection.start.column == selection.end.column
 6861        {
 6862            return None;
 6863        }
 6864        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 6865        let query = snapshot
 6866            .buffer_snapshot()
 6867            .text_for_range(selection_anchor_range.clone())
 6868            .collect::<String>();
 6869        if query.trim().is_empty() {
 6870            return None;
 6871        }
 6872        Some((query, selection_anchor_range))
 6873    }
 6874
 6875    fn update_selection_occurrence_highlights(
 6876        &mut self,
 6877        query_text: String,
 6878        query_range: Range<Anchor>,
 6879        multi_buffer_range_to_query: Range<Point>,
 6880        use_debounce: bool,
 6881        window: &mut Window,
 6882        cx: &mut Context<Editor>,
 6883    ) -> Task<()> {
 6884        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6885        cx.spawn_in(window, async move |editor, cx| {
 6886            if use_debounce {
 6887                cx.background_executor()
 6888                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6889                    .await;
 6890            }
 6891            let match_task = cx.background_spawn(async move {
 6892                let buffer_ranges = multi_buffer_snapshot
 6893                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6894                    .into_iter()
 6895                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6896                let mut match_ranges = Vec::new();
 6897                let Ok(regex) = project::search::SearchQuery::text(
 6898                    query_text.clone(),
 6899                    false,
 6900                    false,
 6901                    false,
 6902                    Default::default(),
 6903                    Default::default(),
 6904                    false,
 6905                    None,
 6906                ) else {
 6907                    return Vec::default();
 6908                };
 6909                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 6910                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6911                    match_ranges.extend(
 6912                        regex
 6913                            .search(buffer_snapshot, Some(search_range.clone()))
 6914                            .await
 6915                            .into_iter()
 6916                            .filter_map(|match_range| {
 6917                                let match_start = buffer_snapshot
 6918                                    .anchor_after(search_range.start + match_range.start);
 6919                                let match_end = buffer_snapshot
 6920                                    .anchor_before(search_range.start + match_range.end);
 6921                                let match_anchor_range = Anchor::range_in_buffer(
 6922                                    excerpt_id,
 6923                                    buffer_snapshot.remote_id(),
 6924                                    match_start..match_end,
 6925                                );
 6926                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6927                            }),
 6928                    );
 6929                }
 6930                match_ranges
 6931            });
 6932            let match_ranges = match_task.await;
 6933            editor
 6934                .update_in(cx, |editor, _, cx| {
 6935                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6936                    if !match_ranges.is_empty() {
 6937                        editor.highlight_background::<SelectedTextHighlight>(
 6938                            &match_ranges,
 6939                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6940                            cx,
 6941                        )
 6942                    }
 6943                })
 6944                .log_err();
 6945        })
 6946    }
 6947
 6948    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6949        struct NewlineFold;
 6950        let type_id = std::any::TypeId::of::<NewlineFold>();
 6951        if !self.mode.is_single_line() {
 6952            return;
 6953        }
 6954        let snapshot = self.snapshot(window, cx);
 6955        if snapshot.buffer_snapshot().max_point().row == 0 {
 6956            return;
 6957        }
 6958        let task = cx.background_spawn(async move {
 6959            let new_newlines = snapshot
 6960                .buffer_chars_at(0)
 6961                .filter_map(|(c, i)| {
 6962                    if c == '\n' {
 6963                        Some(
 6964                            snapshot.buffer_snapshot().anchor_after(i)
 6965                                ..snapshot.buffer_snapshot().anchor_before(i + 1),
 6966                        )
 6967                    } else {
 6968                        None
 6969                    }
 6970                })
 6971                .collect::<Vec<_>>();
 6972            let existing_newlines = snapshot
 6973                .folds_in_range(0..snapshot.buffer_snapshot().len())
 6974                .filter_map(|fold| {
 6975                    if fold.placeholder.type_tag == Some(type_id) {
 6976                        Some(fold.range.start..fold.range.end)
 6977                    } else {
 6978                        None
 6979                    }
 6980                })
 6981                .collect::<Vec<_>>();
 6982
 6983            (new_newlines, existing_newlines)
 6984        });
 6985        self.folding_newlines = cx.spawn(async move |this, cx| {
 6986            let (new_newlines, existing_newlines) = task.await;
 6987            if new_newlines == existing_newlines {
 6988                return;
 6989            }
 6990            let placeholder = FoldPlaceholder {
 6991                render: Arc::new(move |_, _, cx| {
 6992                    div()
 6993                        .bg(cx.theme().status().hint_background)
 6994                        .border_b_1()
 6995                        .size_full()
 6996                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6997                        .border_color(cx.theme().status().hint)
 6998                        .child("\\n")
 6999                        .into_any()
 7000                }),
 7001                constrain_width: false,
 7002                merge_adjacent: false,
 7003                type_tag: Some(type_id),
 7004            };
 7005            let creases = new_newlines
 7006                .into_iter()
 7007                .map(|range| Crease::simple(range, placeholder.clone()))
 7008                .collect();
 7009            this.update(cx, |this, cx| {
 7010                this.display_map.update(cx, |display_map, cx| {
 7011                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7012                    display_map.fold(creases, cx);
 7013                });
 7014            })
 7015            .ok();
 7016        });
 7017    }
 7018
 7019    fn refresh_selected_text_highlights(
 7020        &mut self,
 7021        on_buffer_edit: bool,
 7022        window: &mut Window,
 7023        cx: &mut Context<Editor>,
 7024    ) {
 7025        let Some((query_text, query_range)) =
 7026            self.prepare_highlight_query_from_selection(window, cx)
 7027        else {
 7028            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7029            self.quick_selection_highlight_task.take();
 7030            self.debounced_selection_highlight_task.take();
 7031            return;
 7032        };
 7033        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7034        if on_buffer_edit
 7035            || self
 7036                .quick_selection_highlight_task
 7037                .as_ref()
 7038                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7039        {
 7040            let multi_buffer_visible_start = self
 7041                .scroll_manager
 7042                .anchor()
 7043                .anchor
 7044                .to_point(&multi_buffer_snapshot);
 7045            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7046                multi_buffer_visible_start
 7047                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7048                Bias::Left,
 7049            );
 7050            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7051            self.quick_selection_highlight_task = Some((
 7052                query_range.clone(),
 7053                self.update_selection_occurrence_highlights(
 7054                    query_text.clone(),
 7055                    query_range.clone(),
 7056                    multi_buffer_visible_range,
 7057                    false,
 7058                    window,
 7059                    cx,
 7060                ),
 7061            ));
 7062        }
 7063        if on_buffer_edit
 7064            || self
 7065                .debounced_selection_highlight_task
 7066                .as_ref()
 7067                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7068        {
 7069            let multi_buffer_start = multi_buffer_snapshot
 7070                .anchor_before(0)
 7071                .to_point(&multi_buffer_snapshot);
 7072            let multi_buffer_end = multi_buffer_snapshot
 7073                .anchor_after(multi_buffer_snapshot.len())
 7074                .to_point(&multi_buffer_snapshot);
 7075            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7076            self.debounced_selection_highlight_task = Some((
 7077                query_range.clone(),
 7078                self.update_selection_occurrence_highlights(
 7079                    query_text,
 7080                    query_range,
 7081                    multi_buffer_full_range,
 7082                    true,
 7083                    window,
 7084                    cx,
 7085                ),
 7086            ));
 7087        }
 7088    }
 7089
 7090    pub fn refresh_edit_prediction(
 7091        &mut self,
 7092        debounce: bool,
 7093        user_requested: bool,
 7094        window: &mut Window,
 7095        cx: &mut Context<Self>,
 7096    ) -> Option<()> {
 7097        if DisableAiSettings::get_global(cx).disable_ai {
 7098            return None;
 7099        }
 7100
 7101        let provider = self.edit_prediction_provider()?;
 7102        let cursor = self.selections.newest_anchor().head();
 7103        let (buffer, cursor_buffer_position) =
 7104            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7105
 7106        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7107            self.discard_edit_prediction(false, cx);
 7108            return None;
 7109        }
 7110
 7111        self.update_visible_edit_prediction(window, cx);
 7112
 7113        if !user_requested
 7114            && (!self.should_show_edit_predictions()
 7115                || !self.is_focused(window)
 7116                || buffer.read(cx).is_empty())
 7117        {
 7118            self.discard_edit_prediction(false, cx);
 7119            return None;
 7120        }
 7121
 7122        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7123        Some(())
 7124    }
 7125
 7126    fn show_edit_predictions_in_menu(&self) -> bool {
 7127        match self.edit_prediction_settings {
 7128            EditPredictionSettings::Disabled => false,
 7129            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7130        }
 7131    }
 7132
 7133    pub fn edit_predictions_enabled(&self) -> bool {
 7134        match self.edit_prediction_settings {
 7135            EditPredictionSettings::Disabled => false,
 7136            EditPredictionSettings::Enabled { .. } => true,
 7137        }
 7138    }
 7139
 7140    fn edit_prediction_requires_modifier(&self) -> bool {
 7141        match self.edit_prediction_settings {
 7142            EditPredictionSettings::Disabled => false,
 7143            EditPredictionSettings::Enabled {
 7144                preview_requires_modifier,
 7145                ..
 7146            } => preview_requires_modifier,
 7147        }
 7148    }
 7149
 7150    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7151        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7152            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7153            self.discard_edit_prediction(false, cx);
 7154        } else {
 7155            let selection = self.selections.newest_anchor();
 7156            let cursor = selection.head();
 7157
 7158            if let Some((buffer, cursor_buffer_position)) =
 7159                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7160            {
 7161                self.edit_prediction_settings =
 7162                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7163            }
 7164        }
 7165    }
 7166
 7167    fn edit_prediction_settings_at_position(
 7168        &self,
 7169        buffer: &Entity<Buffer>,
 7170        buffer_position: language::Anchor,
 7171        cx: &App,
 7172    ) -> EditPredictionSettings {
 7173        if !self.mode.is_full()
 7174            || !self.show_edit_predictions_override.unwrap_or(true)
 7175            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7176        {
 7177            return EditPredictionSettings::Disabled;
 7178        }
 7179
 7180        let buffer = buffer.read(cx);
 7181
 7182        let file = buffer.file();
 7183
 7184        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7185            return EditPredictionSettings::Disabled;
 7186        };
 7187
 7188        let by_provider = matches!(
 7189            self.menu_edit_predictions_policy,
 7190            MenuEditPredictionsPolicy::ByProvider
 7191        );
 7192
 7193        let show_in_menu = by_provider
 7194            && self
 7195                .edit_prediction_provider
 7196                .as_ref()
 7197                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7198
 7199        let preview_requires_modifier =
 7200            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7201
 7202        EditPredictionSettings::Enabled {
 7203            show_in_menu,
 7204            preview_requires_modifier,
 7205        }
 7206    }
 7207
 7208    fn should_show_edit_predictions(&self) -> bool {
 7209        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7210    }
 7211
 7212    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7213        matches!(
 7214            self.edit_prediction_preview,
 7215            EditPredictionPreview::Active { .. }
 7216        )
 7217    }
 7218
 7219    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7220        let cursor = self.selections.newest_anchor().head();
 7221        if let Some((buffer, cursor_position)) =
 7222            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7223        {
 7224            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7225        } else {
 7226            false
 7227        }
 7228    }
 7229
 7230    pub fn supports_minimap(&self, cx: &App) -> bool {
 7231        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7232    }
 7233
 7234    fn edit_predictions_enabled_in_buffer(
 7235        &self,
 7236        buffer: &Entity<Buffer>,
 7237        buffer_position: language::Anchor,
 7238        cx: &App,
 7239    ) -> bool {
 7240        maybe!({
 7241            if self.read_only(cx) {
 7242                return Some(false);
 7243            }
 7244            let provider = self.edit_prediction_provider()?;
 7245            if !provider.is_enabled(buffer, buffer_position, cx) {
 7246                return Some(false);
 7247            }
 7248            let buffer = buffer.read(cx);
 7249            let Some(file) = buffer.file() else {
 7250                return Some(true);
 7251            };
 7252            let settings = all_language_settings(Some(file), cx);
 7253            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7254        })
 7255        .unwrap_or(false)
 7256    }
 7257
 7258    fn cycle_edit_prediction(
 7259        &mut self,
 7260        direction: Direction,
 7261        window: &mut Window,
 7262        cx: &mut Context<Self>,
 7263    ) -> Option<()> {
 7264        let provider = self.edit_prediction_provider()?;
 7265        let cursor = self.selections.newest_anchor().head();
 7266        let (buffer, cursor_buffer_position) =
 7267            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7268        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7269            return None;
 7270        }
 7271
 7272        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7273        self.update_visible_edit_prediction(window, cx);
 7274
 7275        Some(())
 7276    }
 7277
 7278    pub fn show_edit_prediction(
 7279        &mut self,
 7280        _: &ShowEditPrediction,
 7281        window: &mut Window,
 7282        cx: &mut Context<Self>,
 7283    ) {
 7284        if !self.has_active_edit_prediction() {
 7285            self.refresh_edit_prediction(false, true, window, cx);
 7286            return;
 7287        }
 7288
 7289        self.update_visible_edit_prediction(window, cx);
 7290    }
 7291
 7292    pub fn display_cursor_names(
 7293        &mut self,
 7294        _: &DisplayCursorNames,
 7295        window: &mut Window,
 7296        cx: &mut Context<Self>,
 7297    ) {
 7298        self.show_cursor_names(window, cx);
 7299    }
 7300
 7301    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7302        self.show_cursor_names = true;
 7303        cx.notify();
 7304        cx.spawn_in(window, async move |this, cx| {
 7305            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7306            this.update(cx, |this, cx| {
 7307                this.show_cursor_names = false;
 7308                cx.notify()
 7309            })
 7310            .ok()
 7311        })
 7312        .detach();
 7313    }
 7314
 7315    pub fn next_edit_prediction(
 7316        &mut self,
 7317        _: &NextEditPrediction,
 7318        window: &mut Window,
 7319        cx: &mut Context<Self>,
 7320    ) {
 7321        if self.has_active_edit_prediction() {
 7322            self.cycle_edit_prediction(Direction::Next, window, cx);
 7323        } else {
 7324            let is_copilot_disabled = self
 7325                .refresh_edit_prediction(false, true, window, cx)
 7326                .is_none();
 7327            if is_copilot_disabled {
 7328                cx.propagate();
 7329            }
 7330        }
 7331    }
 7332
 7333    pub fn previous_edit_prediction(
 7334        &mut self,
 7335        _: &PreviousEditPrediction,
 7336        window: &mut Window,
 7337        cx: &mut Context<Self>,
 7338    ) {
 7339        if self.has_active_edit_prediction() {
 7340            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7341        } else {
 7342            let is_copilot_disabled = self
 7343                .refresh_edit_prediction(false, true, window, cx)
 7344                .is_none();
 7345            if is_copilot_disabled {
 7346                cx.propagate();
 7347            }
 7348        }
 7349    }
 7350
 7351    pub fn accept_edit_prediction(
 7352        &mut self,
 7353        _: &AcceptEditPrediction,
 7354        window: &mut Window,
 7355        cx: &mut Context<Self>,
 7356    ) {
 7357        if self.show_edit_predictions_in_menu() {
 7358            self.hide_context_menu(window, cx);
 7359        }
 7360
 7361        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7362            return;
 7363        };
 7364
 7365        match &active_edit_prediction.completion {
 7366            EditPrediction::MoveWithin { target, .. } => {
 7367                let target = *target;
 7368
 7369                if let Some(position_map) = &self.last_position_map {
 7370                    if position_map
 7371                        .visible_row_range
 7372                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7373                        || !self.edit_prediction_requires_modifier()
 7374                    {
 7375                        self.unfold_ranges(&[target..target], true, false, cx);
 7376                        // Note that this is also done in vim's handler of the Tab action.
 7377                        self.change_selections(
 7378                            SelectionEffects::scroll(Autoscroll::newest()),
 7379                            window,
 7380                            cx,
 7381                            |selections| {
 7382                                selections.select_anchor_ranges([target..target]);
 7383                            },
 7384                        );
 7385                        self.clear_row_highlights::<EditPredictionPreview>();
 7386
 7387                        self.edit_prediction_preview
 7388                            .set_previous_scroll_position(None);
 7389                    } else {
 7390                        self.edit_prediction_preview
 7391                            .set_previous_scroll_position(Some(
 7392                                position_map.snapshot.scroll_anchor,
 7393                            ));
 7394
 7395                        self.highlight_rows::<EditPredictionPreview>(
 7396                            target..target,
 7397                            cx.theme().colors().editor_highlighted_line_background,
 7398                            RowHighlightOptions {
 7399                                autoscroll: true,
 7400                                ..Default::default()
 7401                            },
 7402                            cx,
 7403                        );
 7404                        self.request_autoscroll(Autoscroll::fit(), cx);
 7405                    }
 7406                }
 7407            }
 7408            EditPrediction::MoveOutside { snapshot, target } => {
 7409                if let Some(workspace) = self.workspace() {
 7410                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7411                        .detach_and_log_err(cx);
 7412                }
 7413            }
 7414            EditPrediction::Edit { edits, .. } => {
 7415                self.report_edit_prediction_event(
 7416                    active_edit_prediction.completion_id.clone(),
 7417                    true,
 7418                    cx,
 7419                );
 7420
 7421                if let Some(provider) = self.edit_prediction_provider() {
 7422                    provider.accept(cx);
 7423                }
 7424
 7425                // Store the transaction ID and selections before applying the edit
 7426                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7427
 7428                let snapshot = self.buffer.read(cx).snapshot(cx);
 7429                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7430
 7431                self.buffer.update(cx, |buffer, cx| {
 7432                    buffer.edit(edits.iter().cloned(), None, cx)
 7433                });
 7434
 7435                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7436                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7437                });
 7438
 7439                let selections = self.selections.disjoint_anchors_arc();
 7440                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7441                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7442                    if has_new_transaction {
 7443                        self.selection_history
 7444                            .insert_transaction(transaction_id_now, selections);
 7445                    }
 7446                }
 7447
 7448                self.update_visible_edit_prediction(window, cx);
 7449                if self.active_edit_prediction.is_none() {
 7450                    self.refresh_edit_prediction(true, true, window, cx);
 7451                }
 7452
 7453                cx.notify();
 7454            }
 7455        }
 7456
 7457        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7458    }
 7459
 7460    pub fn accept_partial_edit_prediction(
 7461        &mut self,
 7462        _: &AcceptPartialEditPrediction,
 7463        window: &mut Window,
 7464        cx: &mut Context<Self>,
 7465    ) {
 7466        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7467            return;
 7468        };
 7469        if self.selections.count() != 1 {
 7470            return;
 7471        }
 7472
 7473        match &active_edit_prediction.completion {
 7474            EditPrediction::MoveWithin { target, .. } => {
 7475                let target = *target;
 7476                self.change_selections(
 7477                    SelectionEffects::scroll(Autoscroll::newest()),
 7478                    window,
 7479                    cx,
 7480                    |selections| {
 7481                        selections.select_anchor_ranges([target..target]);
 7482                    },
 7483                );
 7484            }
 7485            EditPrediction::MoveOutside { snapshot, target } => {
 7486                if let Some(workspace) = self.workspace() {
 7487                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7488                        .detach_and_log_err(cx);
 7489                }
 7490            }
 7491            EditPrediction::Edit { edits, .. } => {
 7492                self.report_edit_prediction_event(
 7493                    active_edit_prediction.completion_id.clone(),
 7494                    true,
 7495                    cx,
 7496                );
 7497
 7498                // Find an insertion that starts at the cursor position.
 7499                let snapshot = self.buffer.read(cx).snapshot(cx);
 7500                let cursor_offset = self
 7501                    .selections
 7502                    .newest::<usize>(&self.display_snapshot(cx))
 7503                    .head();
 7504                let insertion = edits.iter().find_map(|(range, text)| {
 7505                    let range = range.to_offset(&snapshot);
 7506                    if range.is_empty() && range.start == cursor_offset {
 7507                        Some(text)
 7508                    } else {
 7509                        None
 7510                    }
 7511                });
 7512
 7513                if let Some(text) = insertion {
 7514                    let mut partial_completion = text
 7515                        .chars()
 7516                        .by_ref()
 7517                        .take_while(|c| c.is_alphabetic())
 7518                        .collect::<String>();
 7519                    if partial_completion.is_empty() {
 7520                        partial_completion = text
 7521                            .chars()
 7522                            .by_ref()
 7523                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7524                            .collect::<String>();
 7525                    }
 7526
 7527                    cx.emit(EditorEvent::InputHandled {
 7528                        utf16_range_to_replace: None,
 7529                        text: partial_completion.clone().into(),
 7530                    });
 7531
 7532                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7533
 7534                    self.refresh_edit_prediction(true, true, window, cx);
 7535                    cx.notify();
 7536                } else {
 7537                    self.accept_edit_prediction(&Default::default(), window, cx);
 7538                }
 7539            }
 7540        }
 7541    }
 7542
 7543    fn discard_edit_prediction(
 7544        &mut self,
 7545        should_report_edit_prediction_event: bool,
 7546        cx: &mut Context<Self>,
 7547    ) -> bool {
 7548        if should_report_edit_prediction_event {
 7549            let completion_id = self
 7550                .active_edit_prediction
 7551                .as_ref()
 7552                .and_then(|active_completion| active_completion.completion_id.clone());
 7553
 7554            self.report_edit_prediction_event(completion_id, false, cx);
 7555        }
 7556
 7557        if let Some(provider) = self.edit_prediction_provider() {
 7558            provider.discard(cx);
 7559        }
 7560
 7561        self.take_active_edit_prediction(cx)
 7562    }
 7563
 7564    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7565        let Some(provider) = self.edit_prediction_provider() else {
 7566            return;
 7567        };
 7568
 7569        let Some((_, buffer, _)) = self
 7570            .buffer
 7571            .read(cx)
 7572            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7573        else {
 7574            return;
 7575        };
 7576
 7577        let extension = buffer
 7578            .read(cx)
 7579            .file()
 7580            .and_then(|file| Some(file.path().extension()?.to_string()));
 7581
 7582        let event_type = match accepted {
 7583            true => "Edit Prediction Accepted",
 7584            false => "Edit Prediction Discarded",
 7585        };
 7586        telemetry::event!(
 7587            event_type,
 7588            provider = provider.name(),
 7589            prediction_id = id,
 7590            suggestion_accepted = accepted,
 7591            file_extension = extension,
 7592        );
 7593    }
 7594
 7595    fn open_editor_at_anchor(
 7596        snapshot: &language::BufferSnapshot,
 7597        target: language::Anchor,
 7598        workspace: &Entity<Workspace>,
 7599        window: &mut Window,
 7600        cx: &mut App,
 7601    ) -> Task<Result<()>> {
 7602        workspace.update(cx, |workspace, cx| {
 7603            let path = snapshot.file().map(|file| file.full_path(cx));
 7604            let Some(path) =
 7605                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7606            else {
 7607                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7608            };
 7609            let target = text::ToPoint::to_point(&target, snapshot);
 7610            let item = workspace.open_path(path, None, true, window, cx);
 7611            window.spawn(cx, async move |cx| {
 7612                let Some(editor) = item.await?.downcast::<Editor>() else {
 7613                    return Ok(());
 7614                };
 7615                editor
 7616                    .update_in(cx, |editor, window, cx| {
 7617                        editor.go_to_singleton_buffer_point(target, window, cx);
 7618                    })
 7619                    .ok();
 7620                anyhow::Ok(())
 7621            })
 7622        })
 7623    }
 7624
 7625    pub fn has_active_edit_prediction(&self) -> bool {
 7626        self.active_edit_prediction.is_some()
 7627    }
 7628
 7629    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7630        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7631            return false;
 7632        };
 7633
 7634        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7635        self.clear_highlights::<EditPredictionHighlight>(cx);
 7636        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7637        true
 7638    }
 7639
 7640    /// Returns true when we're displaying the edit prediction popover below the cursor
 7641    /// like we are not previewing and the LSP autocomplete menu is visible
 7642    /// or we are in `when_holding_modifier` mode.
 7643    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7644        if self.edit_prediction_preview_is_active()
 7645            || !self.show_edit_predictions_in_menu()
 7646            || !self.edit_predictions_enabled()
 7647        {
 7648            return false;
 7649        }
 7650
 7651        if self.has_visible_completions_menu() {
 7652            return true;
 7653        }
 7654
 7655        has_completion && self.edit_prediction_requires_modifier()
 7656    }
 7657
 7658    fn handle_modifiers_changed(
 7659        &mut self,
 7660        modifiers: Modifiers,
 7661        position_map: &PositionMap,
 7662        window: &mut Window,
 7663        cx: &mut Context<Self>,
 7664    ) {
 7665        // Ensure that the edit prediction preview is updated, even when not
 7666        // enabled, if there's an active edit prediction preview.
 7667        if self.show_edit_predictions_in_menu()
 7668            || matches!(
 7669                self.edit_prediction_preview,
 7670                EditPredictionPreview::Active { .. }
 7671            )
 7672        {
 7673            self.update_edit_prediction_preview(&modifiers, window, cx);
 7674        }
 7675
 7676        self.update_selection_mode(&modifiers, position_map, window, cx);
 7677
 7678        let mouse_position = window.mouse_position();
 7679        if !position_map.text_hitbox.is_hovered(window) {
 7680            return;
 7681        }
 7682
 7683        self.update_hovered_link(
 7684            position_map.point_for_position(mouse_position),
 7685            &position_map.snapshot,
 7686            modifiers,
 7687            window,
 7688            cx,
 7689        )
 7690    }
 7691
 7692    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7693        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7694            MultiCursorModifier::Alt => modifiers.secondary(),
 7695            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7696        }
 7697    }
 7698
 7699    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7700        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7701            MultiCursorModifier::Alt => modifiers.alt,
 7702            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7703        }
 7704    }
 7705
 7706    fn columnar_selection_mode(
 7707        modifiers: &Modifiers,
 7708        cx: &mut Context<Self>,
 7709    ) -> Option<ColumnarMode> {
 7710        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7711            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 7712                Some(ColumnarMode::FromMouse)
 7713            } else if Self::is_alt_pressed(modifiers, cx) {
 7714                Some(ColumnarMode::FromSelection)
 7715            } else {
 7716                None
 7717            }
 7718        } else {
 7719            None
 7720        }
 7721    }
 7722
 7723    fn update_selection_mode(
 7724        &mut self,
 7725        modifiers: &Modifiers,
 7726        position_map: &PositionMap,
 7727        window: &mut Window,
 7728        cx: &mut Context<Self>,
 7729    ) {
 7730        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7731            return;
 7732        };
 7733        if self.selections.pending_anchor().is_none() {
 7734            return;
 7735        }
 7736
 7737        let mouse_position = window.mouse_position();
 7738        let point_for_position = position_map.point_for_position(mouse_position);
 7739        let position = point_for_position.previous_valid;
 7740
 7741        self.select(
 7742            SelectPhase::BeginColumnar {
 7743                position,
 7744                reset: false,
 7745                mode,
 7746                goal_column: point_for_position.exact_unclipped.column(),
 7747            },
 7748            window,
 7749            cx,
 7750        );
 7751    }
 7752
 7753    fn update_edit_prediction_preview(
 7754        &mut self,
 7755        modifiers: &Modifiers,
 7756        window: &mut Window,
 7757        cx: &mut Context<Self>,
 7758    ) {
 7759        let mut modifiers_held = false;
 7760        if let Some(accept_keystroke) = self
 7761            .accept_edit_prediction_keybind(false, window, cx)
 7762            .keystroke()
 7763        {
 7764            modifiers_held = modifiers_held
 7765                || (accept_keystroke.modifiers() == modifiers
 7766                    && accept_keystroke.modifiers().modified());
 7767        };
 7768        if let Some(accept_partial_keystroke) = self
 7769            .accept_edit_prediction_keybind(true, window, cx)
 7770            .keystroke()
 7771        {
 7772            modifiers_held = modifiers_held
 7773                || (accept_partial_keystroke.modifiers() == modifiers
 7774                    && accept_partial_keystroke.modifiers().modified());
 7775        }
 7776
 7777        if modifiers_held {
 7778            if matches!(
 7779                self.edit_prediction_preview,
 7780                EditPredictionPreview::Inactive { .. }
 7781            ) {
 7782                self.edit_prediction_preview = EditPredictionPreview::Active {
 7783                    previous_scroll_position: None,
 7784                    since: Instant::now(),
 7785                };
 7786
 7787                self.update_visible_edit_prediction(window, cx);
 7788                cx.notify();
 7789            }
 7790        } else if let EditPredictionPreview::Active {
 7791            previous_scroll_position,
 7792            since,
 7793        } = self.edit_prediction_preview
 7794        {
 7795            if let (Some(previous_scroll_position), Some(position_map)) =
 7796                (previous_scroll_position, self.last_position_map.as_ref())
 7797            {
 7798                self.set_scroll_position(
 7799                    previous_scroll_position
 7800                        .scroll_position(&position_map.snapshot.display_snapshot),
 7801                    window,
 7802                    cx,
 7803                );
 7804            }
 7805
 7806            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7807                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7808            };
 7809            self.clear_row_highlights::<EditPredictionPreview>();
 7810            self.update_visible_edit_prediction(window, cx);
 7811            cx.notify();
 7812        }
 7813    }
 7814
 7815    fn update_visible_edit_prediction(
 7816        &mut self,
 7817        _window: &mut Window,
 7818        cx: &mut Context<Self>,
 7819    ) -> Option<()> {
 7820        if DisableAiSettings::get_global(cx).disable_ai {
 7821            return None;
 7822        }
 7823
 7824        if self.ime_transaction.is_some() {
 7825            self.discard_edit_prediction(false, cx);
 7826            return None;
 7827        }
 7828
 7829        let selection = self.selections.newest_anchor();
 7830        let cursor = selection.head();
 7831        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7832        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7833        let excerpt_id = cursor.excerpt_id;
 7834
 7835        let show_in_menu = self.show_edit_predictions_in_menu();
 7836        let completions_menu_has_precedence = !show_in_menu
 7837            && (self.context_menu.borrow().is_some()
 7838                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7839
 7840        if completions_menu_has_precedence
 7841            || !offset_selection.is_empty()
 7842            || self
 7843                .active_edit_prediction
 7844                .as_ref()
 7845                .is_some_and(|completion| {
 7846                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7847                        return false;
 7848                    };
 7849                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7850                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7851                    !invalidation_range.contains(&offset_selection.head())
 7852                })
 7853        {
 7854            self.discard_edit_prediction(false, cx);
 7855            return None;
 7856        }
 7857
 7858        self.take_active_edit_prediction(cx);
 7859        let Some(provider) = self.edit_prediction_provider() else {
 7860            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7861            return None;
 7862        };
 7863
 7864        let (buffer, cursor_buffer_position) =
 7865            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7866
 7867        self.edit_prediction_settings =
 7868            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7869
 7870        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7871
 7872        if self.edit_prediction_indent_conflict {
 7873            let cursor_point = cursor.to_point(&multibuffer);
 7874
 7875            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7876
 7877            if let Some((_, indent)) = indents.iter().next()
 7878                && indent.len == cursor_point.column
 7879            {
 7880                self.edit_prediction_indent_conflict = false;
 7881            }
 7882        }
 7883
 7884        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7885
 7886        let (completion_id, edits, edit_preview) = match edit_prediction {
 7887            edit_prediction::EditPrediction::Local {
 7888                id,
 7889                edits,
 7890                edit_preview,
 7891            } => (id, edits, edit_preview),
 7892            edit_prediction::EditPrediction::Jump {
 7893                id,
 7894                snapshot,
 7895                target,
 7896            } => {
 7897                self.stale_edit_prediction_in_menu = None;
 7898                self.active_edit_prediction = Some(EditPredictionState {
 7899                    inlay_ids: vec![],
 7900                    completion: EditPrediction::MoveOutside { snapshot, target },
 7901                    completion_id: id,
 7902                    invalidation_range: None,
 7903                });
 7904                cx.notify();
 7905                return Some(());
 7906            }
 7907        };
 7908
 7909        let edits = edits
 7910            .into_iter()
 7911            .flat_map(|(range, new_text)| {
 7912                Some((
 7913                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 7914                    new_text,
 7915                ))
 7916            })
 7917            .collect::<Vec<_>>();
 7918        if edits.is_empty() {
 7919            return None;
 7920        }
 7921
 7922        let first_edit_start = edits.first().unwrap().0.start;
 7923        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7924        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7925
 7926        let last_edit_end = edits.last().unwrap().0.end;
 7927        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7928        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7929
 7930        let cursor_row = cursor.to_point(&multibuffer).row;
 7931
 7932        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7933
 7934        let mut inlay_ids = Vec::new();
 7935        let invalidation_row_range;
 7936        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7937            Some(cursor_row..edit_end_row)
 7938        } else if cursor_row > edit_end_row {
 7939            Some(edit_start_row..cursor_row)
 7940        } else {
 7941            None
 7942        };
 7943        let supports_jump = self
 7944            .edit_prediction_provider
 7945            .as_ref()
 7946            .map(|provider| provider.provider.supports_jump_to_edit())
 7947            .unwrap_or(true);
 7948
 7949        let is_move = supports_jump
 7950            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7951        let completion = if is_move {
 7952            invalidation_row_range =
 7953                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7954            let target = first_edit_start;
 7955            EditPrediction::MoveWithin { target, snapshot }
 7956        } else {
 7957            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7958                && !self.edit_predictions_hidden_for_vim_mode;
 7959
 7960            if show_completions_in_buffer {
 7961                if edits
 7962                    .iter()
 7963                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7964                {
 7965                    let mut inlays = Vec::new();
 7966                    for (range, new_text) in &edits {
 7967                        let inlay = Inlay::edit_prediction(
 7968                            post_inc(&mut self.next_inlay_id),
 7969                            range.start,
 7970                            new_text.as_ref(),
 7971                        );
 7972                        inlay_ids.push(inlay.id);
 7973                        inlays.push(inlay);
 7974                    }
 7975
 7976                    self.splice_inlays(&[], inlays, cx);
 7977                } else {
 7978                    let background_color = cx.theme().status().deleted_background;
 7979                    self.highlight_text::<EditPredictionHighlight>(
 7980                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7981                        HighlightStyle {
 7982                            background_color: Some(background_color),
 7983                            ..Default::default()
 7984                        },
 7985                        cx,
 7986                    );
 7987                }
 7988            }
 7989
 7990            invalidation_row_range = edit_start_row..edit_end_row;
 7991
 7992            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7993                if provider.show_tab_accept_marker() {
 7994                    EditDisplayMode::TabAccept
 7995                } else {
 7996                    EditDisplayMode::Inline
 7997                }
 7998            } else {
 7999                EditDisplayMode::DiffPopover
 8000            };
 8001
 8002            EditPrediction::Edit {
 8003                edits,
 8004                edit_preview,
 8005                display_mode,
 8006                snapshot,
 8007            }
 8008        };
 8009
 8010        let invalidation_range = multibuffer
 8011            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8012            ..multibuffer.anchor_after(Point::new(
 8013                invalidation_row_range.end,
 8014                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8015            ));
 8016
 8017        self.stale_edit_prediction_in_menu = None;
 8018        self.active_edit_prediction = Some(EditPredictionState {
 8019            inlay_ids,
 8020            completion,
 8021            completion_id,
 8022            invalidation_range: Some(invalidation_range),
 8023        });
 8024
 8025        cx.notify();
 8026
 8027        Some(())
 8028    }
 8029
 8030    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8031        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8032    }
 8033
 8034    fn clear_tasks(&mut self) {
 8035        self.tasks.clear()
 8036    }
 8037
 8038    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8039        if self.tasks.insert(key, value).is_some() {
 8040            // This case should hopefully be rare, but just in case...
 8041            log::error!(
 8042                "multiple different run targets found on a single line, only the last target will be rendered"
 8043            )
 8044        }
 8045    }
 8046
 8047    /// Get all display points of breakpoints that will be rendered within editor
 8048    ///
 8049    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8050    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8051    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8052    fn active_breakpoints(
 8053        &self,
 8054        range: Range<DisplayRow>,
 8055        window: &mut Window,
 8056        cx: &mut Context<Self>,
 8057    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8058        let mut breakpoint_display_points = HashMap::default();
 8059
 8060        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8061            return breakpoint_display_points;
 8062        };
 8063
 8064        let snapshot = self.snapshot(window, cx);
 8065
 8066        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8067        let Some(project) = self.project() else {
 8068            return breakpoint_display_points;
 8069        };
 8070
 8071        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8072            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8073
 8074        for (buffer_snapshot, range, excerpt_id) in
 8075            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8076        {
 8077            let Some(buffer) = project
 8078                .read(cx)
 8079                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8080            else {
 8081                continue;
 8082            };
 8083            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8084                &buffer,
 8085                Some(
 8086                    buffer_snapshot.anchor_before(range.start)
 8087                        ..buffer_snapshot.anchor_after(range.end),
 8088                ),
 8089                buffer_snapshot,
 8090                cx,
 8091            );
 8092            for (breakpoint, state) in breakpoints {
 8093                let multi_buffer_anchor =
 8094                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8095                let position = multi_buffer_anchor
 8096                    .to_point(&multi_buffer_snapshot)
 8097                    .to_display_point(&snapshot);
 8098
 8099                breakpoint_display_points.insert(
 8100                    position.row(),
 8101                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8102                );
 8103            }
 8104        }
 8105
 8106        breakpoint_display_points
 8107    }
 8108
 8109    fn breakpoint_context_menu(
 8110        &self,
 8111        anchor: Anchor,
 8112        window: &mut Window,
 8113        cx: &mut Context<Self>,
 8114    ) -> Entity<ui::ContextMenu> {
 8115        let weak_editor = cx.weak_entity();
 8116        let focus_handle = self.focus_handle(cx);
 8117
 8118        let row = self
 8119            .buffer
 8120            .read(cx)
 8121            .snapshot(cx)
 8122            .summary_for_anchor::<Point>(&anchor)
 8123            .row;
 8124
 8125        let breakpoint = self
 8126            .breakpoint_at_row(row, window, cx)
 8127            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8128
 8129        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8130            "Edit Log Breakpoint"
 8131        } else {
 8132            "Set Log Breakpoint"
 8133        };
 8134
 8135        let condition_breakpoint_msg = if breakpoint
 8136            .as_ref()
 8137            .is_some_and(|bp| bp.1.condition.is_some())
 8138        {
 8139            "Edit Condition Breakpoint"
 8140        } else {
 8141            "Set Condition Breakpoint"
 8142        };
 8143
 8144        let hit_condition_breakpoint_msg = if breakpoint
 8145            .as_ref()
 8146            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8147        {
 8148            "Edit Hit Condition Breakpoint"
 8149        } else {
 8150            "Set Hit Condition Breakpoint"
 8151        };
 8152
 8153        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8154            "Unset Breakpoint"
 8155        } else {
 8156            "Set Breakpoint"
 8157        };
 8158
 8159        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8160
 8161        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8162            BreakpointState::Enabled => Some("Disable"),
 8163            BreakpointState::Disabled => Some("Enable"),
 8164        });
 8165
 8166        let (anchor, breakpoint) =
 8167            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8168
 8169        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8170            menu.on_blur_subscription(Subscription::new(|| {}))
 8171                .context(focus_handle)
 8172                .when(run_to_cursor, |this| {
 8173                    let weak_editor = weak_editor.clone();
 8174                    this.entry("Run to cursor", None, move |window, cx| {
 8175                        weak_editor
 8176                            .update(cx, |editor, cx| {
 8177                                editor.change_selections(
 8178                                    SelectionEffects::no_scroll(),
 8179                                    window,
 8180                                    cx,
 8181                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8182                                );
 8183                            })
 8184                            .ok();
 8185
 8186                        window.dispatch_action(Box::new(RunToCursor), cx);
 8187                    })
 8188                    .separator()
 8189                })
 8190                .when_some(toggle_state_msg, |this, msg| {
 8191                    this.entry(msg, None, {
 8192                        let weak_editor = weak_editor.clone();
 8193                        let breakpoint = breakpoint.clone();
 8194                        move |_window, cx| {
 8195                            weak_editor
 8196                                .update(cx, |this, cx| {
 8197                                    this.edit_breakpoint_at_anchor(
 8198                                        anchor,
 8199                                        breakpoint.as_ref().clone(),
 8200                                        BreakpointEditAction::InvertState,
 8201                                        cx,
 8202                                    );
 8203                                })
 8204                                .log_err();
 8205                        }
 8206                    })
 8207                })
 8208                .entry(set_breakpoint_msg, None, {
 8209                    let weak_editor = weak_editor.clone();
 8210                    let breakpoint = breakpoint.clone();
 8211                    move |_window, cx| {
 8212                        weak_editor
 8213                            .update(cx, |this, cx| {
 8214                                this.edit_breakpoint_at_anchor(
 8215                                    anchor,
 8216                                    breakpoint.as_ref().clone(),
 8217                                    BreakpointEditAction::Toggle,
 8218                                    cx,
 8219                                );
 8220                            })
 8221                            .log_err();
 8222                    }
 8223                })
 8224                .entry(log_breakpoint_msg, None, {
 8225                    let breakpoint = breakpoint.clone();
 8226                    let weak_editor = weak_editor.clone();
 8227                    move |window, cx| {
 8228                        weak_editor
 8229                            .update(cx, |this, cx| {
 8230                                this.add_edit_breakpoint_block(
 8231                                    anchor,
 8232                                    breakpoint.as_ref(),
 8233                                    BreakpointPromptEditAction::Log,
 8234                                    window,
 8235                                    cx,
 8236                                );
 8237                            })
 8238                            .log_err();
 8239                    }
 8240                })
 8241                .entry(condition_breakpoint_msg, None, {
 8242                    let breakpoint = breakpoint.clone();
 8243                    let weak_editor = weak_editor.clone();
 8244                    move |window, cx| {
 8245                        weak_editor
 8246                            .update(cx, |this, cx| {
 8247                                this.add_edit_breakpoint_block(
 8248                                    anchor,
 8249                                    breakpoint.as_ref(),
 8250                                    BreakpointPromptEditAction::Condition,
 8251                                    window,
 8252                                    cx,
 8253                                );
 8254                            })
 8255                            .log_err();
 8256                    }
 8257                })
 8258                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8259                    weak_editor
 8260                        .update(cx, |this, cx| {
 8261                            this.add_edit_breakpoint_block(
 8262                                anchor,
 8263                                breakpoint.as_ref(),
 8264                                BreakpointPromptEditAction::HitCondition,
 8265                                window,
 8266                                cx,
 8267                            );
 8268                        })
 8269                        .log_err();
 8270                })
 8271        })
 8272    }
 8273
 8274    fn render_breakpoint(
 8275        &self,
 8276        position: Anchor,
 8277        row: DisplayRow,
 8278        breakpoint: &Breakpoint,
 8279        state: Option<BreakpointSessionState>,
 8280        cx: &mut Context<Self>,
 8281    ) -> IconButton {
 8282        let is_rejected = state.is_some_and(|s| !s.verified);
 8283        // Is it a breakpoint that shows up when hovering over gutter?
 8284        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8285            (false, false),
 8286            |PhantomBreakpointIndicator {
 8287                 is_active,
 8288                 display_row,
 8289                 collides_with_existing_breakpoint,
 8290             }| {
 8291                (
 8292                    is_active && display_row == row,
 8293                    collides_with_existing_breakpoint,
 8294                )
 8295            },
 8296        );
 8297
 8298        let (color, icon) = {
 8299            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8300                (false, false) => ui::IconName::DebugBreakpoint,
 8301                (true, false) => ui::IconName::DebugLogBreakpoint,
 8302                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8303                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8304            };
 8305
 8306            let color = if is_phantom {
 8307                Color::Hint
 8308            } else if is_rejected {
 8309                Color::Disabled
 8310            } else {
 8311                Color::Debugger
 8312            };
 8313
 8314            (color, icon)
 8315        };
 8316
 8317        let breakpoint = Arc::from(breakpoint.clone());
 8318
 8319        let alt_as_text = gpui::Keystroke {
 8320            modifiers: Modifiers::secondary_key(),
 8321            ..Default::default()
 8322        };
 8323        let primary_action_text = if breakpoint.is_disabled() {
 8324            "Enable breakpoint"
 8325        } else if is_phantom && !collides_with_existing {
 8326            "Set breakpoint"
 8327        } else {
 8328            "Unset breakpoint"
 8329        };
 8330        let focus_handle = self.focus_handle.clone();
 8331
 8332        let meta = if is_rejected {
 8333            SharedString::from("No executable code is associated with this line.")
 8334        } else if collides_with_existing && !breakpoint.is_disabled() {
 8335            SharedString::from(format!(
 8336                "{alt_as_text}-click to disable,\nright-click for more options."
 8337            ))
 8338        } else {
 8339            SharedString::from("Right-click for more options.")
 8340        };
 8341        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8342            .icon_size(IconSize::XSmall)
 8343            .size(ui::ButtonSize::None)
 8344            .when(is_rejected, |this| {
 8345                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8346            })
 8347            .icon_color(color)
 8348            .style(ButtonStyle::Transparent)
 8349            .on_click(cx.listener({
 8350                move |editor, event: &ClickEvent, window, cx| {
 8351                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8352                        BreakpointEditAction::InvertState
 8353                    } else {
 8354                        BreakpointEditAction::Toggle
 8355                    };
 8356
 8357                    window.focus(&editor.focus_handle(cx));
 8358                    editor.edit_breakpoint_at_anchor(
 8359                        position,
 8360                        breakpoint.as_ref().clone(),
 8361                        edit_action,
 8362                        cx,
 8363                    );
 8364                }
 8365            }))
 8366            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8367                editor.set_breakpoint_context_menu(
 8368                    row,
 8369                    Some(position),
 8370                    event.position(),
 8371                    window,
 8372                    cx,
 8373                );
 8374            }))
 8375            .tooltip(move |_window, cx| {
 8376                Tooltip::with_meta_in(
 8377                    primary_action_text,
 8378                    Some(&ToggleBreakpoint),
 8379                    meta.clone(),
 8380                    &focus_handle,
 8381                    cx,
 8382                )
 8383            })
 8384    }
 8385
 8386    fn build_tasks_context(
 8387        project: &Entity<Project>,
 8388        buffer: &Entity<Buffer>,
 8389        buffer_row: u32,
 8390        tasks: &Arc<RunnableTasks>,
 8391        cx: &mut Context<Self>,
 8392    ) -> Task<Option<task::TaskContext>> {
 8393        let position = Point::new(buffer_row, tasks.column);
 8394        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8395        let location = Location {
 8396            buffer: buffer.clone(),
 8397            range: range_start..range_start,
 8398        };
 8399        // Fill in the environmental variables from the tree-sitter captures
 8400        let mut captured_task_variables = TaskVariables::default();
 8401        for (capture_name, value) in tasks.extra_variables.clone() {
 8402            captured_task_variables.insert(
 8403                task::VariableName::Custom(capture_name.into()),
 8404                value.clone(),
 8405            );
 8406        }
 8407        project.update(cx, |project, cx| {
 8408            project.task_store().update(cx, |task_store, cx| {
 8409                task_store.task_context_for_location(captured_task_variables, location, cx)
 8410            })
 8411        })
 8412    }
 8413
 8414    pub fn spawn_nearest_task(
 8415        &mut self,
 8416        action: &SpawnNearestTask,
 8417        window: &mut Window,
 8418        cx: &mut Context<Self>,
 8419    ) {
 8420        let Some((workspace, _)) = self.workspace.clone() else {
 8421            return;
 8422        };
 8423        let Some(project) = self.project.clone() else {
 8424            return;
 8425        };
 8426
 8427        // Try to find a closest, enclosing node using tree-sitter that has a task
 8428        let Some((buffer, buffer_row, tasks)) = self
 8429            .find_enclosing_node_task(cx)
 8430            // Or find the task that's closest in row-distance.
 8431            .or_else(|| self.find_closest_task(cx))
 8432        else {
 8433            return;
 8434        };
 8435
 8436        let reveal_strategy = action.reveal;
 8437        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8438        cx.spawn_in(window, async move |_, cx| {
 8439            let context = task_context.await?;
 8440            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8441
 8442            let resolved = &mut resolved_task.resolved;
 8443            resolved.reveal = reveal_strategy;
 8444
 8445            workspace
 8446                .update_in(cx, |workspace, window, cx| {
 8447                    workspace.schedule_resolved_task(
 8448                        task_source_kind,
 8449                        resolved_task,
 8450                        false,
 8451                        window,
 8452                        cx,
 8453                    );
 8454                })
 8455                .ok()
 8456        })
 8457        .detach();
 8458    }
 8459
 8460    fn find_closest_task(
 8461        &mut self,
 8462        cx: &mut Context<Self>,
 8463    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8464        let cursor_row = self
 8465            .selections
 8466            .newest_adjusted(&self.display_snapshot(cx))
 8467            .head()
 8468            .row;
 8469
 8470        let ((buffer_id, row), tasks) = self
 8471            .tasks
 8472            .iter()
 8473            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8474
 8475        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8476        let tasks = Arc::new(tasks.to_owned());
 8477        Some((buffer, *row, tasks))
 8478    }
 8479
 8480    fn find_enclosing_node_task(
 8481        &mut self,
 8482        cx: &mut Context<Self>,
 8483    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8484        let snapshot = self.buffer.read(cx).snapshot(cx);
 8485        let offset = self
 8486            .selections
 8487            .newest::<usize>(&self.display_snapshot(cx))
 8488            .head();
 8489        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8490        let buffer_id = excerpt.buffer().remote_id();
 8491
 8492        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8493        let mut cursor = layer.node().walk();
 8494
 8495        while cursor.goto_first_child_for_byte(offset).is_some() {
 8496            if cursor.node().end_byte() == offset {
 8497                cursor.goto_next_sibling();
 8498            }
 8499        }
 8500
 8501        // Ascend to the smallest ancestor that contains the range and has a task.
 8502        loop {
 8503            let node = cursor.node();
 8504            let node_range = node.byte_range();
 8505            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8506
 8507            // Check if this node contains our offset
 8508            if node_range.start <= offset && node_range.end >= offset {
 8509                // If it contains offset, check for task
 8510                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8511                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8512                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8513                }
 8514            }
 8515
 8516            if !cursor.goto_parent() {
 8517                break;
 8518            }
 8519        }
 8520        None
 8521    }
 8522
 8523    fn render_run_indicator(
 8524        &self,
 8525        _style: &EditorStyle,
 8526        is_active: bool,
 8527        row: DisplayRow,
 8528        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8529        cx: &mut Context<Self>,
 8530    ) -> IconButton {
 8531        let color = Color::Muted;
 8532        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8533
 8534        IconButton::new(
 8535            ("run_indicator", row.0 as usize),
 8536            ui::IconName::PlayOutlined,
 8537        )
 8538        .shape(ui::IconButtonShape::Square)
 8539        .icon_size(IconSize::XSmall)
 8540        .icon_color(color)
 8541        .toggle_state(is_active)
 8542        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8543            let quick_launch = match e {
 8544                ClickEvent::Keyboard(_) => true,
 8545                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8546            };
 8547
 8548            window.focus(&editor.focus_handle(cx));
 8549            editor.toggle_code_actions(
 8550                &ToggleCodeActions {
 8551                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8552                    quick_launch,
 8553                },
 8554                window,
 8555                cx,
 8556            );
 8557        }))
 8558        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8559            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8560        }))
 8561    }
 8562
 8563    pub fn context_menu_visible(&self) -> bool {
 8564        !self.edit_prediction_preview_is_active()
 8565            && self
 8566                .context_menu
 8567                .borrow()
 8568                .as_ref()
 8569                .is_some_and(|menu| menu.visible())
 8570    }
 8571
 8572    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8573        self.context_menu
 8574            .borrow()
 8575            .as_ref()
 8576            .map(|menu| menu.origin())
 8577    }
 8578
 8579    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8580        self.context_menu_options = Some(options);
 8581    }
 8582
 8583    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8584    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8585
 8586    fn render_edit_prediction_popover(
 8587        &mut self,
 8588        text_bounds: &Bounds<Pixels>,
 8589        content_origin: gpui::Point<Pixels>,
 8590        right_margin: Pixels,
 8591        editor_snapshot: &EditorSnapshot,
 8592        visible_row_range: Range<DisplayRow>,
 8593        scroll_top: ScrollOffset,
 8594        scroll_bottom: ScrollOffset,
 8595        line_layouts: &[LineWithInvisibles],
 8596        line_height: Pixels,
 8597        scroll_position: gpui::Point<ScrollOffset>,
 8598        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8599        newest_selection_head: Option<DisplayPoint>,
 8600        editor_width: Pixels,
 8601        style: &EditorStyle,
 8602        window: &mut Window,
 8603        cx: &mut App,
 8604    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8605        if self.mode().is_minimap() {
 8606            return None;
 8607        }
 8608        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8609
 8610        if self.edit_prediction_visible_in_cursor_popover(true) {
 8611            return None;
 8612        }
 8613
 8614        match &active_edit_prediction.completion {
 8615            EditPrediction::MoveWithin { target, .. } => {
 8616                let target_display_point = target.to_display_point(editor_snapshot);
 8617
 8618                if self.edit_prediction_requires_modifier() {
 8619                    if !self.edit_prediction_preview_is_active() {
 8620                        return None;
 8621                    }
 8622
 8623                    self.render_edit_prediction_modifier_jump_popover(
 8624                        text_bounds,
 8625                        content_origin,
 8626                        visible_row_range,
 8627                        line_layouts,
 8628                        line_height,
 8629                        scroll_pixel_position,
 8630                        newest_selection_head,
 8631                        target_display_point,
 8632                        window,
 8633                        cx,
 8634                    )
 8635                } else {
 8636                    self.render_edit_prediction_eager_jump_popover(
 8637                        text_bounds,
 8638                        content_origin,
 8639                        editor_snapshot,
 8640                        visible_row_range,
 8641                        scroll_top,
 8642                        scroll_bottom,
 8643                        line_height,
 8644                        scroll_pixel_position,
 8645                        target_display_point,
 8646                        editor_width,
 8647                        window,
 8648                        cx,
 8649                    )
 8650                }
 8651            }
 8652            EditPrediction::Edit {
 8653                display_mode: EditDisplayMode::Inline,
 8654                ..
 8655            } => None,
 8656            EditPrediction::Edit {
 8657                display_mode: EditDisplayMode::TabAccept,
 8658                edits,
 8659                ..
 8660            } => {
 8661                let range = &edits.first()?.0;
 8662                let target_display_point = range.end.to_display_point(editor_snapshot);
 8663
 8664                self.render_edit_prediction_end_of_line_popover(
 8665                    "Accept",
 8666                    editor_snapshot,
 8667                    visible_row_range,
 8668                    target_display_point,
 8669                    line_height,
 8670                    scroll_pixel_position,
 8671                    content_origin,
 8672                    editor_width,
 8673                    window,
 8674                    cx,
 8675                )
 8676            }
 8677            EditPrediction::Edit {
 8678                edits,
 8679                edit_preview,
 8680                display_mode: EditDisplayMode::DiffPopover,
 8681                snapshot,
 8682            } => self.render_edit_prediction_diff_popover(
 8683                text_bounds,
 8684                content_origin,
 8685                right_margin,
 8686                editor_snapshot,
 8687                visible_row_range,
 8688                line_layouts,
 8689                line_height,
 8690                scroll_position,
 8691                scroll_pixel_position,
 8692                newest_selection_head,
 8693                editor_width,
 8694                style,
 8695                edits,
 8696                edit_preview,
 8697                snapshot,
 8698                window,
 8699                cx,
 8700            ),
 8701            EditPrediction::MoveOutside { snapshot, .. } => {
 8702                let file_name = snapshot
 8703                    .file()
 8704                    .map(|file| file.file_name(cx))
 8705                    .unwrap_or("untitled");
 8706                let mut element = self
 8707                    .render_edit_prediction_line_popover(
 8708                        format!("Jump to {file_name}"),
 8709                        Some(IconName::ZedPredict),
 8710                        window,
 8711                        cx,
 8712                    )
 8713                    .into_any();
 8714
 8715                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8716                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8717                let origin_y = text_bounds.size.height - size.height - px(30.);
 8718                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8719                element.prepaint_at(origin, window, cx);
 8720
 8721                Some((element, origin))
 8722            }
 8723        }
 8724    }
 8725
 8726    fn render_edit_prediction_modifier_jump_popover(
 8727        &mut self,
 8728        text_bounds: &Bounds<Pixels>,
 8729        content_origin: gpui::Point<Pixels>,
 8730        visible_row_range: Range<DisplayRow>,
 8731        line_layouts: &[LineWithInvisibles],
 8732        line_height: Pixels,
 8733        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8734        newest_selection_head: Option<DisplayPoint>,
 8735        target_display_point: DisplayPoint,
 8736        window: &mut Window,
 8737        cx: &mut App,
 8738    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8739        let scrolled_content_origin =
 8740            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8741
 8742        const SCROLL_PADDING_Y: Pixels = px(12.);
 8743
 8744        if target_display_point.row() < visible_row_range.start {
 8745            return self.render_edit_prediction_scroll_popover(
 8746                |_| SCROLL_PADDING_Y,
 8747                IconName::ArrowUp,
 8748                visible_row_range,
 8749                line_layouts,
 8750                newest_selection_head,
 8751                scrolled_content_origin,
 8752                window,
 8753                cx,
 8754            );
 8755        } else if target_display_point.row() >= visible_row_range.end {
 8756            return self.render_edit_prediction_scroll_popover(
 8757                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8758                IconName::ArrowDown,
 8759                visible_row_range,
 8760                line_layouts,
 8761                newest_selection_head,
 8762                scrolled_content_origin,
 8763                window,
 8764                cx,
 8765            );
 8766        }
 8767
 8768        const POLE_WIDTH: Pixels = px(2.);
 8769
 8770        let line_layout =
 8771            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8772        let target_column = target_display_point.column() as usize;
 8773
 8774        let target_x = line_layout.x_for_index(target_column);
 8775        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8776            - scroll_pixel_position.y;
 8777
 8778        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8779
 8780        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8781        border_color.l += 0.001;
 8782
 8783        let mut element = v_flex()
 8784            .items_end()
 8785            .when(flag_on_right, |el| el.items_start())
 8786            .child(if flag_on_right {
 8787                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8788                    .rounded_bl(px(0.))
 8789                    .rounded_tl(px(0.))
 8790                    .border_l_2()
 8791                    .border_color(border_color)
 8792            } else {
 8793                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8794                    .rounded_br(px(0.))
 8795                    .rounded_tr(px(0.))
 8796                    .border_r_2()
 8797                    .border_color(border_color)
 8798            })
 8799            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8800            .into_any();
 8801
 8802        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8803
 8804        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8805            - point(
 8806                if flag_on_right {
 8807                    POLE_WIDTH
 8808                } else {
 8809                    size.width - POLE_WIDTH
 8810                },
 8811                size.height - line_height,
 8812            );
 8813
 8814        origin.x = origin.x.max(content_origin.x);
 8815
 8816        element.prepaint_at(origin, window, cx);
 8817
 8818        Some((element, origin))
 8819    }
 8820
 8821    fn render_edit_prediction_scroll_popover(
 8822        &mut self,
 8823        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8824        scroll_icon: IconName,
 8825        visible_row_range: Range<DisplayRow>,
 8826        line_layouts: &[LineWithInvisibles],
 8827        newest_selection_head: Option<DisplayPoint>,
 8828        scrolled_content_origin: gpui::Point<Pixels>,
 8829        window: &mut Window,
 8830        cx: &mut App,
 8831    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8832        let mut element = self
 8833            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8834            .into_any();
 8835
 8836        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8837
 8838        let cursor = newest_selection_head?;
 8839        let cursor_row_layout =
 8840            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8841        let cursor_column = cursor.column() as usize;
 8842
 8843        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8844
 8845        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8846
 8847        element.prepaint_at(origin, window, cx);
 8848        Some((element, origin))
 8849    }
 8850
 8851    fn render_edit_prediction_eager_jump_popover(
 8852        &mut self,
 8853        text_bounds: &Bounds<Pixels>,
 8854        content_origin: gpui::Point<Pixels>,
 8855        editor_snapshot: &EditorSnapshot,
 8856        visible_row_range: Range<DisplayRow>,
 8857        scroll_top: ScrollOffset,
 8858        scroll_bottom: ScrollOffset,
 8859        line_height: Pixels,
 8860        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8861        target_display_point: DisplayPoint,
 8862        editor_width: Pixels,
 8863        window: &mut Window,
 8864        cx: &mut App,
 8865    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8866        if target_display_point.row().as_f64() < scroll_top {
 8867            let mut element = self
 8868                .render_edit_prediction_line_popover(
 8869                    "Jump to Edit",
 8870                    Some(IconName::ArrowUp),
 8871                    window,
 8872                    cx,
 8873                )
 8874                .into_any();
 8875
 8876            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8877            let offset = point(
 8878                (text_bounds.size.width - size.width) / 2.,
 8879                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8880            );
 8881
 8882            let origin = text_bounds.origin + offset;
 8883            element.prepaint_at(origin, window, cx);
 8884            Some((element, origin))
 8885        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 8886            let mut element = self
 8887                .render_edit_prediction_line_popover(
 8888                    "Jump to Edit",
 8889                    Some(IconName::ArrowDown),
 8890                    window,
 8891                    cx,
 8892                )
 8893                .into_any();
 8894
 8895            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8896            let offset = point(
 8897                (text_bounds.size.width - size.width) / 2.,
 8898                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8899            );
 8900
 8901            let origin = text_bounds.origin + offset;
 8902            element.prepaint_at(origin, window, cx);
 8903            Some((element, origin))
 8904        } else {
 8905            self.render_edit_prediction_end_of_line_popover(
 8906                "Jump to Edit",
 8907                editor_snapshot,
 8908                visible_row_range,
 8909                target_display_point,
 8910                line_height,
 8911                scroll_pixel_position,
 8912                content_origin,
 8913                editor_width,
 8914                window,
 8915                cx,
 8916            )
 8917        }
 8918    }
 8919
 8920    fn render_edit_prediction_end_of_line_popover(
 8921        self: &mut Editor,
 8922        label: &'static str,
 8923        editor_snapshot: &EditorSnapshot,
 8924        visible_row_range: Range<DisplayRow>,
 8925        target_display_point: DisplayPoint,
 8926        line_height: Pixels,
 8927        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8928        content_origin: gpui::Point<Pixels>,
 8929        editor_width: Pixels,
 8930        window: &mut Window,
 8931        cx: &mut App,
 8932    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8933        let target_line_end = DisplayPoint::new(
 8934            target_display_point.row(),
 8935            editor_snapshot.line_len(target_display_point.row()),
 8936        );
 8937
 8938        let mut element = self
 8939            .render_edit_prediction_line_popover(label, None, window, cx)
 8940            .into_any();
 8941
 8942        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8943
 8944        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8945
 8946        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 8947        let mut origin = start_point
 8948            + line_origin
 8949            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8950        origin.x = origin.x.max(content_origin.x);
 8951
 8952        let max_x = content_origin.x + editor_width - size.width;
 8953
 8954        if origin.x > max_x {
 8955            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8956
 8957            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8958                origin.y += offset;
 8959                IconName::ArrowUp
 8960            } else {
 8961                origin.y -= offset;
 8962                IconName::ArrowDown
 8963            };
 8964
 8965            element = self
 8966                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 8967                .into_any();
 8968
 8969            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8970
 8971            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8972        }
 8973
 8974        element.prepaint_at(origin, window, cx);
 8975        Some((element, origin))
 8976    }
 8977
 8978    fn render_edit_prediction_diff_popover(
 8979        self: &Editor,
 8980        text_bounds: &Bounds<Pixels>,
 8981        content_origin: gpui::Point<Pixels>,
 8982        right_margin: Pixels,
 8983        editor_snapshot: &EditorSnapshot,
 8984        visible_row_range: Range<DisplayRow>,
 8985        line_layouts: &[LineWithInvisibles],
 8986        line_height: Pixels,
 8987        scroll_position: gpui::Point<ScrollOffset>,
 8988        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8989        newest_selection_head: Option<DisplayPoint>,
 8990        editor_width: Pixels,
 8991        style: &EditorStyle,
 8992        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 8993        edit_preview: &Option<language::EditPreview>,
 8994        snapshot: &language::BufferSnapshot,
 8995        window: &mut Window,
 8996        cx: &mut App,
 8997    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8998        let edit_start = edits
 8999            .first()
 9000            .unwrap()
 9001            .0
 9002            .start
 9003            .to_display_point(editor_snapshot);
 9004        let edit_end = edits
 9005            .last()
 9006            .unwrap()
 9007            .0
 9008            .end
 9009            .to_display_point(editor_snapshot);
 9010
 9011        let is_visible = visible_row_range.contains(&edit_start.row())
 9012            || visible_row_range.contains(&edit_end.row());
 9013        if !is_visible {
 9014            return None;
 9015        }
 9016
 9017        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9018            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9019        } else {
 9020            // Fallback for providers without edit_preview
 9021            crate::edit_prediction_fallback_text(edits, cx)
 9022        };
 9023
 9024        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9025        let line_count = highlighted_edits.text.lines().count();
 9026
 9027        const BORDER_WIDTH: Pixels = px(1.);
 9028
 9029        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9030        let has_keybind = keybind.is_some();
 9031
 9032        let mut element = h_flex()
 9033            .items_start()
 9034            .child(
 9035                h_flex()
 9036                    .bg(cx.theme().colors().editor_background)
 9037                    .border(BORDER_WIDTH)
 9038                    .shadow_xs()
 9039                    .border_color(cx.theme().colors().border)
 9040                    .rounded_l_lg()
 9041                    .when(line_count > 1, |el| el.rounded_br_lg())
 9042                    .pr_1()
 9043                    .child(styled_text),
 9044            )
 9045            .child(
 9046                h_flex()
 9047                    .h(line_height + BORDER_WIDTH * 2.)
 9048                    .px_1p5()
 9049                    .gap_1()
 9050                    // Workaround: For some reason, there's a gap if we don't do this
 9051                    .ml(-BORDER_WIDTH)
 9052                    .shadow(vec![gpui::BoxShadow {
 9053                        color: gpui::black().opacity(0.05),
 9054                        offset: point(px(1.), px(1.)),
 9055                        blur_radius: px(2.),
 9056                        spread_radius: px(0.),
 9057                    }])
 9058                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9059                    .border(BORDER_WIDTH)
 9060                    .border_color(cx.theme().colors().border)
 9061                    .rounded_r_lg()
 9062                    .id("edit_prediction_diff_popover_keybind")
 9063                    .when(!has_keybind, |el| {
 9064                        let status_colors = cx.theme().status();
 9065
 9066                        el.bg(status_colors.error_background)
 9067                            .border_color(status_colors.error.opacity(0.6))
 9068                            .child(Icon::new(IconName::Info).color(Color::Error))
 9069                            .cursor_default()
 9070                            .hoverable_tooltip(move |_window, cx| {
 9071                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9072                            })
 9073                    })
 9074                    .children(keybind),
 9075            )
 9076            .into_any();
 9077
 9078        let longest_row =
 9079            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9080        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9081            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9082        } else {
 9083            layout_line(
 9084                longest_row,
 9085                editor_snapshot,
 9086                style,
 9087                editor_width,
 9088                |_| false,
 9089                window,
 9090                cx,
 9091            )
 9092            .width
 9093        };
 9094
 9095        let viewport_bounds =
 9096            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9097                right: -right_margin,
 9098                ..Default::default()
 9099            });
 9100
 9101        let x_after_longest = Pixels::from(
 9102            ScrollPixelOffset::from(
 9103                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9104            ) - scroll_pixel_position.x,
 9105        );
 9106
 9107        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9108
 9109        // Fully visible if it can be displayed within the window (allow overlapping other
 9110        // panes). However, this is only allowed if the popover starts within text_bounds.
 9111        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9112            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9113
 9114        let mut origin = if can_position_to_the_right {
 9115            point(
 9116                x_after_longest,
 9117                text_bounds.origin.y
 9118                    + Pixels::from(
 9119                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9120                            - scroll_pixel_position.y,
 9121                    ),
 9122            )
 9123        } else {
 9124            let cursor_row = newest_selection_head.map(|head| head.row());
 9125            let above_edit = edit_start
 9126                .row()
 9127                .0
 9128                .checked_sub(line_count as u32)
 9129                .map(DisplayRow);
 9130            let below_edit = Some(edit_end.row() + 1);
 9131            let above_cursor =
 9132                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9133            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9134
 9135            // Place the edit popover adjacent to the edit if there is a location
 9136            // available that is onscreen and does not obscure the cursor. Otherwise,
 9137            // place it adjacent to the cursor.
 9138            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9139                .into_iter()
 9140                .flatten()
 9141                .find(|&start_row| {
 9142                    let end_row = start_row + line_count as u32;
 9143                    visible_row_range.contains(&start_row)
 9144                        && visible_row_range.contains(&end_row)
 9145                        && cursor_row
 9146                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9147                })?;
 9148
 9149            content_origin
 9150                + point(
 9151                    Pixels::from(-scroll_pixel_position.x),
 9152                    Pixels::from(
 9153                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9154                    ),
 9155                )
 9156        };
 9157
 9158        origin.x -= BORDER_WIDTH;
 9159
 9160        window.defer_draw(element, origin, 1);
 9161
 9162        // Do not return an element, since it will already be drawn due to defer_draw.
 9163        None
 9164    }
 9165
 9166    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9167        px(30.)
 9168    }
 9169
 9170    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9171        if self.read_only(cx) {
 9172            cx.theme().players().read_only()
 9173        } else {
 9174            self.style.as_ref().unwrap().local_player
 9175        }
 9176    }
 9177
 9178    fn render_edit_prediction_accept_keybind(
 9179        &self,
 9180        window: &mut Window,
 9181        cx: &mut App,
 9182    ) -> Option<AnyElement> {
 9183        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9184        let accept_keystroke = accept_binding.keystroke()?;
 9185
 9186        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9187
 9188        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9189            Color::Accent
 9190        } else {
 9191            Color::Muted
 9192        };
 9193
 9194        h_flex()
 9195            .px_0p5()
 9196            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9197            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9198            .text_size(TextSize::XSmall.rems(cx))
 9199            .child(h_flex().children(ui::render_modifiers(
 9200                accept_keystroke.modifiers(),
 9201                PlatformStyle::platform(),
 9202                Some(modifiers_color),
 9203                Some(IconSize::XSmall.rems().into()),
 9204                true,
 9205            )))
 9206            .when(is_platform_style_mac, |parent| {
 9207                parent.child(accept_keystroke.key().to_string())
 9208            })
 9209            .when(!is_platform_style_mac, |parent| {
 9210                parent.child(
 9211                    Key::new(
 9212                        util::capitalize(accept_keystroke.key()),
 9213                        Some(Color::Default),
 9214                    )
 9215                    .size(Some(IconSize::XSmall.rems().into())),
 9216                )
 9217            })
 9218            .into_any()
 9219            .into()
 9220    }
 9221
 9222    fn render_edit_prediction_line_popover(
 9223        &self,
 9224        label: impl Into<SharedString>,
 9225        icon: Option<IconName>,
 9226        window: &mut Window,
 9227        cx: &mut App,
 9228    ) -> Stateful<Div> {
 9229        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9230
 9231        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9232        let has_keybind = keybind.is_some();
 9233
 9234        h_flex()
 9235            .id("ep-line-popover")
 9236            .py_0p5()
 9237            .pl_1()
 9238            .pr(padding_right)
 9239            .gap_1()
 9240            .rounded_md()
 9241            .border_1()
 9242            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9243            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9244            .shadow_xs()
 9245            .when(!has_keybind, |el| {
 9246                let status_colors = cx.theme().status();
 9247
 9248                el.bg(status_colors.error_background)
 9249                    .border_color(status_colors.error.opacity(0.6))
 9250                    .pl_2()
 9251                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9252                    .cursor_default()
 9253                    .hoverable_tooltip(move |_window, cx| {
 9254                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9255                    })
 9256            })
 9257            .children(keybind)
 9258            .child(
 9259                Label::new(label)
 9260                    .size(LabelSize::Small)
 9261                    .when(!has_keybind, |el| {
 9262                        el.color(cx.theme().status().error.into()).strikethrough()
 9263                    }),
 9264            )
 9265            .when(!has_keybind, |el| {
 9266                el.child(
 9267                    h_flex().ml_1().child(
 9268                        Icon::new(IconName::Info)
 9269                            .size(IconSize::Small)
 9270                            .color(cx.theme().status().error.into()),
 9271                    ),
 9272                )
 9273            })
 9274            .when_some(icon, |element, icon| {
 9275                element.child(
 9276                    div()
 9277                        .mt(px(1.5))
 9278                        .child(Icon::new(icon).size(IconSize::Small)),
 9279                )
 9280            })
 9281    }
 9282
 9283    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9284        let accent_color = cx.theme().colors().text_accent;
 9285        let editor_bg_color = cx.theme().colors().editor_background;
 9286        editor_bg_color.blend(accent_color.opacity(0.1))
 9287    }
 9288
 9289    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9290        let accent_color = cx.theme().colors().text_accent;
 9291        let editor_bg_color = cx.theme().colors().editor_background;
 9292        editor_bg_color.blend(accent_color.opacity(0.6))
 9293    }
 9294    fn get_prediction_provider_icon_name(
 9295        provider: &Option<RegisteredEditPredictionProvider>,
 9296    ) -> IconName {
 9297        match provider {
 9298            Some(provider) => match provider.provider.name() {
 9299                "copilot" => IconName::Copilot,
 9300                "supermaven" => IconName::Supermaven,
 9301                _ => IconName::ZedPredict,
 9302            },
 9303            None => IconName::ZedPredict,
 9304        }
 9305    }
 9306
 9307    fn render_edit_prediction_cursor_popover(
 9308        &self,
 9309        min_width: Pixels,
 9310        max_width: Pixels,
 9311        cursor_point: Point,
 9312        style: &EditorStyle,
 9313        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9314        _window: &Window,
 9315        cx: &mut Context<Editor>,
 9316    ) -> Option<AnyElement> {
 9317        let provider = self.edit_prediction_provider.as_ref()?;
 9318        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9319
 9320        let is_refreshing = provider.provider.is_refreshing(cx);
 9321
 9322        fn pending_completion_container(icon: IconName) -> Div {
 9323            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9324        }
 9325
 9326        let completion = match &self.active_edit_prediction {
 9327            Some(prediction) => {
 9328                if !self.has_visible_completions_menu() {
 9329                    const RADIUS: Pixels = px(6.);
 9330                    const BORDER_WIDTH: Pixels = px(1.);
 9331
 9332                    return Some(
 9333                        h_flex()
 9334                            .elevation_2(cx)
 9335                            .border(BORDER_WIDTH)
 9336                            .border_color(cx.theme().colors().border)
 9337                            .when(accept_keystroke.is_none(), |el| {
 9338                                el.border_color(cx.theme().status().error)
 9339                            })
 9340                            .rounded(RADIUS)
 9341                            .rounded_tl(px(0.))
 9342                            .overflow_hidden()
 9343                            .child(div().px_1p5().child(match &prediction.completion {
 9344                                EditPrediction::MoveWithin { target, snapshot } => {
 9345                                    use text::ToPoint as _;
 9346                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9347                                    {
 9348                                        Icon::new(IconName::ZedPredictDown)
 9349                                    } else {
 9350                                        Icon::new(IconName::ZedPredictUp)
 9351                                    }
 9352                                }
 9353                                EditPrediction::MoveOutside { .. } => {
 9354                                    // TODO [zeta2] custom icon for external jump?
 9355                                    Icon::new(provider_icon)
 9356                                }
 9357                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9358                            }))
 9359                            .child(
 9360                                h_flex()
 9361                                    .gap_1()
 9362                                    .py_1()
 9363                                    .px_2()
 9364                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9365                                    .border_l_1()
 9366                                    .border_color(cx.theme().colors().border)
 9367                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9368                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9369                                        el.child(
 9370                                            Label::new("Hold")
 9371                                                .size(LabelSize::Small)
 9372                                                .when(accept_keystroke.is_none(), |el| {
 9373                                                    el.strikethrough()
 9374                                                })
 9375                                                .line_height_style(LineHeightStyle::UiLabel),
 9376                                        )
 9377                                    })
 9378                                    .id("edit_prediction_cursor_popover_keybind")
 9379                                    .when(accept_keystroke.is_none(), |el| {
 9380                                        let status_colors = cx.theme().status();
 9381
 9382                                        el.bg(status_colors.error_background)
 9383                                            .border_color(status_colors.error.opacity(0.6))
 9384                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9385                                            .cursor_default()
 9386                                            .hoverable_tooltip(move |_window, cx| {
 9387                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9388                                                    .into()
 9389                                            })
 9390                                    })
 9391                                    .when_some(
 9392                                        accept_keystroke.as_ref(),
 9393                                        |el, accept_keystroke| {
 9394                                            el.child(h_flex().children(ui::render_modifiers(
 9395                                                accept_keystroke.modifiers(),
 9396                                                PlatformStyle::platform(),
 9397                                                Some(Color::Default),
 9398                                                Some(IconSize::XSmall.rems().into()),
 9399                                                false,
 9400                                            )))
 9401                                        },
 9402                                    ),
 9403                            )
 9404                            .into_any(),
 9405                    );
 9406                }
 9407
 9408                self.render_edit_prediction_cursor_popover_preview(
 9409                    prediction,
 9410                    cursor_point,
 9411                    style,
 9412                    cx,
 9413                )?
 9414            }
 9415
 9416            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9417                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9418                    stale_completion,
 9419                    cursor_point,
 9420                    style,
 9421                    cx,
 9422                )?,
 9423
 9424                None => pending_completion_container(provider_icon)
 9425                    .child(Label::new("...").size(LabelSize::Small)),
 9426            },
 9427
 9428            None => pending_completion_container(provider_icon)
 9429                .child(Label::new("...").size(LabelSize::Small)),
 9430        };
 9431
 9432        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9433            completion
 9434                .with_animation(
 9435                    "loading-completion",
 9436                    Animation::new(Duration::from_secs(2))
 9437                        .repeat()
 9438                        .with_easing(pulsating_between(0.4, 0.8)),
 9439                    |label, delta| label.opacity(delta),
 9440                )
 9441                .into_any_element()
 9442        } else {
 9443            completion.into_any_element()
 9444        };
 9445
 9446        let has_completion = self.active_edit_prediction.is_some();
 9447
 9448        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9449        Some(
 9450            h_flex()
 9451                .min_w(min_width)
 9452                .max_w(max_width)
 9453                .flex_1()
 9454                .elevation_2(cx)
 9455                .border_color(cx.theme().colors().border)
 9456                .child(
 9457                    div()
 9458                        .flex_1()
 9459                        .py_1()
 9460                        .px_2()
 9461                        .overflow_hidden()
 9462                        .child(completion),
 9463                )
 9464                .when_some(accept_keystroke, |el, accept_keystroke| {
 9465                    if !accept_keystroke.modifiers().modified() {
 9466                        return el;
 9467                    }
 9468
 9469                    el.child(
 9470                        h_flex()
 9471                            .h_full()
 9472                            .border_l_1()
 9473                            .rounded_r_lg()
 9474                            .border_color(cx.theme().colors().border)
 9475                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9476                            .gap_1()
 9477                            .py_1()
 9478                            .px_2()
 9479                            .child(
 9480                                h_flex()
 9481                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9482                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9483                                    .child(h_flex().children(ui::render_modifiers(
 9484                                        accept_keystroke.modifiers(),
 9485                                        PlatformStyle::platform(),
 9486                                        Some(if !has_completion {
 9487                                            Color::Muted
 9488                                        } else {
 9489                                            Color::Default
 9490                                        }),
 9491                                        None,
 9492                                        false,
 9493                                    ))),
 9494                            )
 9495                            .child(Label::new("Preview").into_any_element())
 9496                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9497                    )
 9498                })
 9499                .into_any(),
 9500        )
 9501    }
 9502
 9503    fn render_edit_prediction_cursor_popover_preview(
 9504        &self,
 9505        completion: &EditPredictionState,
 9506        cursor_point: Point,
 9507        style: &EditorStyle,
 9508        cx: &mut Context<Editor>,
 9509    ) -> Option<Div> {
 9510        use text::ToPoint as _;
 9511
 9512        fn render_relative_row_jump(
 9513            prefix: impl Into<String>,
 9514            current_row: u32,
 9515            target_row: u32,
 9516        ) -> Div {
 9517            let (row_diff, arrow) = if target_row < current_row {
 9518                (current_row - target_row, IconName::ArrowUp)
 9519            } else {
 9520                (target_row - current_row, IconName::ArrowDown)
 9521            };
 9522
 9523            h_flex()
 9524                .child(
 9525                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9526                        .color(Color::Muted)
 9527                        .size(LabelSize::Small),
 9528                )
 9529                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9530        }
 9531
 9532        let supports_jump = self
 9533            .edit_prediction_provider
 9534            .as_ref()
 9535            .map(|provider| provider.provider.supports_jump_to_edit())
 9536            .unwrap_or(true);
 9537
 9538        match &completion.completion {
 9539            EditPrediction::MoveWithin {
 9540                target, snapshot, ..
 9541            } => {
 9542                if !supports_jump {
 9543                    return None;
 9544                }
 9545
 9546                Some(
 9547                    h_flex()
 9548                        .px_2()
 9549                        .gap_2()
 9550                        .flex_1()
 9551                        .child(
 9552                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9553                                Icon::new(IconName::ZedPredictDown)
 9554                            } else {
 9555                                Icon::new(IconName::ZedPredictUp)
 9556                            },
 9557                        )
 9558                        .child(Label::new("Jump to Edit")),
 9559                )
 9560            }
 9561            EditPrediction::MoveOutside { snapshot, .. } => {
 9562                let file_name = snapshot
 9563                    .file()
 9564                    .map(|file| file.file_name(cx))
 9565                    .unwrap_or("untitled");
 9566                Some(
 9567                    h_flex()
 9568                        .px_2()
 9569                        .gap_2()
 9570                        .flex_1()
 9571                        .child(Icon::new(IconName::ZedPredict))
 9572                        .child(Label::new(format!("Jump to {file_name}"))),
 9573                )
 9574            }
 9575            EditPrediction::Edit {
 9576                edits,
 9577                edit_preview,
 9578                snapshot,
 9579                display_mode: _,
 9580            } => {
 9581                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9582
 9583                let (highlighted_edits, has_more_lines) =
 9584                    if let Some(edit_preview) = edit_preview.as_ref() {
 9585                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9586                            .first_line_preview()
 9587                    } else {
 9588                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9589                    };
 9590
 9591                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9592                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9593
 9594                let preview = h_flex()
 9595                    .gap_1()
 9596                    .min_w_16()
 9597                    .child(styled_text)
 9598                    .when(has_more_lines, |parent| parent.child(""));
 9599
 9600                let left = if supports_jump && first_edit_row != cursor_point.row {
 9601                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9602                        .into_any_element()
 9603                } else {
 9604                    let icon_name =
 9605                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9606                    Icon::new(icon_name).into_any_element()
 9607                };
 9608
 9609                Some(
 9610                    h_flex()
 9611                        .h_full()
 9612                        .flex_1()
 9613                        .gap_2()
 9614                        .pr_1()
 9615                        .overflow_x_hidden()
 9616                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9617                        .child(left)
 9618                        .child(preview),
 9619                )
 9620            }
 9621        }
 9622    }
 9623
 9624    pub fn render_context_menu(
 9625        &self,
 9626        style: &EditorStyle,
 9627        max_height_in_lines: u32,
 9628        window: &mut Window,
 9629        cx: &mut Context<Editor>,
 9630    ) -> Option<AnyElement> {
 9631        let menu = self.context_menu.borrow();
 9632        let menu = menu.as_ref()?;
 9633        if !menu.visible() {
 9634            return None;
 9635        };
 9636        Some(menu.render(style, max_height_in_lines, window, cx))
 9637    }
 9638
 9639    fn render_context_menu_aside(
 9640        &mut self,
 9641        max_size: Size<Pixels>,
 9642        window: &mut Window,
 9643        cx: &mut Context<Editor>,
 9644    ) -> Option<AnyElement> {
 9645        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9646            if menu.visible() {
 9647                menu.render_aside(max_size, window, cx)
 9648            } else {
 9649                None
 9650            }
 9651        })
 9652    }
 9653
 9654    fn hide_context_menu(
 9655        &mut self,
 9656        window: &mut Window,
 9657        cx: &mut Context<Self>,
 9658    ) -> Option<CodeContextMenu> {
 9659        cx.notify();
 9660        self.completion_tasks.clear();
 9661        let context_menu = self.context_menu.borrow_mut().take();
 9662        self.stale_edit_prediction_in_menu.take();
 9663        self.update_visible_edit_prediction(window, cx);
 9664        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9665            && let Some(completion_provider) = &self.completion_provider
 9666        {
 9667            completion_provider.selection_changed(None, window, cx);
 9668        }
 9669        context_menu
 9670    }
 9671
 9672    fn show_snippet_choices(
 9673        &mut self,
 9674        choices: &Vec<String>,
 9675        selection: Range<Anchor>,
 9676        cx: &mut Context<Self>,
 9677    ) {
 9678        let Some((_, buffer, _)) = self
 9679            .buffer()
 9680            .read(cx)
 9681            .excerpt_containing(selection.start, cx)
 9682        else {
 9683            return;
 9684        };
 9685        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9686        else {
 9687            return;
 9688        };
 9689        if buffer != end_buffer {
 9690            log::error!("expected anchor range to have matching buffer IDs");
 9691            return;
 9692        }
 9693
 9694        let id = post_inc(&mut self.next_completion_id);
 9695        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9696        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9697            CompletionsMenu::new_snippet_choices(
 9698                id,
 9699                true,
 9700                choices,
 9701                selection,
 9702                buffer,
 9703                snippet_sort_order,
 9704            ),
 9705        ));
 9706    }
 9707
 9708    pub fn insert_snippet(
 9709        &mut self,
 9710        insertion_ranges: &[Range<usize>],
 9711        snippet: Snippet,
 9712        window: &mut Window,
 9713        cx: &mut Context<Self>,
 9714    ) -> Result<()> {
 9715        struct Tabstop<T> {
 9716            is_end_tabstop: bool,
 9717            ranges: Vec<Range<T>>,
 9718            choices: Option<Vec<String>>,
 9719        }
 9720
 9721        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9722            let snippet_text: Arc<str> = snippet.text.clone().into();
 9723            let edits = insertion_ranges
 9724                .iter()
 9725                .cloned()
 9726                .map(|range| (range, snippet_text.clone()));
 9727            let autoindent_mode = AutoindentMode::Block {
 9728                original_indent_columns: Vec::new(),
 9729            };
 9730            buffer.edit(edits, Some(autoindent_mode), cx);
 9731
 9732            let snapshot = &*buffer.read(cx);
 9733            let snippet = &snippet;
 9734            snippet
 9735                .tabstops
 9736                .iter()
 9737                .map(|tabstop| {
 9738                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9739                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9740                    });
 9741                    let mut tabstop_ranges = tabstop
 9742                        .ranges
 9743                        .iter()
 9744                        .flat_map(|tabstop_range| {
 9745                            let mut delta = 0_isize;
 9746                            insertion_ranges.iter().map(move |insertion_range| {
 9747                                let insertion_start = insertion_range.start as isize + delta;
 9748                                delta +=
 9749                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9750
 9751                                let start = ((insertion_start + tabstop_range.start) as usize)
 9752                                    .min(snapshot.len());
 9753                                let end = ((insertion_start + tabstop_range.end) as usize)
 9754                                    .min(snapshot.len());
 9755                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9756                            })
 9757                        })
 9758                        .collect::<Vec<_>>();
 9759                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9760
 9761                    Tabstop {
 9762                        is_end_tabstop,
 9763                        ranges: tabstop_ranges,
 9764                        choices: tabstop.choices.clone(),
 9765                    }
 9766                })
 9767                .collect::<Vec<_>>()
 9768        });
 9769        if let Some(tabstop) = tabstops.first() {
 9770            self.change_selections(Default::default(), window, cx, |s| {
 9771                // Reverse order so that the first range is the newest created selection.
 9772                // Completions will use it and autoscroll will prioritize it.
 9773                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9774            });
 9775
 9776            if let Some(choices) = &tabstop.choices
 9777                && let Some(selection) = tabstop.ranges.first()
 9778            {
 9779                self.show_snippet_choices(choices, selection.clone(), cx)
 9780            }
 9781
 9782            // If we're already at the last tabstop and it's at the end of the snippet,
 9783            // we're done, we don't need to keep the state around.
 9784            if !tabstop.is_end_tabstop {
 9785                let choices = tabstops
 9786                    .iter()
 9787                    .map(|tabstop| tabstop.choices.clone())
 9788                    .collect();
 9789
 9790                let ranges = tabstops
 9791                    .into_iter()
 9792                    .map(|tabstop| tabstop.ranges)
 9793                    .collect::<Vec<_>>();
 9794
 9795                self.snippet_stack.push(SnippetState {
 9796                    active_index: 0,
 9797                    ranges,
 9798                    choices,
 9799                });
 9800            }
 9801
 9802            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9803            if self.autoclose_regions.is_empty() {
 9804                let snapshot = self.buffer.read(cx).snapshot(cx);
 9805                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
 9806                    let selection_head = selection.head();
 9807                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9808                        continue;
 9809                    };
 9810
 9811                    let mut bracket_pair = None;
 9812                    let max_lookup_length = scope
 9813                        .brackets()
 9814                        .map(|(pair, _)| {
 9815                            pair.start
 9816                                .as_str()
 9817                                .chars()
 9818                                .count()
 9819                                .max(pair.end.as_str().chars().count())
 9820                        })
 9821                        .max();
 9822                    if let Some(max_lookup_length) = max_lookup_length {
 9823                        let next_text = snapshot
 9824                            .chars_at(selection_head)
 9825                            .take(max_lookup_length)
 9826                            .collect::<String>();
 9827                        let prev_text = snapshot
 9828                            .reversed_chars_at(selection_head)
 9829                            .take(max_lookup_length)
 9830                            .collect::<String>();
 9831
 9832                        for (pair, enabled) in scope.brackets() {
 9833                            if enabled
 9834                                && pair.close
 9835                                && prev_text.starts_with(pair.start.as_str())
 9836                                && next_text.starts_with(pair.end.as_str())
 9837                            {
 9838                                bracket_pair = Some(pair.clone());
 9839                                break;
 9840                            }
 9841                        }
 9842                    }
 9843
 9844                    if let Some(pair) = bracket_pair {
 9845                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9846                        let autoclose_enabled =
 9847                            self.use_autoclose && snapshot_settings.use_autoclose;
 9848                        if autoclose_enabled {
 9849                            let start = snapshot.anchor_after(selection_head);
 9850                            let end = snapshot.anchor_after(selection_head);
 9851                            self.autoclose_regions.push(AutocloseRegion {
 9852                                selection_id: selection.id,
 9853                                range: start..end,
 9854                                pair,
 9855                            });
 9856                        }
 9857                    }
 9858                }
 9859            }
 9860        }
 9861        Ok(())
 9862    }
 9863
 9864    pub fn move_to_next_snippet_tabstop(
 9865        &mut self,
 9866        window: &mut Window,
 9867        cx: &mut Context<Self>,
 9868    ) -> bool {
 9869        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9870    }
 9871
 9872    pub fn move_to_prev_snippet_tabstop(
 9873        &mut self,
 9874        window: &mut Window,
 9875        cx: &mut Context<Self>,
 9876    ) -> bool {
 9877        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9878    }
 9879
 9880    pub fn move_to_snippet_tabstop(
 9881        &mut self,
 9882        bias: Bias,
 9883        window: &mut Window,
 9884        cx: &mut Context<Self>,
 9885    ) -> bool {
 9886        if let Some(mut snippet) = self.snippet_stack.pop() {
 9887            match bias {
 9888                Bias::Left => {
 9889                    if snippet.active_index > 0 {
 9890                        snippet.active_index -= 1;
 9891                    } else {
 9892                        self.snippet_stack.push(snippet);
 9893                        return false;
 9894                    }
 9895                }
 9896                Bias::Right => {
 9897                    if snippet.active_index + 1 < snippet.ranges.len() {
 9898                        snippet.active_index += 1;
 9899                    } else {
 9900                        self.snippet_stack.push(snippet);
 9901                        return false;
 9902                    }
 9903                }
 9904            }
 9905            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9906                self.change_selections(Default::default(), window, cx, |s| {
 9907                    // Reverse order so that the first range is the newest created selection.
 9908                    // Completions will use it and autoscroll will prioritize it.
 9909                    s.select_ranges(current_ranges.iter().rev().cloned())
 9910                });
 9911
 9912                if let Some(choices) = &snippet.choices[snippet.active_index]
 9913                    && let Some(selection) = current_ranges.first()
 9914                {
 9915                    self.show_snippet_choices(choices, selection.clone(), cx);
 9916                }
 9917
 9918                // If snippet state is not at the last tabstop, push it back on the stack
 9919                if snippet.active_index + 1 < snippet.ranges.len() {
 9920                    self.snippet_stack.push(snippet);
 9921                }
 9922                return true;
 9923            }
 9924        }
 9925
 9926        false
 9927    }
 9928
 9929    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9930        self.transact(window, cx, |this, window, cx| {
 9931            this.select_all(&SelectAll, window, cx);
 9932            this.insert("", window, cx);
 9933        });
 9934    }
 9935
 9936    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9937        if self.read_only(cx) {
 9938            return;
 9939        }
 9940        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9941        self.transact(window, cx, |this, window, cx| {
 9942            this.select_autoclose_pair(window, cx);
 9943
 9944            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9945
 9946            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9947            if !this.linked_edit_ranges.is_empty() {
 9948                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
 9949                let snapshot = this.buffer.read(cx).snapshot(cx);
 9950
 9951                for selection in selections.iter() {
 9952                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9953                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9954                    if selection_start.buffer_id != selection_end.buffer_id {
 9955                        continue;
 9956                    }
 9957                    if let Some(ranges) =
 9958                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9959                    {
 9960                        for (buffer, entries) in ranges {
 9961                            linked_ranges.entry(buffer).or_default().extend(entries);
 9962                        }
 9963                    }
 9964                }
 9965            }
 9966
 9967            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
 9968            for selection in &mut selections {
 9969                if selection.is_empty() {
 9970                    let old_head = selection.head();
 9971                    let mut new_head =
 9972                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9973                            .to_point(&display_map);
 9974                    if let Some((buffer, line_buffer_range)) = display_map
 9975                        .buffer_snapshot()
 9976                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9977                    {
 9978                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9979                        let indent_len = match indent_size.kind {
 9980                            IndentKind::Space => {
 9981                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9982                            }
 9983                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9984                        };
 9985                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9986                            let indent_len = indent_len.get();
 9987                            new_head = cmp::min(
 9988                                new_head,
 9989                                MultiBufferPoint::new(
 9990                                    old_head.row,
 9991                                    ((old_head.column - 1) / indent_len) * indent_len,
 9992                                ),
 9993                            );
 9994                        }
 9995                    }
 9996
 9997                    selection.set_head(new_head, SelectionGoal::None);
 9998                }
 9999            }
10000
10001            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10002            this.insert("", window, cx);
10003            let empty_str: Arc<str> = Arc::from("");
10004            for (buffer, edits) in linked_ranges {
10005                let snapshot = buffer.read(cx).snapshot();
10006                use text::ToPoint as TP;
10007
10008                let edits = edits
10009                    .into_iter()
10010                    .map(|range| {
10011                        let end_point = TP::to_point(&range.end, &snapshot);
10012                        let mut start_point = TP::to_point(&range.start, &snapshot);
10013
10014                        if end_point == start_point {
10015                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10016                                .saturating_sub(1);
10017                            start_point =
10018                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10019                        };
10020
10021                        (start_point..end_point, empty_str.clone())
10022                    })
10023                    .sorted_by_key(|(range, _)| range.start)
10024                    .collect::<Vec<_>>();
10025                buffer.update(cx, |this, cx| {
10026                    this.edit(edits, None, cx);
10027                })
10028            }
10029            this.refresh_edit_prediction(true, false, window, cx);
10030            refresh_linked_ranges(this, window, cx);
10031        });
10032    }
10033
10034    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10035        if self.read_only(cx) {
10036            return;
10037        }
10038        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10039        self.transact(window, cx, |this, window, cx| {
10040            this.change_selections(Default::default(), window, cx, |s| {
10041                s.move_with(|map, selection| {
10042                    if selection.is_empty() {
10043                        let cursor = movement::right(map, selection.head());
10044                        selection.end = cursor;
10045                        selection.reversed = true;
10046                        selection.goal = SelectionGoal::None;
10047                    }
10048                })
10049            });
10050            this.insert("", window, cx);
10051            this.refresh_edit_prediction(true, false, window, cx);
10052        });
10053    }
10054
10055    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10056        if self.mode.is_single_line() {
10057            cx.propagate();
10058            return;
10059        }
10060
10061        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10062        if self.move_to_prev_snippet_tabstop(window, cx) {
10063            return;
10064        }
10065        self.outdent(&Outdent, window, cx);
10066    }
10067
10068    pub fn next_snippet_tabstop(
10069        &mut self,
10070        _: &NextSnippetTabstop,
10071        window: &mut Window,
10072        cx: &mut Context<Self>,
10073    ) {
10074        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10075            cx.propagate();
10076            return;
10077        }
10078
10079        if self.move_to_next_snippet_tabstop(window, cx) {
10080            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10081            return;
10082        }
10083        cx.propagate();
10084    }
10085
10086    pub fn previous_snippet_tabstop(
10087        &mut self,
10088        _: &PreviousSnippetTabstop,
10089        window: &mut Window,
10090        cx: &mut Context<Self>,
10091    ) {
10092        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10093            cx.propagate();
10094            return;
10095        }
10096
10097        if self.move_to_prev_snippet_tabstop(window, cx) {
10098            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10099            return;
10100        }
10101        cx.propagate();
10102    }
10103
10104    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10105        if self.mode.is_single_line() {
10106            cx.propagate();
10107            return;
10108        }
10109
10110        if self.move_to_next_snippet_tabstop(window, cx) {
10111            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10112            return;
10113        }
10114        if self.read_only(cx) {
10115            return;
10116        }
10117        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10118        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10119        let buffer = self.buffer.read(cx);
10120        let snapshot = buffer.snapshot(cx);
10121        let rows_iter = selections.iter().map(|s| s.head().row);
10122        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10123
10124        let has_some_cursor_in_whitespace = selections
10125            .iter()
10126            .filter(|selection| selection.is_empty())
10127            .any(|selection| {
10128                let cursor = selection.head();
10129                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10130                cursor.column < current_indent.len
10131            });
10132
10133        let mut edits = Vec::new();
10134        let mut prev_edited_row = 0;
10135        let mut row_delta = 0;
10136        for selection in &mut selections {
10137            if selection.start.row != prev_edited_row {
10138                row_delta = 0;
10139            }
10140            prev_edited_row = selection.end.row;
10141
10142            // If the selection is non-empty, then increase the indentation of the selected lines.
10143            if !selection.is_empty() {
10144                row_delta =
10145                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10146                continue;
10147            }
10148
10149            let cursor = selection.head();
10150            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10151            if let Some(suggested_indent) =
10152                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10153            {
10154                // Don't do anything if already at suggested indent
10155                // and there is any other cursor which is not
10156                if has_some_cursor_in_whitespace
10157                    && cursor.column == current_indent.len
10158                    && current_indent.len == suggested_indent.len
10159                {
10160                    continue;
10161                }
10162
10163                // Adjust line and move cursor to suggested indent
10164                // if cursor is not at suggested indent
10165                if cursor.column < suggested_indent.len
10166                    && cursor.column <= current_indent.len
10167                    && current_indent.len <= suggested_indent.len
10168                {
10169                    selection.start = Point::new(cursor.row, suggested_indent.len);
10170                    selection.end = selection.start;
10171                    if row_delta == 0 {
10172                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10173                            cursor.row,
10174                            current_indent,
10175                            suggested_indent,
10176                        ));
10177                        row_delta = suggested_indent.len - current_indent.len;
10178                    }
10179                    continue;
10180                }
10181
10182                // If current indent is more than suggested indent
10183                // only move cursor to current indent and skip indent
10184                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10185                    selection.start = Point::new(cursor.row, current_indent.len);
10186                    selection.end = selection.start;
10187                    continue;
10188                }
10189            }
10190
10191            // Otherwise, insert a hard or soft tab.
10192            let settings = buffer.language_settings_at(cursor, cx);
10193            let tab_size = if settings.hard_tabs {
10194                IndentSize::tab()
10195            } else {
10196                let tab_size = settings.tab_size.get();
10197                let indent_remainder = snapshot
10198                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10199                    .flat_map(str::chars)
10200                    .fold(row_delta % tab_size, |counter: u32, c| {
10201                        if c == '\t' {
10202                            0
10203                        } else {
10204                            (counter + 1) % tab_size
10205                        }
10206                    });
10207
10208                let chars_to_next_tab_stop = tab_size - indent_remainder;
10209                IndentSize::spaces(chars_to_next_tab_stop)
10210            };
10211            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10212            selection.end = selection.start;
10213            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10214            row_delta += tab_size.len;
10215        }
10216
10217        self.transact(window, cx, |this, window, cx| {
10218            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10219            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10220            this.refresh_edit_prediction(true, false, window, cx);
10221        });
10222    }
10223
10224    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10225        if self.read_only(cx) {
10226            return;
10227        }
10228        if self.mode.is_single_line() {
10229            cx.propagate();
10230            return;
10231        }
10232
10233        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10234        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10235        let mut prev_edited_row = 0;
10236        let mut row_delta = 0;
10237        let mut edits = Vec::new();
10238        let buffer = self.buffer.read(cx);
10239        let snapshot = buffer.snapshot(cx);
10240        for selection in &mut selections {
10241            if selection.start.row != prev_edited_row {
10242                row_delta = 0;
10243            }
10244            prev_edited_row = selection.end.row;
10245
10246            row_delta =
10247                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10248        }
10249
10250        self.transact(window, cx, |this, window, cx| {
10251            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10252            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10253        });
10254    }
10255
10256    fn indent_selection(
10257        buffer: &MultiBuffer,
10258        snapshot: &MultiBufferSnapshot,
10259        selection: &mut Selection<Point>,
10260        edits: &mut Vec<(Range<Point>, String)>,
10261        delta_for_start_row: u32,
10262        cx: &App,
10263    ) -> u32 {
10264        let settings = buffer.language_settings_at(selection.start, cx);
10265        let tab_size = settings.tab_size.get();
10266        let indent_kind = if settings.hard_tabs {
10267            IndentKind::Tab
10268        } else {
10269            IndentKind::Space
10270        };
10271        let mut start_row = selection.start.row;
10272        let mut end_row = selection.end.row + 1;
10273
10274        // If a selection ends at the beginning of a line, don't indent
10275        // that last line.
10276        if selection.end.column == 0 && selection.end.row > selection.start.row {
10277            end_row -= 1;
10278        }
10279
10280        // Avoid re-indenting a row that has already been indented by a
10281        // previous selection, but still update this selection's column
10282        // to reflect that indentation.
10283        if delta_for_start_row > 0 {
10284            start_row += 1;
10285            selection.start.column += delta_for_start_row;
10286            if selection.end.row == selection.start.row {
10287                selection.end.column += delta_for_start_row;
10288            }
10289        }
10290
10291        let mut delta_for_end_row = 0;
10292        let has_multiple_rows = start_row + 1 != end_row;
10293        for row in start_row..end_row {
10294            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10295            let indent_delta = match (current_indent.kind, indent_kind) {
10296                (IndentKind::Space, IndentKind::Space) => {
10297                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10298                    IndentSize::spaces(columns_to_next_tab_stop)
10299                }
10300                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10301                (_, IndentKind::Tab) => IndentSize::tab(),
10302            };
10303
10304            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10305                0
10306            } else {
10307                selection.start.column
10308            };
10309            let row_start = Point::new(row, start);
10310            edits.push((
10311                row_start..row_start,
10312                indent_delta.chars().collect::<String>(),
10313            ));
10314
10315            // Update this selection's endpoints to reflect the indentation.
10316            if row == selection.start.row {
10317                selection.start.column += indent_delta.len;
10318            }
10319            if row == selection.end.row {
10320                selection.end.column += indent_delta.len;
10321                delta_for_end_row = indent_delta.len;
10322            }
10323        }
10324
10325        if selection.start.row == selection.end.row {
10326            delta_for_start_row + delta_for_end_row
10327        } else {
10328            delta_for_end_row
10329        }
10330    }
10331
10332    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10333        if self.read_only(cx) {
10334            return;
10335        }
10336        if self.mode.is_single_line() {
10337            cx.propagate();
10338            return;
10339        }
10340
10341        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10342        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10343        let selections = self.selections.all::<Point>(&display_map);
10344        let mut deletion_ranges = Vec::new();
10345        let mut last_outdent = None;
10346        {
10347            let buffer = self.buffer.read(cx);
10348            let snapshot = buffer.snapshot(cx);
10349            for selection in &selections {
10350                let settings = buffer.language_settings_at(selection.start, cx);
10351                let tab_size = settings.tab_size.get();
10352                let mut rows = selection.spanned_rows(false, &display_map);
10353
10354                // Avoid re-outdenting a row that has already been outdented by a
10355                // previous selection.
10356                if let Some(last_row) = last_outdent
10357                    && last_row == rows.start
10358                {
10359                    rows.start = rows.start.next_row();
10360                }
10361                let has_multiple_rows = rows.len() > 1;
10362                for row in rows.iter_rows() {
10363                    let indent_size = snapshot.indent_size_for_line(row);
10364                    if indent_size.len > 0 {
10365                        let deletion_len = match indent_size.kind {
10366                            IndentKind::Space => {
10367                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10368                                if columns_to_prev_tab_stop == 0 {
10369                                    tab_size
10370                                } else {
10371                                    columns_to_prev_tab_stop
10372                                }
10373                            }
10374                            IndentKind::Tab => 1,
10375                        };
10376                        let start = if has_multiple_rows
10377                            || deletion_len > selection.start.column
10378                            || indent_size.len < selection.start.column
10379                        {
10380                            0
10381                        } else {
10382                            selection.start.column - deletion_len
10383                        };
10384                        deletion_ranges.push(
10385                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10386                        );
10387                        last_outdent = Some(row);
10388                    }
10389                }
10390            }
10391        }
10392
10393        self.transact(window, cx, |this, window, cx| {
10394            this.buffer.update(cx, |buffer, cx| {
10395                let empty_str: Arc<str> = Arc::default();
10396                buffer.edit(
10397                    deletion_ranges
10398                        .into_iter()
10399                        .map(|range| (range, empty_str.clone())),
10400                    None,
10401                    cx,
10402                );
10403            });
10404            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10405            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10406        });
10407    }
10408
10409    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10410        if self.read_only(cx) {
10411            return;
10412        }
10413        if self.mode.is_single_line() {
10414            cx.propagate();
10415            return;
10416        }
10417
10418        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10419        let selections = self
10420            .selections
10421            .all::<usize>(&self.display_snapshot(cx))
10422            .into_iter()
10423            .map(|s| s.range());
10424
10425        self.transact(window, cx, |this, window, cx| {
10426            this.buffer.update(cx, |buffer, cx| {
10427                buffer.autoindent_ranges(selections, cx);
10428            });
10429            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10430            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10431        });
10432    }
10433
10434    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10435        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10436        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10437        let selections = self.selections.all::<Point>(&display_map);
10438
10439        let mut new_cursors = Vec::new();
10440        let mut edit_ranges = Vec::new();
10441        let mut selections = selections.iter().peekable();
10442        while let Some(selection) = selections.next() {
10443            let mut rows = selection.spanned_rows(false, &display_map);
10444
10445            // Accumulate contiguous regions of rows that we want to delete.
10446            while let Some(next_selection) = selections.peek() {
10447                let next_rows = next_selection.spanned_rows(false, &display_map);
10448                if next_rows.start <= rows.end {
10449                    rows.end = next_rows.end;
10450                    selections.next().unwrap();
10451                } else {
10452                    break;
10453                }
10454            }
10455
10456            let buffer = display_map.buffer_snapshot();
10457            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10458            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10459                // If there's a line after the range, delete the \n from the end of the row range
10460                (
10461                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10462                    rows.end,
10463                )
10464            } else {
10465                // If there isn't a line after the range, delete the \n from the line before the
10466                // start of the row range
10467                edit_start = edit_start.saturating_sub(1);
10468                (buffer.len(), rows.start.previous_row())
10469            };
10470
10471            let text_layout_details = self.text_layout_details(window);
10472            let x = display_map.x_for_display_point(
10473                selection.head().to_display_point(&display_map),
10474                &text_layout_details,
10475            );
10476            let row = Point::new(target_row.0, 0)
10477                .to_display_point(&display_map)
10478                .row();
10479            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10480
10481            new_cursors.push((
10482                selection.id,
10483                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10484                SelectionGoal::None,
10485            ));
10486            edit_ranges.push(edit_start..edit_end);
10487        }
10488
10489        self.transact(window, cx, |this, window, cx| {
10490            let buffer = this.buffer.update(cx, |buffer, cx| {
10491                let empty_str: Arc<str> = Arc::default();
10492                buffer.edit(
10493                    edit_ranges
10494                        .into_iter()
10495                        .map(|range| (range, empty_str.clone())),
10496                    None,
10497                    cx,
10498                );
10499                buffer.snapshot(cx)
10500            });
10501            let new_selections = new_cursors
10502                .into_iter()
10503                .map(|(id, cursor, goal)| {
10504                    let cursor = cursor.to_point(&buffer);
10505                    Selection {
10506                        id,
10507                        start: cursor,
10508                        end: cursor,
10509                        reversed: false,
10510                        goal,
10511                    }
10512                })
10513                .collect();
10514
10515            this.change_selections(Default::default(), window, cx, |s| {
10516                s.select(new_selections);
10517            });
10518        });
10519    }
10520
10521    pub fn join_lines_impl(
10522        &mut self,
10523        insert_whitespace: bool,
10524        window: &mut Window,
10525        cx: &mut Context<Self>,
10526    ) {
10527        if self.read_only(cx) {
10528            return;
10529        }
10530        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10531        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10532            let start = MultiBufferRow(selection.start.row);
10533            // Treat single line selections as if they include the next line. Otherwise this action
10534            // would do nothing for single line selections individual cursors.
10535            let end = if selection.start.row == selection.end.row {
10536                MultiBufferRow(selection.start.row + 1)
10537            } else {
10538                MultiBufferRow(selection.end.row)
10539            };
10540
10541            if let Some(last_row_range) = row_ranges.last_mut()
10542                && start <= last_row_range.end
10543            {
10544                last_row_range.end = end;
10545                continue;
10546            }
10547            row_ranges.push(start..end);
10548        }
10549
10550        let snapshot = self.buffer.read(cx).snapshot(cx);
10551        let mut cursor_positions = Vec::new();
10552        for row_range in &row_ranges {
10553            let anchor = snapshot.anchor_before(Point::new(
10554                row_range.end.previous_row().0,
10555                snapshot.line_len(row_range.end.previous_row()),
10556            ));
10557            cursor_positions.push(anchor..anchor);
10558        }
10559
10560        self.transact(window, cx, |this, window, cx| {
10561            for row_range in row_ranges.into_iter().rev() {
10562                for row in row_range.iter_rows().rev() {
10563                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10564                    let next_line_row = row.next_row();
10565                    let indent = snapshot.indent_size_for_line(next_line_row);
10566                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10567
10568                    let replace =
10569                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10570                            " "
10571                        } else {
10572                            ""
10573                        };
10574
10575                    this.buffer.update(cx, |buffer, cx| {
10576                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10577                    });
10578                }
10579            }
10580
10581            this.change_selections(Default::default(), window, cx, |s| {
10582                s.select_anchor_ranges(cursor_positions)
10583            });
10584        });
10585    }
10586
10587    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10588        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10589        self.join_lines_impl(true, window, cx);
10590    }
10591
10592    pub fn sort_lines_case_sensitive(
10593        &mut self,
10594        _: &SortLinesCaseSensitive,
10595        window: &mut Window,
10596        cx: &mut Context<Self>,
10597    ) {
10598        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10599    }
10600
10601    pub fn sort_lines_by_length(
10602        &mut self,
10603        _: &SortLinesByLength,
10604        window: &mut Window,
10605        cx: &mut Context<Self>,
10606    ) {
10607        self.manipulate_immutable_lines(window, cx, |lines| {
10608            lines.sort_by_key(|&line| line.chars().count())
10609        })
10610    }
10611
10612    pub fn sort_lines_case_insensitive(
10613        &mut self,
10614        _: &SortLinesCaseInsensitive,
10615        window: &mut Window,
10616        cx: &mut Context<Self>,
10617    ) {
10618        self.manipulate_immutable_lines(window, cx, |lines| {
10619            lines.sort_by_key(|line| line.to_lowercase())
10620        })
10621    }
10622
10623    pub fn unique_lines_case_insensitive(
10624        &mut self,
10625        _: &UniqueLinesCaseInsensitive,
10626        window: &mut Window,
10627        cx: &mut Context<Self>,
10628    ) {
10629        self.manipulate_immutable_lines(window, cx, |lines| {
10630            let mut seen = HashSet::default();
10631            lines.retain(|line| seen.insert(line.to_lowercase()));
10632        })
10633    }
10634
10635    pub fn unique_lines_case_sensitive(
10636        &mut self,
10637        _: &UniqueLinesCaseSensitive,
10638        window: &mut Window,
10639        cx: &mut Context<Self>,
10640    ) {
10641        self.manipulate_immutable_lines(window, cx, |lines| {
10642            let mut seen = HashSet::default();
10643            lines.retain(|line| seen.insert(*line));
10644        })
10645    }
10646
10647    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10648        let snapshot = self.buffer.read(cx).snapshot(cx);
10649        for selection in self.selections.disjoint_anchors_arc().iter() {
10650            if snapshot
10651                .language_at(selection.start)
10652                .and_then(|lang| lang.config().wrap_characters.as_ref())
10653                .is_some()
10654            {
10655                return true;
10656            }
10657        }
10658        false
10659    }
10660
10661    fn wrap_selections_in_tag(
10662        &mut self,
10663        _: &WrapSelectionsInTag,
10664        window: &mut Window,
10665        cx: &mut Context<Self>,
10666    ) {
10667        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10668
10669        let snapshot = self.buffer.read(cx).snapshot(cx);
10670
10671        let mut edits = Vec::new();
10672        let mut boundaries = Vec::new();
10673
10674        for selection in self
10675            .selections
10676            .all_adjusted(&self.display_snapshot(cx))
10677            .iter()
10678        {
10679            let Some(wrap_config) = snapshot
10680                .language_at(selection.start)
10681                .and_then(|lang| lang.config().wrap_characters.clone())
10682            else {
10683                continue;
10684            };
10685
10686            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10687            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10688
10689            let start_before = snapshot.anchor_before(selection.start);
10690            let end_after = snapshot.anchor_after(selection.end);
10691
10692            edits.push((start_before..start_before, open_tag));
10693            edits.push((end_after..end_after, close_tag));
10694
10695            boundaries.push((
10696                start_before,
10697                end_after,
10698                wrap_config.start_prefix.len(),
10699                wrap_config.end_suffix.len(),
10700            ));
10701        }
10702
10703        if edits.is_empty() {
10704            return;
10705        }
10706
10707        self.transact(window, cx, |this, window, cx| {
10708            let buffer = this.buffer.update(cx, |buffer, cx| {
10709                buffer.edit(edits, None, cx);
10710                buffer.snapshot(cx)
10711            });
10712
10713            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10714            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10715                boundaries.into_iter()
10716            {
10717                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10718                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10719                new_selections.push(open_offset..open_offset);
10720                new_selections.push(close_offset..close_offset);
10721            }
10722
10723            this.change_selections(Default::default(), window, cx, |s| {
10724                s.select_ranges(new_selections);
10725            });
10726
10727            this.request_autoscroll(Autoscroll::fit(), cx);
10728        });
10729    }
10730
10731    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10732        let Some(project) = self.project.clone() else {
10733            return;
10734        };
10735        self.reload(project, window, cx)
10736            .detach_and_notify_err(window, cx);
10737    }
10738
10739    pub fn restore_file(
10740        &mut self,
10741        _: &::git::RestoreFile,
10742        window: &mut Window,
10743        cx: &mut Context<Self>,
10744    ) {
10745        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10746        let mut buffer_ids = HashSet::default();
10747        let snapshot = self.buffer().read(cx).snapshot(cx);
10748        for selection in self.selections.all::<usize>(&self.display_snapshot(cx)) {
10749            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10750        }
10751
10752        let buffer = self.buffer().read(cx);
10753        let ranges = buffer_ids
10754            .into_iter()
10755            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10756            .collect::<Vec<_>>();
10757
10758        self.restore_hunks_in_ranges(ranges, window, cx);
10759    }
10760
10761    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10762        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10763        let selections = self
10764            .selections
10765            .all(&self.display_snapshot(cx))
10766            .into_iter()
10767            .map(|s| s.range())
10768            .collect();
10769        self.restore_hunks_in_ranges(selections, window, cx);
10770    }
10771
10772    pub fn restore_hunks_in_ranges(
10773        &mut self,
10774        ranges: Vec<Range<Point>>,
10775        window: &mut Window,
10776        cx: &mut Context<Editor>,
10777    ) {
10778        let mut revert_changes = HashMap::default();
10779        let chunk_by = self
10780            .snapshot(window, cx)
10781            .hunks_for_ranges(ranges)
10782            .into_iter()
10783            .chunk_by(|hunk| hunk.buffer_id);
10784        for (buffer_id, hunks) in &chunk_by {
10785            let hunks = hunks.collect::<Vec<_>>();
10786            for hunk in &hunks {
10787                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10788            }
10789            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10790        }
10791        drop(chunk_by);
10792        if !revert_changes.is_empty() {
10793            self.transact(window, cx, |editor, window, cx| {
10794                editor.restore(revert_changes, window, cx);
10795            });
10796        }
10797    }
10798
10799    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
10800        if let Some(status) = self
10801            .addons
10802            .iter()
10803            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
10804        {
10805            return Some(status);
10806        }
10807        self.project
10808            .as_ref()?
10809            .read(cx)
10810            .status_for_buffer_id(buffer_id, cx)
10811    }
10812
10813    pub fn open_active_item_in_terminal(
10814        &mut self,
10815        _: &OpenInTerminal,
10816        window: &mut Window,
10817        cx: &mut Context<Self>,
10818    ) {
10819        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10820            let project_path = buffer.read(cx).project_path(cx)?;
10821            let project = self.project()?.read(cx);
10822            let entry = project.entry_for_path(&project_path, cx)?;
10823            let parent = match &entry.canonical_path {
10824                Some(canonical_path) => canonical_path.to_path_buf(),
10825                None => project.absolute_path(&project_path, cx)?,
10826            }
10827            .parent()?
10828            .to_path_buf();
10829            Some(parent)
10830        }) {
10831            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10832        }
10833    }
10834
10835    fn set_breakpoint_context_menu(
10836        &mut self,
10837        display_row: DisplayRow,
10838        position: Option<Anchor>,
10839        clicked_point: gpui::Point<Pixels>,
10840        window: &mut Window,
10841        cx: &mut Context<Self>,
10842    ) {
10843        let source = self
10844            .buffer
10845            .read(cx)
10846            .snapshot(cx)
10847            .anchor_before(Point::new(display_row.0, 0u32));
10848
10849        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10850
10851        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10852            self,
10853            source,
10854            clicked_point,
10855            context_menu,
10856            window,
10857            cx,
10858        );
10859    }
10860
10861    fn add_edit_breakpoint_block(
10862        &mut self,
10863        anchor: Anchor,
10864        breakpoint: &Breakpoint,
10865        edit_action: BreakpointPromptEditAction,
10866        window: &mut Window,
10867        cx: &mut Context<Self>,
10868    ) {
10869        let weak_editor = cx.weak_entity();
10870        let bp_prompt = cx.new(|cx| {
10871            BreakpointPromptEditor::new(
10872                weak_editor,
10873                anchor,
10874                breakpoint.clone(),
10875                edit_action,
10876                window,
10877                cx,
10878            )
10879        });
10880
10881        let height = bp_prompt.update(cx, |this, cx| {
10882            this.prompt
10883                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10884        });
10885        let cloned_prompt = bp_prompt.clone();
10886        let blocks = vec![BlockProperties {
10887            style: BlockStyle::Sticky,
10888            placement: BlockPlacement::Above(anchor),
10889            height: Some(height),
10890            render: Arc::new(move |cx| {
10891                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10892                cloned_prompt.clone().into_any_element()
10893            }),
10894            priority: 0,
10895        }];
10896
10897        let focus_handle = bp_prompt.focus_handle(cx);
10898        window.focus(&focus_handle);
10899
10900        let block_ids = self.insert_blocks(blocks, None, cx);
10901        bp_prompt.update(cx, |prompt, _| {
10902            prompt.add_block_ids(block_ids);
10903        });
10904    }
10905
10906    pub(crate) fn breakpoint_at_row(
10907        &self,
10908        row: u32,
10909        window: &mut Window,
10910        cx: &mut Context<Self>,
10911    ) -> Option<(Anchor, Breakpoint)> {
10912        let snapshot = self.snapshot(window, cx);
10913        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
10914
10915        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10916    }
10917
10918    pub(crate) fn breakpoint_at_anchor(
10919        &self,
10920        breakpoint_position: Anchor,
10921        snapshot: &EditorSnapshot,
10922        cx: &mut Context<Self>,
10923    ) -> Option<(Anchor, Breakpoint)> {
10924        let buffer = self
10925            .buffer
10926            .read(cx)
10927            .buffer_for_anchor(breakpoint_position, cx)?;
10928
10929        let enclosing_excerpt = breakpoint_position.excerpt_id;
10930        let buffer_snapshot = buffer.read(cx).snapshot();
10931
10932        let row = buffer_snapshot
10933            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10934            .row;
10935
10936        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
10937        let anchor_end = snapshot
10938            .buffer_snapshot()
10939            .anchor_after(Point::new(row, line_len));
10940
10941        self.breakpoint_store
10942            .as_ref()?
10943            .read_with(cx, |breakpoint_store, cx| {
10944                breakpoint_store
10945                    .breakpoints(
10946                        &buffer,
10947                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10948                        &buffer_snapshot,
10949                        cx,
10950                    )
10951                    .next()
10952                    .and_then(|(bp, _)| {
10953                        let breakpoint_row = buffer_snapshot
10954                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10955                            .row;
10956
10957                        if breakpoint_row == row {
10958                            snapshot
10959                                .buffer_snapshot()
10960                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10961                                .map(|position| (position, bp.bp.clone()))
10962                        } else {
10963                            None
10964                        }
10965                    })
10966            })
10967    }
10968
10969    pub fn edit_log_breakpoint(
10970        &mut self,
10971        _: &EditLogBreakpoint,
10972        window: &mut Window,
10973        cx: &mut Context<Self>,
10974    ) {
10975        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10976            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10977                message: None,
10978                state: BreakpointState::Enabled,
10979                condition: None,
10980                hit_condition: None,
10981            });
10982
10983            self.add_edit_breakpoint_block(
10984                anchor,
10985                &breakpoint,
10986                BreakpointPromptEditAction::Log,
10987                window,
10988                cx,
10989            );
10990        }
10991    }
10992
10993    fn breakpoints_at_cursors(
10994        &self,
10995        window: &mut Window,
10996        cx: &mut Context<Self>,
10997    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10998        let snapshot = self.snapshot(window, cx);
10999        let cursors = self
11000            .selections
11001            .disjoint_anchors_arc()
11002            .iter()
11003            .map(|selection| {
11004                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11005
11006                let breakpoint_position = self
11007                    .breakpoint_at_row(cursor_position.row, window, cx)
11008                    .map(|bp| bp.0)
11009                    .unwrap_or_else(|| {
11010                        snapshot
11011                            .display_snapshot
11012                            .buffer_snapshot()
11013                            .anchor_after(Point::new(cursor_position.row, 0))
11014                    });
11015
11016                let breakpoint = self
11017                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11018                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11019
11020                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11021            })
11022            // 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.
11023            .collect::<HashMap<Anchor, _>>();
11024
11025        cursors.into_iter().collect()
11026    }
11027
11028    pub fn enable_breakpoint(
11029        &mut self,
11030        _: &crate::actions::EnableBreakpoint,
11031        window: &mut Window,
11032        cx: &mut Context<Self>,
11033    ) {
11034        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11035            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11036                continue;
11037            };
11038            self.edit_breakpoint_at_anchor(
11039                anchor,
11040                breakpoint,
11041                BreakpointEditAction::InvertState,
11042                cx,
11043            );
11044        }
11045    }
11046
11047    pub fn disable_breakpoint(
11048        &mut self,
11049        _: &crate::actions::DisableBreakpoint,
11050        window: &mut Window,
11051        cx: &mut Context<Self>,
11052    ) {
11053        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11054            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11055                continue;
11056            };
11057            self.edit_breakpoint_at_anchor(
11058                anchor,
11059                breakpoint,
11060                BreakpointEditAction::InvertState,
11061                cx,
11062            );
11063        }
11064    }
11065
11066    pub fn toggle_breakpoint(
11067        &mut self,
11068        _: &crate::actions::ToggleBreakpoint,
11069        window: &mut Window,
11070        cx: &mut Context<Self>,
11071    ) {
11072        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11073            if let Some(breakpoint) = breakpoint {
11074                self.edit_breakpoint_at_anchor(
11075                    anchor,
11076                    breakpoint,
11077                    BreakpointEditAction::Toggle,
11078                    cx,
11079                );
11080            } else {
11081                self.edit_breakpoint_at_anchor(
11082                    anchor,
11083                    Breakpoint::new_standard(),
11084                    BreakpointEditAction::Toggle,
11085                    cx,
11086                );
11087            }
11088        }
11089    }
11090
11091    pub fn edit_breakpoint_at_anchor(
11092        &mut self,
11093        breakpoint_position: Anchor,
11094        breakpoint: Breakpoint,
11095        edit_action: BreakpointEditAction,
11096        cx: &mut Context<Self>,
11097    ) {
11098        let Some(breakpoint_store) = &self.breakpoint_store else {
11099            return;
11100        };
11101
11102        let Some(buffer) = self
11103            .buffer
11104            .read(cx)
11105            .buffer_for_anchor(breakpoint_position, cx)
11106        else {
11107            return;
11108        };
11109
11110        breakpoint_store.update(cx, |breakpoint_store, cx| {
11111            breakpoint_store.toggle_breakpoint(
11112                buffer,
11113                BreakpointWithPosition {
11114                    position: breakpoint_position.text_anchor,
11115                    bp: breakpoint,
11116                },
11117                edit_action,
11118                cx,
11119            );
11120        });
11121
11122        cx.notify();
11123    }
11124
11125    #[cfg(any(test, feature = "test-support"))]
11126    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11127        self.breakpoint_store.clone()
11128    }
11129
11130    pub fn prepare_restore_change(
11131        &self,
11132        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11133        hunk: &MultiBufferDiffHunk,
11134        cx: &mut App,
11135    ) -> Option<()> {
11136        if hunk.is_created_file() {
11137            return None;
11138        }
11139        let buffer = self.buffer.read(cx);
11140        let diff = buffer.diff_for(hunk.buffer_id)?;
11141        let buffer = buffer.buffer(hunk.buffer_id)?;
11142        let buffer = buffer.read(cx);
11143        let original_text = diff
11144            .read(cx)
11145            .base_text()
11146            .as_rope()
11147            .slice(hunk.diff_base_byte_range.clone());
11148        let buffer_snapshot = buffer.snapshot();
11149        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11150        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11151            probe
11152                .0
11153                .start
11154                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11155                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11156        }) {
11157            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11158            Some(())
11159        } else {
11160            None
11161        }
11162    }
11163
11164    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11165        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11166    }
11167
11168    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11169        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11170    }
11171
11172    fn manipulate_lines<M>(
11173        &mut self,
11174        window: &mut Window,
11175        cx: &mut Context<Self>,
11176        mut manipulate: M,
11177    ) where
11178        M: FnMut(&str) -> LineManipulationResult,
11179    {
11180        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11181
11182        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11183        let buffer = self.buffer.read(cx).snapshot(cx);
11184
11185        let mut edits = Vec::new();
11186
11187        let selections = self.selections.all::<Point>(&display_map);
11188        let mut selections = selections.iter().peekable();
11189        let mut contiguous_row_selections = Vec::new();
11190        let mut new_selections = Vec::new();
11191        let mut added_lines = 0;
11192        let mut removed_lines = 0;
11193
11194        while let Some(selection) = selections.next() {
11195            let (start_row, end_row) = consume_contiguous_rows(
11196                &mut contiguous_row_selections,
11197                selection,
11198                &display_map,
11199                &mut selections,
11200            );
11201
11202            let start_point = Point::new(start_row.0, 0);
11203            let end_point = Point::new(
11204                end_row.previous_row().0,
11205                buffer.line_len(end_row.previous_row()),
11206            );
11207            let text = buffer
11208                .text_for_range(start_point..end_point)
11209                .collect::<String>();
11210
11211            let LineManipulationResult {
11212                new_text,
11213                line_count_before,
11214                line_count_after,
11215            } = manipulate(&text);
11216
11217            edits.push((start_point..end_point, new_text));
11218
11219            // Selections must change based on added and removed line count
11220            let start_row =
11221                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11222            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11223            new_selections.push(Selection {
11224                id: selection.id,
11225                start: start_row,
11226                end: end_row,
11227                goal: SelectionGoal::None,
11228                reversed: selection.reversed,
11229            });
11230
11231            if line_count_after > line_count_before {
11232                added_lines += line_count_after - line_count_before;
11233            } else if line_count_before > line_count_after {
11234                removed_lines += line_count_before - line_count_after;
11235            }
11236        }
11237
11238        self.transact(window, cx, |this, window, cx| {
11239            let buffer = this.buffer.update(cx, |buffer, cx| {
11240                buffer.edit(edits, None, cx);
11241                buffer.snapshot(cx)
11242            });
11243
11244            // Recalculate offsets on newly edited buffer
11245            let new_selections = new_selections
11246                .iter()
11247                .map(|s| {
11248                    let start_point = Point::new(s.start.0, 0);
11249                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11250                    Selection {
11251                        id: s.id,
11252                        start: buffer.point_to_offset(start_point),
11253                        end: buffer.point_to_offset(end_point),
11254                        goal: s.goal,
11255                        reversed: s.reversed,
11256                    }
11257                })
11258                .collect();
11259
11260            this.change_selections(Default::default(), window, cx, |s| {
11261                s.select(new_selections);
11262            });
11263
11264            this.request_autoscroll(Autoscroll::fit(), cx);
11265        });
11266    }
11267
11268    fn manipulate_immutable_lines<Fn>(
11269        &mut self,
11270        window: &mut Window,
11271        cx: &mut Context<Self>,
11272        mut callback: Fn,
11273    ) where
11274        Fn: FnMut(&mut Vec<&str>),
11275    {
11276        self.manipulate_lines(window, cx, |text| {
11277            let mut lines: Vec<&str> = text.split('\n').collect();
11278            let line_count_before = lines.len();
11279
11280            callback(&mut lines);
11281
11282            LineManipulationResult {
11283                new_text: lines.join("\n"),
11284                line_count_before,
11285                line_count_after: lines.len(),
11286            }
11287        });
11288    }
11289
11290    fn manipulate_mutable_lines<Fn>(
11291        &mut self,
11292        window: &mut Window,
11293        cx: &mut Context<Self>,
11294        mut callback: Fn,
11295    ) where
11296        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11297    {
11298        self.manipulate_lines(window, cx, |text| {
11299            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11300            let line_count_before = lines.len();
11301
11302            callback(&mut lines);
11303
11304            LineManipulationResult {
11305                new_text: lines.join("\n"),
11306                line_count_before,
11307                line_count_after: lines.len(),
11308            }
11309        });
11310    }
11311
11312    pub fn convert_indentation_to_spaces(
11313        &mut self,
11314        _: &ConvertIndentationToSpaces,
11315        window: &mut Window,
11316        cx: &mut Context<Self>,
11317    ) {
11318        let settings = self.buffer.read(cx).language_settings(cx);
11319        let tab_size = settings.tab_size.get() as usize;
11320
11321        self.manipulate_mutable_lines(window, cx, |lines| {
11322            // Allocates a reasonably sized scratch buffer once for the whole loop
11323            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11324            // Avoids recomputing spaces that could be inserted many times
11325            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11326                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11327                .collect();
11328
11329            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11330                let mut chars = line.as_ref().chars();
11331                let mut col = 0;
11332                let mut changed = false;
11333
11334                for ch in chars.by_ref() {
11335                    match ch {
11336                        ' ' => {
11337                            reindented_line.push(' ');
11338                            col += 1;
11339                        }
11340                        '\t' => {
11341                            // \t are converted to spaces depending on the current column
11342                            let spaces_len = tab_size - (col % tab_size);
11343                            reindented_line.extend(&space_cache[spaces_len - 1]);
11344                            col += spaces_len;
11345                            changed = true;
11346                        }
11347                        _ => {
11348                            // If we dont append before break, the character is consumed
11349                            reindented_line.push(ch);
11350                            break;
11351                        }
11352                    }
11353                }
11354
11355                if !changed {
11356                    reindented_line.clear();
11357                    continue;
11358                }
11359                // Append the rest of the line and replace old reference with new one
11360                reindented_line.extend(chars);
11361                *line = Cow::Owned(reindented_line.clone());
11362                reindented_line.clear();
11363            }
11364        });
11365    }
11366
11367    pub fn convert_indentation_to_tabs(
11368        &mut self,
11369        _: &ConvertIndentationToTabs,
11370        window: &mut Window,
11371        cx: &mut Context<Self>,
11372    ) {
11373        let settings = self.buffer.read(cx).language_settings(cx);
11374        let tab_size = settings.tab_size.get() as usize;
11375
11376        self.manipulate_mutable_lines(window, cx, |lines| {
11377            // Allocates a reasonably sized buffer once for the whole loop
11378            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11379            // Avoids recomputing spaces that could be inserted many times
11380            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11381                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11382                .collect();
11383
11384            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11385                let mut chars = line.chars();
11386                let mut spaces_count = 0;
11387                let mut first_non_indent_char = None;
11388                let mut changed = false;
11389
11390                for ch in chars.by_ref() {
11391                    match ch {
11392                        ' ' => {
11393                            // Keep track of spaces. Append \t when we reach tab_size
11394                            spaces_count += 1;
11395                            changed = true;
11396                            if spaces_count == tab_size {
11397                                reindented_line.push('\t');
11398                                spaces_count = 0;
11399                            }
11400                        }
11401                        '\t' => {
11402                            reindented_line.push('\t');
11403                            spaces_count = 0;
11404                        }
11405                        _ => {
11406                            // Dont append it yet, we might have remaining spaces
11407                            first_non_indent_char = Some(ch);
11408                            break;
11409                        }
11410                    }
11411                }
11412
11413                if !changed {
11414                    reindented_line.clear();
11415                    continue;
11416                }
11417                // Remaining spaces that didn't make a full tab stop
11418                if spaces_count > 0 {
11419                    reindented_line.extend(&space_cache[spaces_count - 1]);
11420                }
11421                // If we consume an extra character that was not indentation, add it back
11422                if let Some(extra_char) = first_non_indent_char {
11423                    reindented_line.push(extra_char);
11424                }
11425                // Append the rest of the line and replace old reference with new one
11426                reindented_line.extend(chars);
11427                *line = Cow::Owned(reindented_line.clone());
11428                reindented_line.clear();
11429            }
11430        });
11431    }
11432
11433    pub fn convert_to_upper_case(
11434        &mut self,
11435        _: &ConvertToUpperCase,
11436        window: &mut Window,
11437        cx: &mut Context<Self>,
11438    ) {
11439        self.manipulate_text(window, cx, |text| text.to_uppercase())
11440    }
11441
11442    pub fn convert_to_lower_case(
11443        &mut self,
11444        _: &ConvertToLowerCase,
11445        window: &mut Window,
11446        cx: &mut Context<Self>,
11447    ) {
11448        self.manipulate_text(window, cx, |text| text.to_lowercase())
11449    }
11450
11451    pub fn convert_to_title_case(
11452        &mut self,
11453        _: &ConvertToTitleCase,
11454        window: &mut Window,
11455        cx: &mut Context<Self>,
11456    ) {
11457        self.manipulate_text(window, cx, |text| {
11458            text.split('\n')
11459                .map(|line| line.to_case(Case::Title))
11460                .join("\n")
11461        })
11462    }
11463
11464    pub fn convert_to_snake_case(
11465        &mut self,
11466        _: &ConvertToSnakeCase,
11467        window: &mut Window,
11468        cx: &mut Context<Self>,
11469    ) {
11470        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11471    }
11472
11473    pub fn convert_to_kebab_case(
11474        &mut self,
11475        _: &ConvertToKebabCase,
11476        window: &mut Window,
11477        cx: &mut Context<Self>,
11478    ) {
11479        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11480    }
11481
11482    pub fn convert_to_upper_camel_case(
11483        &mut self,
11484        _: &ConvertToUpperCamelCase,
11485        window: &mut Window,
11486        cx: &mut Context<Self>,
11487    ) {
11488        self.manipulate_text(window, cx, |text| {
11489            text.split('\n')
11490                .map(|line| line.to_case(Case::UpperCamel))
11491                .join("\n")
11492        })
11493    }
11494
11495    pub fn convert_to_lower_camel_case(
11496        &mut self,
11497        _: &ConvertToLowerCamelCase,
11498        window: &mut Window,
11499        cx: &mut Context<Self>,
11500    ) {
11501        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11502    }
11503
11504    pub fn convert_to_opposite_case(
11505        &mut self,
11506        _: &ConvertToOppositeCase,
11507        window: &mut Window,
11508        cx: &mut Context<Self>,
11509    ) {
11510        self.manipulate_text(window, cx, |text| {
11511            text.chars()
11512                .fold(String::with_capacity(text.len()), |mut t, c| {
11513                    if c.is_uppercase() {
11514                        t.extend(c.to_lowercase());
11515                    } else {
11516                        t.extend(c.to_uppercase());
11517                    }
11518                    t
11519                })
11520        })
11521    }
11522
11523    pub fn convert_to_sentence_case(
11524        &mut self,
11525        _: &ConvertToSentenceCase,
11526        window: &mut Window,
11527        cx: &mut Context<Self>,
11528    ) {
11529        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11530    }
11531
11532    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11533        self.manipulate_text(window, cx, |text| {
11534            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11535            if has_upper_case_characters {
11536                text.to_lowercase()
11537            } else {
11538                text.to_uppercase()
11539            }
11540        })
11541    }
11542
11543    pub fn convert_to_rot13(
11544        &mut self,
11545        _: &ConvertToRot13,
11546        window: &mut Window,
11547        cx: &mut Context<Self>,
11548    ) {
11549        self.manipulate_text(window, cx, |text| {
11550            text.chars()
11551                .map(|c| match c {
11552                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11553                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11554                    _ => c,
11555                })
11556                .collect()
11557        })
11558    }
11559
11560    pub fn convert_to_rot47(
11561        &mut self,
11562        _: &ConvertToRot47,
11563        window: &mut Window,
11564        cx: &mut Context<Self>,
11565    ) {
11566        self.manipulate_text(window, cx, |text| {
11567            text.chars()
11568                .map(|c| {
11569                    let code_point = c as u32;
11570                    if code_point >= 33 && code_point <= 126 {
11571                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11572                    }
11573                    c
11574                })
11575                .collect()
11576        })
11577    }
11578
11579    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11580    where
11581        Fn: FnMut(&str) -> String,
11582    {
11583        let buffer = self.buffer.read(cx).snapshot(cx);
11584
11585        let mut new_selections = Vec::new();
11586        let mut edits = Vec::new();
11587        let mut selection_adjustment = 0i32;
11588
11589        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
11590            let selection_is_empty = selection.is_empty();
11591
11592            let (start, end) = if selection_is_empty {
11593                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11594                (word_range.start, word_range.end)
11595            } else {
11596                (
11597                    buffer.point_to_offset(selection.start),
11598                    buffer.point_to_offset(selection.end),
11599                )
11600            };
11601
11602            let text = buffer.text_for_range(start..end).collect::<String>();
11603            let old_length = text.len() as i32;
11604            let text = callback(&text);
11605
11606            new_selections.push(Selection {
11607                start: (start as i32 - selection_adjustment) as usize,
11608                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11609                goal: SelectionGoal::None,
11610                id: selection.id,
11611                reversed: selection.reversed,
11612            });
11613
11614            selection_adjustment += old_length - text.len() as i32;
11615
11616            edits.push((start..end, text));
11617        }
11618
11619        self.transact(window, cx, |this, window, cx| {
11620            this.buffer.update(cx, |buffer, cx| {
11621                buffer.edit(edits, None, cx);
11622            });
11623
11624            this.change_selections(Default::default(), window, cx, |s| {
11625                s.select(new_selections);
11626            });
11627
11628            this.request_autoscroll(Autoscroll::fit(), cx);
11629        });
11630    }
11631
11632    pub fn move_selection_on_drop(
11633        &mut self,
11634        selection: &Selection<Anchor>,
11635        target: DisplayPoint,
11636        is_cut: bool,
11637        window: &mut Window,
11638        cx: &mut Context<Self>,
11639    ) {
11640        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11641        let buffer = display_map.buffer_snapshot();
11642        let mut edits = Vec::new();
11643        let insert_point = display_map
11644            .clip_point(target, Bias::Left)
11645            .to_point(&display_map);
11646        let text = buffer
11647            .text_for_range(selection.start..selection.end)
11648            .collect::<String>();
11649        if is_cut {
11650            edits.push(((selection.start..selection.end), String::new()));
11651        }
11652        let insert_anchor = buffer.anchor_before(insert_point);
11653        edits.push(((insert_anchor..insert_anchor), text));
11654        let last_edit_start = insert_anchor.bias_left(buffer);
11655        let last_edit_end = insert_anchor.bias_right(buffer);
11656        self.transact(window, cx, |this, window, cx| {
11657            this.buffer.update(cx, |buffer, cx| {
11658                buffer.edit(edits, None, cx);
11659            });
11660            this.change_selections(Default::default(), window, cx, |s| {
11661                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11662            });
11663        });
11664    }
11665
11666    pub fn clear_selection_drag_state(&mut self) {
11667        self.selection_drag_state = SelectionDragState::None;
11668    }
11669
11670    pub fn duplicate(
11671        &mut self,
11672        upwards: bool,
11673        whole_lines: bool,
11674        window: &mut Window,
11675        cx: &mut Context<Self>,
11676    ) {
11677        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11678
11679        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11680        let buffer = display_map.buffer_snapshot();
11681        let selections = self.selections.all::<Point>(&display_map);
11682
11683        let mut edits = Vec::new();
11684        let mut selections_iter = selections.iter().peekable();
11685        while let Some(selection) = selections_iter.next() {
11686            let mut rows = selection.spanned_rows(false, &display_map);
11687            // duplicate line-wise
11688            if whole_lines || selection.start == selection.end {
11689                // Avoid duplicating the same lines twice.
11690                while let Some(next_selection) = selections_iter.peek() {
11691                    let next_rows = next_selection.spanned_rows(false, &display_map);
11692                    if next_rows.start < rows.end {
11693                        rows.end = next_rows.end;
11694                        selections_iter.next().unwrap();
11695                    } else {
11696                        break;
11697                    }
11698                }
11699
11700                // Copy the text from the selected row region and splice it either at the start
11701                // or end of the region.
11702                let start = Point::new(rows.start.0, 0);
11703                let end = Point::new(
11704                    rows.end.previous_row().0,
11705                    buffer.line_len(rows.end.previous_row()),
11706                );
11707
11708                let mut text = buffer.text_for_range(start..end).collect::<String>();
11709
11710                let insert_location = if upwards {
11711                    // When duplicating upward, we need to insert before the current line.
11712                    // If we're on the last line and it doesn't end with a newline,
11713                    // we need to add a newline before the duplicated content.
11714                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11715                        && buffer.max_point().column > 0
11716                        && !text.ends_with('\n');
11717
11718                    if needs_leading_newline {
11719                        text.insert(0, '\n');
11720                        end
11721                    } else {
11722                        text.push('\n');
11723                        Point::new(rows.start.0, 0)
11724                    }
11725                } else {
11726                    text.push('\n');
11727                    start
11728                };
11729                edits.push((insert_location..insert_location, text));
11730            } else {
11731                // duplicate character-wise
11732                let start = selection.start;
11733                let end = selection.end;
11734                let text = buffer.text_for_range(start..end).collect::<String>();
11735                edits.push((selection.end..selection.end, text));
11736            }
11737        }
11738
11739        self.transact(window, cx, |this, window, cx| {
11740            this.buffer.update(cx, |buffer, cx| {
11741                buffer.edit(edits, None, cx);
11742            });
11743
11744            // When duplicating upward with whole lines, move the cursor to the duplicated line
11745            if upwards && whole_lines {
11746                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
11747
11748                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11749                    let mut new_ranges = Vec::new();
11750                    let selections = s.all::<Point>(&display_map);
11751                    let mut selections_iter = selections.iter().peekable();
11752
11753                    while let Some(first_selection) = selections_iter.next() {
11754                        // Group contiguous selections together to find the total row span
11755                        let mut group_selections = vec![first_selection];
11756                        let mut rows = first_selection.spanned_rows(false, &display_map);
11757
11758                        while let Some(next_selection) = selections_iter.peek() {
11759                            let next_rows = next_selection.spanned_rows(false, &display_map);
11760                            if next_rows.start < rows.end {
11761                                rows.end = next_rows.end;
11762                                group_selections.push(selections_iter.next().unwrap());
11763                            } else {
11764                                break;
11765                            }
11766                        }
11767
11768                        let row_count = rows.end.0 - rows.start.0;
11769
11770                        // Move all selections in this group up by the total number of duplicated rows
11771                        for selection in group_selections {
11772                            let new_start = Point::new(
11773                                selection.start.row.saturating_sub(row_count),
11774                                selection.start.column,
11775                            );
11776
11777                            let new_end = Point::new(
11778                                selection.end.row.saturating_sub(row_count),
11779                                selection.end.column,
11780                            );
11781
11782                            new_ranges.push(new_start..new_end);
11783                        }
11784                    }
11785
11786                    s.select_ranges(new_ranges);
11787                });
11788            }
11789
11790            this.request_autoscroll(Autoscroll::fit(), cx);
11791        });
11792    }
11793
11794    pub fn duplicate_line_up(
11795        &mut self,
11796        _: &DuplicateLineUp,
11797        window: &mut Window,
11798        cx: &mut Context<Self>,
11799    ) {
11800        self.duplicate(true, true, window, cx);
11801    }
11802
11803    pub fn duplicate_line_down(
11804        &mut self,
11805        _: &DuplicateLineDown,
11806        window: &mut Window,
11807        cx: &mut Context<Self>,
11808    ) {
11809        self.duplicate(false, true, window, cx);
11810    }
11811
11812    pub fn duplicate_selection(
11813        &mut self,
11814        _: &DuplicateSelection,
11815        window: &mut Window,
11816        cx: &mut Context<Self>,
11817    ) {
11818        self.duplicate(false, false, window, cx);
11819    }
11820
11821    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11822        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11823        if self.mode.is_single_line() {
11824            cx.propagate();
11825            return;
11826        }
11827
11828        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11829        let buffer = self.buffer.read(cx).snapshot(cx);
11830
11831        let mut edits = Vec::new();
11832        let mut unfold_ranges = Vec::new();
11833        let mut refold_creases = Vec::new();
11834
11835        let selections = self.selections.all::<Point>(&display_map);
11836        let mut selections = selections.iter().peekable();
11837        let mut contiguous_row_selections = Vec::new();
11838        let mut new_selections = Vec::new();
11839
11840        while let Some(selection) = selections.next() {
11841            // Find all the selections that span a contiguous row range
11842            let (start_row, end_row) = consume_contiguous_rows(
11843                &mut contiguous_row_selections,
11844                selection,
11845                &display_map,
11846                &mut selections,
11847            );
11848
11849            // Move the text spanned by the row range to be before the line preceding the row range
11850            if start_row.0 > 0 {
11851                let range_to_move = Point::new(
11852                    start_row.previous_row().0,
11853                    buffer.line_len(start_row.previous_row()),
11854                )
11855                    ..Point::new(
11856                        end_row.previous_row().0,
11857                        buffer.line_len(end_row.previous_row()),
11858                    );
11859                let insertion_point = display_map
11860                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11861                    .0;
11862
11863                // Don't move lines across excerpts
11864                if buffer
11865                    .excerpt_containing(insertion_point..range_to_move.end)
11866                    .is_some()
11867                {
11868                    let text = buffer
11869                        .text_for_range(range_to_move.clone())
11870                        .flat_map(|s| s.chars())
11871                        .skip(1)
11872                        .chain(['\n'])
11873                        .collect::<String>();
11874
11875                    edits.push((
11876                        buffer.anchor_after(range_to_move.start)
11877                            ..buffer.anchor_before(range_to_move.end),
11878                        String::new(),
11879                    ));
11880                    let insertion_anchor = buffer.anchor_after(insertion_point);
11881                    edits.push((insertion_anchor..insertion_anchor, text));
11882
11883                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11884
11885                    // Move selections up
11886                    new_selections.extend(contiguous_row_selections.drain(..).map(
11887                        |mut selection| {
11888                            selection.start.row -= row_delta;
11889                            selection.end.row -= row_delta;
11890                            selection
11891                        },
11892                    ));
11893
11894                    // Move folds up
11895                    unfold_ranges.push(range_to_move.clone());
11896                    for fold in display_map.folds_in_range(
11897                        buffer.anchor_before(range_to_move.start)
11898                            ..buffer.anchor_after(range_to_move.end),
11899                    ) {
11900                        let mut start = fold.range.start.to_point(&buffer);
11901                        let mut end = fold.range.end.to_point(&buffer);
11902                        start.row -= row_delta;
11903                        end.row -= row_delta;
11904                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11905                    }
11906                }
11907            }
11908
11909            // If we didn't move line(s), preserve the existing selections
11910            new_selections.append(&mut contiguous_row_selections);
11911        }
11912
11913        self.transact(window, cx, |this, window, cx| {
11914            this.unfold_ranges(&unfold_ranges, true, true, cx);
11915            this.buffer.update(cx, |buffer, cx| {
11916                for (range, text) in edits {
11917                    buffer.edit([(range, text)], None, cx);
11918                }
11919            });
11920            this.fold_creases(refold_creases, true, window, cx);
11921            this.change_selections(Default::default(), window, cx, |s| {
11922                s.select(new_selections);
11923            })
11924        });
11925    }
11926
11927    pub fn move_line_down(
11928        &mut self,
11929        _: &MoveLineDown,
11930        window: &mut Window,
11931        cx: &mut Context<Self>,
11932    ) {
11933        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11934        if self.mode.is_single_line() {
11935            cx.propagate();
11936            return;
11937        }
11938
11939        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11940        let buffer = self.buffer.read(cx).snapshot(cx);
11941
11942        let mut edits = Vec::new();
11943        let mut unfold_ranges = Vec::new();
11944        let mut refold_creases = Vec::new();
11945
11946        let selections = self.selections.all::<Point>(&display_map);
11947        let mut selections = selections.iter().peekable();
11948        let mut contiguous_row_selections = Vec::new();
11949        let mut new_selections = Vec::new();
11950
11951        while let Some(selection) = selections.next() {
11952            // Find all the selections that span a contiguous row range
11953            let (start_row, end_row) = consume_contiguous_rows(
11954                &mut contiguous_row_selections,
11955                selection,
11956                &display_map,
11957                &mut selections,
11958            );
11959
11960            // Move the text spanned by the row range to be after the last line of the row range
11961            if end_row.0 <= buffer.max_point().row {
11962                let range_to_move =
11963                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11964                let insertion_point = display_map
11965                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11966                    .0;
11967
11968                // Don't move lines across excerpt boundaries
11969                if buffer
11970                    .excerpt_containing(range_to_move.start..insertion_point)
11971                    .is_some()
11972                {
11973                    let mut text = String::from("\n");
11974                    text.extend(buffer.text_for_range(range_to_move.clone()));
11975                    text.pop(); // Drop trailing newline
11976                    edits.push((
11977                        buffer.anchor_after(range_to_move.start)
11978                            ..buffer.anchor_before(range_to_move.end),
11979                        String::new(),
11980                    ));
11981                    let insertion_anchor = buffer.anchor_after(insertion_point);
11982                    edits.push((insertion_anchor..insertion_anchor, text));
11983
11984                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11985
11986                    // Move selections down
11987                    new_selections.extend(contiguous_row_selections.drain(..).map(
11988                        |mut selection| {
11989                            selection.start.row += row_delta;
11990                            selection.end.row += row_delta;
11991                            selection
11992                        },
11993                    ));
11994
11995                    // Move folds down
11996                    unfold_ranges.push(range_to_move.clone());
11997                    for fold in display_map.folds_in_range(
11998                        buffer.anchor_before(range_to_move.start)
11999                            ..buffer.anchor_after(range_to_move.end),
12000                    ) {
12001                        let mut start = fold.range.start.to_point(&buffer);
12002                        let mut end = fold.range.end.to_point(&buffer);
12003                        start.row += row_delta;
12004                        end.row += row_delta;
12005                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12006                    }
12007                }
12008            }
12009
12010            // If we didn't move line(s), preserve the existing selections
12011            new_selections.append(&mut contiguous_row_selections);
12012        }
12013
12014        self.transact(window, cx, |this, window, cx| {
12015            this.unfold_ranges(&unfold_ranges, true, true, cx);
12016            this.buffer.update(cx, |buffer, cx| {
12017                for (range, text) in edits {
12018                    buffer.edit([(range, text)], None, cx);
12019                }
12020            });
12021            this.fold_creases(refold_creases, true, window, cx);
12022            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12023        });
12024    }
12025
12026    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12027        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12028        let text_layout_details = &self.text_layout_details(window);
12029        self.transact(window, cx, |this, window, cx| {
12030            let edits = this.change_selections(Default::default(), window, cx, |s| {
12031                let mut edits: Vec<(Range<usize>, String)> = Default::default();
12032                s.move_with(|display_map, selection| {
12033                    if !selection.is_empty() {
12034                        return;
12035                    }
12036
12037                    let mut head = selection.head();
12038                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12039                    if head.column() == display_map.line_len(head.row()) {
12040                        transpose_offset = display_map
12041                            .buffer_snapshot()
12042                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12043                    }
12044
12045                    if transpose_offset == 0 {
12046                        return;
12047                    }
12048
12049                    *head.column_mut() += 1;
12050                    head = display_map.clip_point(head, Bias::Right);
12051                    let goal = SelectionGoal::HorizontalPosition(
12052                        display_map
12053                            .x_for_display_point(head, text_layout_details)
12054                            .into(),
12055                    );
12056                    selection.collapse_to(head, goal);
12057
12058                    let transpose_start = display_map
12059                        .buffer_snapshot()
12060                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12061                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12062                        let transpose_end = display_map
12063                            .buffer_snapshot()
12064                            .clip_offset(transpose_offset + 1, Bias::Right);
12065                        if let Some(ch) = display_map
12066                            .buffer_snapshot()
12067                            .chars_at(transpose_start)
12068                            .next()
12069                        {
12070                            edits.push((transpose_start..transpose_offset, String::new()));
12071                            edits.push((transpose_end..transpose_end, ch.to_string()));
12072                        }
12073                    }
12074                });
12075                edits
12076            });
12077            this.buffer
12078                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12079            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12080            this.change_selections(Default::default(), window, cx, |s| {
12081                s.select(selections);
12082            });
12083        });
12084    }
12085
12086    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12087        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12088        if self.mode.is_single_line() {
12089            cx.propagate();
12090            return;
12091        }
12092
12093        self.rewrap_impl(RewrapOptions::default(), cx)
12094    }
12095
12096    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12097        let buffer = self.buffer.read(cx).snapshot(cx);
12098        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12099
12100        #[derive(Clone, Debug, PartialEq)]
12101        enum CommentFormat {
12102            /// single line comment, with prefix for line
12103            Line(String),
12104            /// single line within a block comment, with prefix for line
12105            BlockLine(String),
12106            /// a single line of a block comment that includes the initial delimiter
12107            BlockCommentWithStart(BlockCommentConfig),
12108            /// a single line of a block comment that includes the ending delimiter
12109            BlockCommentWithEnd(BlockCommentConfig),
12110        }
12111
12112        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12113        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12114            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12115                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12116                .peekable();
12117
12118            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12119                row
12120            } else {
12121                return Vec::new();
12122            };
12123
12124            let language_settings = buffer.language_settings_at(selection.head(), cx);
12125            let language_scope = buffer.language_scope_at(selection.head());
12126
12127            let indent_and_prefix_for_row =
12128                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12129                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12130                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12131                        &language_scope
12132                    {
12133                        let indent_end = Point::new(row, indent.len);
12134                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12135                        let line_text_after_indent = buffer
12136                            .text_for_range(indent_end..line_end)
12137                            .collect::<String>();
12138
12139                        let is_within_comment_override = buffer
12140                            .language_scope_at(indent_end)
12141                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12142                        let comment_delimiters = if is_within_comment_override {
12143                            // we are within a comment syntax node, but we don't
12144                            // yet know what kind of comment: block, doc or line
12145                            match (
12146                                language_scope.documentation_comment(),
12147                                language_scope.block_comment(),
12148                            ) {
12149                                (Some(config), _) | (_, Some(config))
12150                                    if buffer.contains_str_at(indent_end, &config.start) =>
12151                                {
12152                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12153                                }
12154                                (Some(config), _) | (_, Some(config))
12155                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12156                                {
12157                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12158                                }
12159                                (Some(config), _) | (_, Some(config))
12160                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12161                                {
12162                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12163                                }
12164                                (_, _) => language_scope
12165                                    .line_comment_prefixes()
12166                                    .iter()
12167                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12168                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12169                            }
12170                        } else {
12171                            // we not in an overridden comment node, but we may
12172                            // be within a non-overridden line comment node
12173                            language_scope
12174                                .line_comment_prefixes()
12175                                .iter()
12176                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12177                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12178                        };
12179
12180                        let rewrap_prefix = language_scope
12181                            .rewrap_prefixes()
12182                            .iter()
12183                            .find_map(|prefix_regex| {
12184                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12185                                    if mat.start() == 0 {
12186                                        Some(mat.as_str().to_string())
12187                                    } else {
12188                                        None
12189                                    }
12190                                })
12191                            })
12192                            .flatten();
12193                        (comment_delimiters, rewrap_prefix)
12194                    } else {
12195                        (None, None)
12196                    };
12197                    (indent, comment_prefix, rewrap_prefix)
12198                };
12199
12200            let mut ranges = Vec::new();
12201            let from_empty_selection = selection.is_empty();
12202
12203            let mut current_range_start = first_row;
12204            let mut prev_row = first_row;
12205            let (
12206                mut current_range_indent,
12207                mut current_range_comment_delimiters,
12208                mut current_range_rewrap_prefix,
12209            ) = indent_and_prefix_for_row(first_row);
12210
12211            for row in non_blank_rows_iter.skip(1) {
12212                let has_paragraph_break = row > prev_row + 1;
12213
12214                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12215                    indent_and_prefix_for_row(row);
12216
12217                let has_indent_change = row_indent != current_range_indent;
12218                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12219
12220                let has_boundary_change = has_comment_change
12221                    || row_rewrap_prefix.is_some()
12222                    || (has_indent_change && current_range_comment_delimiters.is_some());
12223
12224                if has_paragraph_break || has_boundary_change {
12225                    ranges.push((
12226                        language_settings.clone(),
12227                        Point::new(current_range_start, 0)
12228                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12229                        current_range_indent,
12230                        current_range_comment_delimiters.clone(),
12231                        current_range_rewrap_prefix.clone(),
12232                        from_empty_selection,
12233                    ));
12234                    current_range_start = row;
12235                    current_range_indent = row_indent;
12236                    current_range_comment_delimiters = row_comment_delimiters;
12237                    current_range_rewrap_prefix = row_rewrap_prefix;
12238                }
12239                prev_row = row;
12240            }
12241
12242            ranges.push((
12243                language_settings.clone(),
12244                Point::new(current_range_start, 0)
12245                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12246                current_range_indent,
12247                current_range_comment_delimiters,
12248                current_range_rewrap_prefix,
12249                from_empty_selection,
12250            ));
12251
12252            ranges
12253        });
12254
12255        let mut edits = Vec::new();
12256        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12257
12258        for (
12259            language_settings,
12260            wrap_range,
12261            mut indent_size,
12262            comment_prefix,
12263            rewrap_prefix,
12264            from_empty_selection,
12265        ) in wrap_ranges
12266        {
12267            let mut start_row = wrap_range.start.row;
12268            let mut end_row = wrap_range.end.row;
12269
12270            // Skip selections that overlap with a range that has already been rewrapped.
12271            let selection_range = start_row..end_row;
12272            if rewrapped_row_ranges
12273                .iter()
12274                .any(|range| range.overlaps(&selection_range))
12275            {
12276                continue;
12277            }
12278
12279            let tab_size = language_settings.tab_size;
12280
12281            let (line_prefix, inside_comment) = match &comment_prefix {
12282                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12283                    (Some(prefix.as_str()), true)
12284                }
12285                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12286                    (Some(prefix.as_ref()), true)
12287                }
12288                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12289                    start: _,
12290                    end: _,
12291                    prefix,
12292                    tab_size,
12293                })) => {
12294                    indent_size.len += tab_size;
12295                    (Some(prefix.as_ref()), true)
12296                }
12297                None => (None, false),
12298            };
12299            let indent_prefix = indent_size.chars().collect::<String>();
12300            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12301
12302            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12303                RewrapBehavior::InComments => inside_comment,
12304                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12305                RewrapBehavior::Anywhere => true,
12306            };
12307
12308            let should_rewrap = options.override_language_settings
12309                || allow_rewrap_based_on_language
12310                || self.hard_wrap.is_some();
12311            if !should_rewrap {
12312                continue;
12313            }
12314
12315            if from_empty_selection {
12316                'expand_upwards: while start_row > 0 {
12317                    let prev_row = start_row - 1;
12318                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12319                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12320                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12321                    {
12322                        start_row = prev_row;
12323                    } else {
12324                        break 'expand_upwards;
12325                    }
12326                }
12327
12328                'expand_downwards: while end_row < buffer.max_point().row {
12329                    let next_row = end_row + 1;
12330                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12331                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12332                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12333                    {
12334                        end_row = next_row;
12335                    } else {
12336                        break 'expand_downwards;
12337                    }
12338                }
12339            }
12340
12341            let start = Point::new(start_row, 0);
12342            let start_offset = ToOffset::to_offset(&start, &buffer);
12343            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12344            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12345            let mut first_line_delimiter = None;
12346            let mut last_line_delimiter = None;
12347            let Some(lines_without_prefixes) = selection_text
12348                .lines()
12349                .enumerate()
12350                .map(|(ix, line)| {
12351                    let line_trimmed = line.trim_start();
12352                    if rewrap_prefix.is_some() && ix > 0 {
12353                        Ok(line_trimmed)
12354                    } else if let Some(
12355                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12356                            start,
12357                            prefix,
12358                            end,
12359                            tab_size,
12360                        })
12361                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12362                            start,
12363                            prefix,
12364                            end,
12365                            tab_size,
12366                        }),
12367                    ) = &comment_prefix
12368                    {
12369                        let line_trimmed = line_trimmed
12370                            .strip_prefix(start.as_ref())
12371                            .map(|s| {
12372                                let mut indent_size = indent_size;
12373                                indent_size.len -= tab_size;
12374                                let indent_prefix: String = indent_size.chars().collect();
12375                                first_line_delimiter = Some((indent_prefix, start));
12376                                s.trim_start()
12377                            })
12378                            .unwrap_or(line_trimmed);
12379                        let line_trimmed = line_trimmed
12380                            .strip_suffix(end.as_ref())
12381                            .map(|s| {
12382                                last_line_delimiter = Some(end);
12383                                s.trim_end()
12384                            })
12385                            .unwrap_or(line_trimmed);
12386                        let line_trimmed = line_trimmed
12387                            .strip_prefix(prefix.as_ref())
12388                            .unwrap_or(line_trimmed);
12389                        Ok(line_trimmed)
12390                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12391                        line_trimmed.strip_prefix(prefix).with_context(|| {
12392                            format!("line did not start with prefix {prefix:?}: {line:?}")
12393                        })
12394                    } else {
12395                        line_trimmed
12396                            .strip_prefix(&line_prefix.trim_start())
12397                            .with_context(|| {
12398                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12399                            })
12400                    }
12401                })
12402                .collect::<Result<Vec<_>, _>>()
12403                .log_err()
12404            else {
12405                continue;
12406            };
12407
12408            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12409                buffer
12410                    .language_settings_at(Point::new(start_row, 0), cx)
12411                    .preferred_line_length as usize
12412            });
12413
12414            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12415                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12416            } else {
12417                line_prefix.clone()
12418            };
12419
12420            let wrapped_text = {
12421                let mut wrapped_text = wrap_with_prefix(
12422                    line_prefix,
12423                    subsequent_lines_prefix,
12424                    lines_without_prefixes.join("\n"),
12425                    wrap_column,
12426                    tab_size,
12427                    options.preserve_existing_whitespace,
12428                );
12429
12430                if let Some((indent, delimiter)) = first_line_delimiter {
12431                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12432                }
12433                if let Some(last_line) = last_line_delimiter {
12434                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12435                }
12436
12437                wrapped_text
12438            };
12439
12440            // TODO: should always use char-based diff while still supporting cursor behavior that
12441            // matches vim.
12442            let mut diff_options = DiffOptions::default();
12443            if options.override_language_settings {
12444                diff_options.max_word_diff_len = 0;
12445                diff_options.max_word_diff_line_count = 0;
12446            } else {
12447                diff_options.max_word_diff_len = usize::MAX;
12448                diff_options.max_word_diff_line_count = usize::MAX;
12449            }
12450
12451            for (old_range, new_text) in
12452                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12453            {
12454                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12455                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12456                edits.push((edit_start..edit_end, new_text));
12457            }
12458
12459            rewrapped_row_ranges.push(start_row..=end_row);
12460        }
12461
12462        self.buffer
12463            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12464    }
12465
12466    pub fn cut_common(
12467        &mut self,
12468        cut_no_selection_line: bool,
12469        window: &mut Window,
12470        cx: &mut Context<Self>,
12471    ) -> ClipboardItem {
12472        let mut text = String::new();
12473        let buffer = self.buffer.read(cx).snapshot(cx);
12474        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12475        let mut clipboard_selections = Vec::with_capacity(selections.len());
12476        {
12477            let max_point = buffer.max_point();
12478            let mut is_first = true;
12479            for selection in &mut selections {
12480                let is_entire_line =
12481                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12482                if is_entire_line {
12483                    selection.start = Point::new(selection.start.row, 0);
12484                    if !selection.is_empty() && selection.end.column == 0 {
12485                        selection.end = cmp::min(max_point, selection.end);
12486                    } else {
12487                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12488                    }
12489                    selection.goal = SelectionGoal::None;
12490                }
12491                if is_first {
12492                    is_first = false;
12493                } else {
12494                    text += "\n";
12495                }
12496                let mut len = 0;
12497                for chunk in buffer.text_for_range(selection.start..selection.end) {
12498                    text.push_str(chunk);
12499                    len += chunk.len();
12500                }
12501                clipboard_selections.push(ClipboardSelection {
12502                    len,
12503                    is_entire_line,
12504                    first_line_indent: buffer
12505                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12506                        .len,
12507                });
12508            }
12509        }
12510
12511        self.transact(window, cx, |this, window, cx| {
12512            this.change_selections(Default::default(), window, cx, |s| {
12513                s.select(selections);
12514            });
12515            this.insert("", window, cx);
12516        });
12517        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12518    }
12519
12520    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12521        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12522        let item = self.cut_common(true, window, cx);
12523        cx.write_to_clipboard(item);
12524    }
12525
12526    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12527        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12528        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12529            s.move_with(|snapshot, sel| {
12530                if sel.is_empty() {
12531                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12532                }
12533                if sel.is_empty() {
12534                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12535                }
12536            });
12537        });
12538        let item = self.cut_common(false, window, cx);
12539        cx.set_global(KillRing(item))
12540    }
12541
12542    pub fn kill_ring_yank(
12543        &mut self,
12544        _: &KillRingYank,
12545        window: &mut Window,
12546        cx: &mut Context<Self>,
12547    ) {
12548        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12549        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12550            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12551                (kill_ring.text().to_string(), kill_ring.metadata_json())
12552            } else {
12553                return;
12554            }
12555        } else {
12556            return;
12557        };
12558        self.do_paste(&text, metadata, false, window, cx);
12559    }
12560
12561    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12562        self.do_copy(true, cx);
12563    }
12564
12565    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12566        self.do_copy(false, cx);
12567    }
12568
12569    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12570        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12571        let buffer = self.buffer.read(cx).read(cx);
12572        let mut text = String::new();
12573
12574        let mut clipboard_selections = Vec::with_capacity(selections.len());
12575        {
12576            let max_point = buffer.max_point();
12577            let mut is_first = true;
12578            for selection in &selections {
12579                let mut start = selection.start;
12580                let mut end = selection.end;
12581                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12582                let mut add_trailing_newline = false;
12583                if is_entire_line {
12584                    start = Point::new(start.row, 0);
12585                    let next_line_start = Point::new(end.row + 1, 0);
12586                    if next_line_start <= max_point {
12587                        end = next_line_start;
12588                    } else {
12589                        // We're on the last line without a trailing newline.
12590                        // Copy to the end of the line and add a newline afterwards.
12591                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12592                        add_trailing_newline = true;
12593                    }
12594                }
12595
12596                let mut trimmed_selections = Vec::new();
12597                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12598                    let row = MultiBufferRow(start.row);
12599                    let first_indent = buffer.indent_size_for_line(row);
12600                    if first_indent.len == 0 || start.column > first_indent.len {
12601                        trimmed_selections.push(start..end);
12602                    } else {
12603                        trimmed_selections.push(
12604                            Point::new(row.0, first_indent.len)
12605                                ..Point::new(row.0, buffer.line_len(row)),
12606                        );
12607                        for row in start.row + 1..=end.row {
12608                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12609                            if row == end.row {
12610                                line_len = end.column;
12611                            }
12612                            if line_len == 0 {
12613                                trimmed_selections
12614                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12615                                continue;
12616                            }
12617                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12618                            if row_indent_size.len >= first_indent.len {
12619                                trimmed_selections.push(
12620                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12621                                );
12622                            } else {
12623                                trimmed_selections.clear();
12624                                trimmed_selections.push(start..end);
12625                                break;
12626                            }
12627                        }
12628                    }
12629                } else {
12630                    trimmed_selections.push(start..end);
12631                }
12632
12633                for trimmed_range in trimmed_selections {
12634                    if is_first {
12635                        is_first = false;
12636                    } else {
12637                        text += "\n";
12638                    }
12639                    let mut len = 0;
12640                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12641                        text.push_str(chunk);
12642                        len += chunk.len();
12643                    }
12644                    if add_trailing_newline {
12645                        text.push('\n');
12646                        len += 1;
12647                    }
12648                    clipboard_selections.push(ClipboardSelection {
12649                        len,
12650                        is_entire_line,
12651                        first_line_indent: buffer
12652                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12653                            .len,
12654                    });
12655                }
12656            }
12657        }
12658
12659        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12660            text,
12661            clipboard_selections,
12662        ));
12663    }
12664
12665    pub fn do_paste(
12666        &mut self,
12667        text: &String,
12668        clipboard_selections: Option<Vec<ClipboardSelection>>,
12669        handle_entire_lines: bool,
12670        window: &mut Window,
12671        cx: &mut Context<Self>,
12672    ) {
12673        if self.read_only(cx) {
12674            return;
12675        }
12676
12677        let clipboard_text = Cow::Borrowed(text.as_str());
12678
12679        self.transact(window, cx, |this, window, cx| {
12680            let had_active_edit_prediction = this.has_active_edit_prediction();
12681            let display_map = this.display_snapshot(cx);
12682            let old_selections = this.selections.all::<usize>(&display_map);
12683            let cursor_offset = this.selections.last::<usize>(&display_map).head();
12684
12685            if let Some(mut clipboard_selections) = clipboard_selections {
12686                let all_selections_were_entire_line =
12687                    clipboard_selections.iter().all(|s| s.is_entire_line);
12688                let first_selection_indent_column =
12689                    clipboard_selections.first().map(|s| s.first_line_indent);
12690                if clipboard_selections.len() != old_selections.len() {
12691                    clipboard_selections.drain(..);
12692                }
12693                let mut auto_indent_on_paste = true;
12694
12695                this.buffer.update(cx, |buffer, cx| {
12696                    let snapshot = buffer.read(cx);
12697                    auto_indent_on_paste = snapshot
12698                        .language_settings_at(cursor_offset, cx)
12699                        .auto_indent_on_paste;
12700
12701                    let mut start_offset = 0;
12702                    let mut edits = Vec::new();
12703                    let mut original_indent_columns = Vec::new();
12704                    for (ix, selection) in old_selections.iter().enumerate() {
12705                        let to_insert;
12706                        let entire_line;
12707                        let original_indent_column;
12708                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12709                            let end_offset = start_offset + clipboard_selection.len;
12710                            to_insert = &clipboard_text[start_offset..end_offset];
12711                            entire_line = clipboard_selection.is_entire_line;
12712                            start_offset = end_offset + 1;
12713                            original_indent_column = Some(clipboard_selection.first_line_indent);
12714                        } else {
12715                            to_insert = &*clipboard_text;
12716                            entire_line = all_selections_were_entire_line;
12717                            original_indent_column = first_selection_indent_column
12718                        }
12719
12720                        let (range, to_insert) =
12721                            if selection.is_empty() && handle_entire_lines && entire_line {
12722                                // If the corresponding selection was empty when this slice of the
12723                                // clipboard text was written, then the entire line containing the
12724                                // selection was copied. If this selection is also currently empty,
12725                                // then paste the line before the current line of the buffer.
12726                                let column = selection.start.to_point(&snapshot).column as usize;
12727                                let line_start = selection.start - column;
12728                                (line_start..line_start, Cow::Borrowed(to_insert))
12729                            } else {
12730                                let language = snapshot.language_at(selection.head());
12731                                let range = selection.range();
12732                                if let Some(language) = language
12733                                    && language.name() == "Markdown".into()
12734                                {
12735                                    edit_for_markdown_paste(
12736                                        &snapshot,
12737                                        range,
12738                                        to_insert,
12739                                        url::Url::parse(to_insert).ok(),
12740                                    )
12741                                } else {
12742                                    (range, Cow::Borrowed(to_insert))
12743                                }
12744                            };
12745
12746                        edits.push((range, to_insert));
12747                        original_indent_columns.push(original_indent_column);
12748                    }
12749                    drop(snapshot);
12750
12751                    buffer.edit(
12752                        edits,
12753                        if auto_indent_on_paste {
12754                            Some(AutoindentMode::Block {
12755                                original_indent_columns,
12756                            })
12757                        } else {
12758                            None
12759                        },
12760                        cx,
12761                    );
12762                });
12763
12764                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12765                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12766            } else {
12767                let url = url::Url::parse(&clipboard_text).ok();
12768
12769                let auto_indent_mode = if !clipboard_text.is_empty() {
12770                    Some(AutoindentMode::Block {
12771                        original_indent_columns: Vec::new(),
12772                    })
12773                } else {
12774                    None
12775                };
12776
12777                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12778                    let snapshot = buffer.snapshot(cx);
12779
12780                    let anchors = old_selections
12781                        .iter()
12782                        .map(|s| {
12783                            let anchor = snapshot.anchor_after(s.head());
12784                            s.map(|_| anchor)
12785                        })
12786                        .collect::<Vec<_>>();
12787
12788                    let mut edits = Vec::new();
12789
12790                    for selection in old_selections.iter() {
12791                        let language = snapshot.language_at(selection.head());
12792                        let range = selection.range();
12793
12794                        let (edit_range, edit_text) = if let Some(language) = language
12795                            && language.name() == "Markdown".into()
12796                        {
12797                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12798                        } else {
12799                            (range, clipboard_text.clone())
12800                        };
12801
12802                        edits.push((edit_range, edit_text));
12803                    }
12804
12805                    drop(snapshot);
12806                    buffer.edit(edits, auto_indent_mode, cx);
12807
12808                    anchors
12809                });
12810
12811                this.change_selections(Default::default(), window, cx, |s| {
12812                    s.select_anchors(selection_anchors);
12813                });
12814            }
12815
12816            let trigger_in_words =
12817                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12818
12819            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12820        });
12821    }
12822
12823    pub fn diff_clipboard_with_selection(
12824        &mut self,
12825        _: &DiffClipboardWithSelection,
12826        window: &mut Window,
12827        cx: &mut Context<Self>,
12828    ) {
12829        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
12830
12831        if selections.is_empty() {
12832            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12833            return;
12834        };
12835
12836        let clipboard_text = match cx.read_from_clipboard() {
12837            Some(item) => match item.entries().first() {
12838                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12839                _ => None,
12840            },
12841            None => None,
12842        };
12843
12844        let Some(clipboard_text) = clipboard_text else {
12845            log::warn!("Clipboard doesn't contain text.");
12846            return;
12847        };
12848
12849        window.dispatch_action(
12850            Box::new(DiffClipboardWithSelectionData {
12851                clipboard_text,
12852                editor: cx.entity(),
12853            }),
12854            cx,
12855        );
12856    }
12857
12858    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12859        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12860        if let Some(item) = cx.read_from_clipboard() {
12861            let entries = item.entries();
12862
12863            match entries.first() {
12864                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12865                // of all the pasted entries.
12866                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12867                    .do_paste(
12868                        clipboard_string.text(),
12869                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12870                        true,
12871                        window,
12872                        cx,
12873                    ),
12874                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12875            }
12876        }
12877    }
12878
12879    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12880        if self.read_only(cx) {
12881            return;
12882        }
12883
12884        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12885
12886        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12887            if let Some((selections, _)) =
12888                self.selection_history.transaction(transaction_id).cloned()
12889            {
12890                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12891                    s.select_anchors(selections.to_vec());
12892                });
12893            } else {
12894                log::error!(
12895                    "No entry in selection_history found for undo. \
12896                     This may correspond to a bug where undo does not update the selection. \
12897                     If this is occurring, please add details to \
12898                     https://github.com/zed-industries/zed/issues/22692"
12899                );
12900            }
12901            self.request_autoscroll(Autoscroll::fit(), cx);
12902            self.unmark_text(window, cx);
12903            self.refresh_edit_prediction(true, false, window, cx);
12904            cx.emit(EditorEvent::Edited { transaction_id });
12905            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12906        }
12907    }
12908
12909    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12910        if self.read_only(cx) {
12911            return;
12912        }
12913
12914        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12915
12916        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12917            if let Some((_, Some(selections))) =
12918                self.selection_history.transaction(transaction_id).cloned()
12919            {
12920                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12921                    s.select_anchors(selections.to_vec());
12922                });
12923            } else {
12924                log::error!(
12925                    "No entry in selection_history found for redo. \
12926                     This may correspond to a bug where undo does not update the selection. \
12927                     If this is occurring, please add details to \
12928                     https://github.com/zed-industries/zed/issues/22692"
12929                );
12930            }
12931            self.request_autoscroll(Autoscroll::fit(), cx);
12932            self.unmark_text(window, cx);
12933            self.refresh_edit_prediction(true, false, window, cx);
12934            cx.emit(EditorEvent::Edited { transaction_id });
12935        }
12936    }
12937
12938    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12939        self.buffer
12940            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12941    }
12942
12943    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12944        self.buffer
12945            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12946    }
12947
12948    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12949        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12950        self.change_selections(Default::default(), window, cx, |s| {
12951            s.move_with(|map, selection| {
12952                let cursor = if selection.is_empty() {
12953                    movement::left(map, selection.start)
12954                } else {
12955                    selection.start
12956                };
12957                selection.collapse_to(cursor, SelectionGoal::None);
12958            });
12959        })
12960    }
12961
12962    pub fn select_left(&mut self, _: &SelectLeft, 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_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12966        })
12967    }
12968
12969    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12970        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12971        self.change_selections(Default::default(), window, cx, |s| {
12972            s.move_with(|map, selection| {
12973                let cursor = if selection.is_empty() {
12974                    movement::right(map, selection.end)
12975                } else {
12976                    selection.end
12977                };
12978                selection.collapse_to(cursor, SelectionGoal::None)
12979            });
12980        })
12981    }
12982
12983    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12984        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12985        self.change_selections(Default::default(), window, cx, |s| {
12986            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12987        });
12988    }
12989
12990    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12991        if self.take_rename(true, window, cx).is_some() {
12992            return;
12993        }
12994
12995        if self.mode.is_single_line() {
12996            cx.propagate();
12997            return;
12998        }
12999
13000        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13001
13002        let text_layout_details = &self.text_layout_details(window);
13003        let selection_count = self.selections.count();
13004        let first_selection = self.selections.first_anchor();
13005
13006        self.change_selections(Default::default(), window, cx, |s| {
13007            s.move_with(|map, selection| {
13008                if !selection.is_empty() {
13009                    selection.goal = SelectionGoal::None;
13010                }
13011                let (cursor, goal) = movement::up(
13012                    map,
13013                    selection.start,
13014                    selection.goal,
13015                    false,
13016                    text_layout_details,
13017                );
13018                selection.collapse_to(cursor, goal);
13019            });
13020        });
13021
13022        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13023        {
13024            cx.propagate();
13025        }
13026    }
13027
13028    pub fn move_up_by_lines(
13029        &mut self,
13030        action: &MoveUpByLines,
13031        window: &mut Window,
13032        cx: &mut Context<Self>,
13033    ) {
13034        if self.take_rename(true, window, cx).is_some() {
13035            return;
13036        }
13037
13038        if self.mode.is_single_line() {
13039            cx.propagate();
13040            return;
13041        }
13042
13043        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13044
13045        let text_layout_details = &self.text_layout_details(window);
13046
13047        self.change_selections(Default::default(), window, cx, |s| {
13048            s.move_with(|map, selection| {
13049                if !selection.is_empty() {
13050                    selection.goal = SelectionGoal::None;
13051                }
13052                let (cursor, goal) = movement::up_by_rows(
13053                    map,
13054                    selection.start,
13055                    action.lines,
13056                    selection.goal,
13057                    false,
13058                    text_layout_details,
13059                );
13060                selection.collapse_to(cursor, goal);
13061            });
13062        })
13063    }
13064
13065    pub fn move_down_by_lines(
13066        &mut self,
13067        action: &MoveDownByLines,
13068        window: &mut Window,
13069        cx: &mut Context<Self>,
13070    ) {
13071        if self.take_rename(true, window, cx).is_some() {
13072            return;
13073        }
13074
13075        if self.mode.is_single_line() {
13076            cx.propagate();
13077            return;
13078        }
13079
13080        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13081
13082        let text_layout_details = &self.text_layout_details(window);
13083
13084        self.change_selections(Default::default(), window, cx, |s| {
13085            s.move_with(|map, selection| {
13086                if !selection.is_empty() {
13087                    selection.goal = SelectionGoal::None;
13088                }
13089                let (cursor, goal) = movement::down_by_rows(
13090                    map,
13091                    selection.start,
13092                    action.lines,
13093                    selection.goal,
13094                    false,
13095                    text_layout_details,
13096                );
13097                selection.collapse_to(cursor, goal);
13098            });
13099        })
13100    }
13101
13102    pub fn select_down_by_lines(
13103        &mut self,
13104        action: &SelectDownByLines,
13105        window: &mut Window,
13106        cx: &mut Context<Self>,
13107    ) {
13108        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13109        let text_layout_details = &self.text_layout_details(window);
13110        self.change_selections(Default::default(), window, cx, |s| {
13111            s.move_heads_with(|map, head, goal| {
13112                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13113            })
13114        })
13115    }
13116
13117    pub fn select_up_by_lines(
13118        &mut self,
13119        action: &SelectUpByLines,
13120        window: &mut Window,
13121        cx: &mut Context<Self>,
13122    ) {
13123        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13124        let text_layout_details = &self.text_layout_details(window);
13125        self.change_selections(Default::default(), window, cx, |s| {
13126            s.move_heads_with(|map, head, goal| {
13127                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13128            })
13129        })
13130    }
13131
13132    pub fn select_page_up(
13133        &mut self,
13134        _: &SelectPageUp,
13135        window: &mut Window,
13136        cx: &mut Context<Self>,
13137    ) {
13138        let Some(row_count) = self.visible_row_count() else {
13139            return;
13140        };
13141
13142        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13143
13144        let text_layout_details = &self.text_layout_details(window);
13145
13146        self.change_selections(Default::default(), window, cx, |s| {
13147            s.move_heads_with(|map, head, goal| {
13148                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13149            })
13150        })
13151    }
13152
13153    pub fn move_page_up(
13154        &mut self,
13155        action: &MovePageUp,
13156        window: &mut Window,
13157        cx: &mut Context<Self>,
13158    ) {
13159        if self.take_rename(true, window, cx).is_some() {
13160            return;
13161        }
13162
13163        if self
13164            .context_menu
13165            .borrow_mut()
13166            .as_mut()
13167            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13168            .unwrap_or(false)
13169        {
13170            return;
13171        }
13172
13173        if matches!(self.mode, EditorMode::SingleLine) {
13174            cx.propagate();
13175            return;
13176        }
13177
13178        let Some(row_count) = self.visible_row_count() else {
13179            return;
13180        };
13181
13182        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13183
13184        let effects = if action.center_cursor {
13185            SelectionEffects::scroll(Autoscroll::center())
13186        } else {
13187            SelectionEffects::default()
13188        };
13189
13190        let text_layout_details = &self.text_layout_details(window);
13191
13192        self.change_selections(effects, window, cx, |s| {
13193            s.move_with(|map, selection| {
13194                if !selection.is_empty() {
13195                    selection.goal = SelectionGoal::None;
13196                }
13197                let (cursor, goal) = movement::up_by_rows(
13198                    map,
13199                    selection.end,
13200                    row_count,
13201                    selection.goal,
13202                    false,
13203                    text_layout_details,
13204                );
13205                selection.collapse_to(cursor, goal);
13206            });
13207        });
13208    }
13209
13210    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13211        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13212        let text_layout_details = &self.text_layout_details(window);
13213        self.change_selections(Default::default(), window, cx, |s| {
13214            s.move_heads_with(|map, head, goal| {
13215                movement::up(map, head, goal, false, text_layout_details)
13216            })
13217        })
13218    }
13219
13220    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13221        self.take_rename(true, window, cx);
13222
13223        if self.mode.is_single_line() {
13224            cx.propagate();
13225            return;
13226        }
13227
13228        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13229
13230        let text_layout_details = &self.text_layout_details(window);
13231        let selection_count = self.selections.count();
13232        let first_selection = self.selections.first_anchor();
13233
13234        self.change_selections(Default::default(), window, cx, |s| {
13235            s.move_with(|map, selection| {
13236                if !selection.is_empty() {
13237                    selection.goal = SelectionGoal::None;
13238                }
13239                let (cursor, goal) = movement::down(
13240                    map,
13241                    selection.end,
13242                    selection.goal,
13243                    false,
13244                    text_layout_details,
13245                );
13246                selection.collapse_to(cursor, goal);
13247            });
13248        });
13249
13250        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13251        {
13252            cx.propagate();
13253        }
13254    }
13255
13256    pub fn select_page_down(
13257        &mut self,
13258        _: &SelectPageDown,
13259        window: &mut Window,
13260        cx: &mut Context<Self>,
13261    ) {
13262        let Some(row_count) = self.visible_row_count() else {
13263            return;
13264        };
13265
13266        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13267
13268        let text_layout_details = &self.text_layout_details(window);
13269
13270        self.change_selections(Default::default(), window, cx, |s| {
13271            s.move_heads_with(|map, head, goal| {
13272                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13273            })
13274        })
13275    }
13276
13277    pub fn move_page_down(
13278        &mut self,
13279        action: &MovePageDown,
13280        window: &mut Window,
13281        cx: &mut Context<Self>,
13282    ) {
13283        if self.take_rename(true, window, cx).is_some() {
13284            return;
13285        }
13286
13287        if self
13288            .context_menu
13289            .borrow_mut()
13290            .as_mut()
13291            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13292            .unwrap_or(false)
13293        {
13294            return;
13295        }
13296
13297        if matches!(self.mode, EditorMode::SingleLine) {
13298            cx.propagate();
13299            return;
13300        }
13301
13302        let Some(row_count) = self.visible_row_count() else {
13303            return;
13304        };
13305
13306        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13307
13308        let effects = if action.center_cursor {
13309            SelectionEffects::scroll(Autoscroll::center())
13310        } else {
13311            SelectionEffects::default()
13312        };
13313
13314        let text_layout_details = &self.text_layout_details(window);
13315        self.change_selections(effects, window, cx, |s| {
13316            s.move_with(|map, selection| {
13317                if !selection.is_empty() {
13318                    selection.goal = SelectionGoal::None;
13319                }
13320                let (cursor, goal) = movement::down_by_rows(
13321                    map,
13322                    selection.end,
13323                    row_count,
13324                    selection.goal,
13325                    false,
13326                    text_layout_details,
13327                );
13328                selection.collapse_to(cursor, goal);
13329            });
13330        });
13331    }
13332
13333    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13334        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13335        let text_layout_details = &self.text_layout_details(window);
13336        self.change_selections(Default::default(), window, cx, |s| {
13337            s.move_heads_with(|map, head, goal| {
13338                movement::down(map, head, goal, false, text_layout_details)
13339            })
13340        });
13341    }
13342
13343    pub fn context_menu_first(
13344        &mut self,
13345        _: &ContextMenuFirst,
13346        window: &mut Window,
13347        cx: &mut Context<Self>,
13348    ) {
13349        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13350            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13351        }
13352    }
13353
13354    pub fn context_menu_prev(
13355        &mut self,
13356        _: &ContextMenuPrevious,
13357        window: &mut Window,
13358        cx: &mut Context<Self>,
13359    ) {
13360        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13361            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13362        }
13363    }
13364
13365    pub fn context_menu_next(
13366        &mut self,
13367        _: &ContextMenuNext,
13368        window: &mut Window,
13369        cx: &mut Context<Self>,
13370    ) {
13371        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13372            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13373        }
13374    }
13375
13376    pub fn context_menu_last(
13377        &mut self,
13378        _: &ContextMenuLast,
13379        window: &mut Window,
13380        cx: &mut Context<Self>,
13381    ) {
13382        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13383            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13384        }
13385    }
13386
13387    pub fn signature_help_prev(
13388        &mut self,
13389        _: &SignatureHelpPrevious,
13390        _: &mut Window,
13391        cx: &mut Context<Self>,
13392    ) {
13393        if let Some(popover) = self.signature_help_state.popover_mut() {
13394            if popover.current_signature == 0 {
13395                popover.current_signature = popover.signatures.len() - 1;
13396            } else {
13397                popover.current_signature -= 1;
13398            }
13399            cx.notify();
13400        }
13401    }
13402
13403    pub fn signature_help_next(
13404        &mut self,
13405        _: &SignatureHelpNext,
13406        _: &mut Window,
13407        cx: &mut Context<Self>,
13408    ) {
13409        if let Some(popover) = self.signature_help_state.popover_mut() {
13410            if popover.current_signature + 1 == popover.signatures.len() {
13411                popover.current_signature = 0;
13412            } else {
13413                popover.current_signature += 1;
13414            }
13415            cx.notify();
13416        }
13417    }
13418
13419    pub fn move_to_previous_word_start(
13420        &mut self,
13421        _: &MoveToPreviousWordStart,
13422        window: &mut Window,
13423        cx: &mut Context<Self>,
13424    ) {
13425        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13426        self.change_selections(Default::default(), window, cx, |s| {
13427            s.move_cursors_with(|map, head, _| {
13428                (
13429                    movement::previous_word_start(map, head),
13430                    SelectionGoal::None,
13431                )
13432            });
13433        })
13434    }
13435
13436    pub fn move_to_previous_subword_start(
13437        &mut self,
13438        _: &MoveToPreviousSubwordStart,
13439        window: &mut Window,
13440        cx: &mut Context<Self>,
13441    ) {
13442        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13443        self.change_selections(Default::default(), window, cx, |s| {
13444            s.move_cursors_with(|map, head, _| {
13445                (
13446                    movement::previous_subword_start(map, head),
13447                    SelectionGoal::None,
13448                )
13449            });
13450        })
13451    }
13452
13453    pub fn select_to_previous_word_start(
13454        &mut self,
13455        _: &SelectToPreviousWordStart,
13456        window: &mut Window,
13457        cx: &mut Context<Self>,
13458    ) {
13459        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13460        self.change_selections(Default::default(), window, cx, |s| {
13461            s.move_heads_with(|map, head, _| {
13462                (
13463                    movement::previous_word_start(map, head),
13464                    SelectionGoal::None,
13465                )
13466            });
13467        })
13468    }
13469
13470    pub fn select_to_previous_subword_start(
13471        &mut self,
13472        _: &SelectToPreviousSubwordStart,
13473        window: &mut Window,
13474        cx: &mut Context<Self>,
13475    ) {
13476        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13477        self.change_selections(Default::default(), window, cx, |s| {
13478            s.move_heads_with(|map, head, _| {
13479                (
13480                    movement::previous_subword_start(map, head),
13481                    SelectionGoal::None,
13482                )
13483            });
13484        })
13485    }
13486
13487    pub fn delete_to_previous_word_start(
13488        &mut self,
13489        action: &DeleteToPreviousWordStart,
13490        window: &mut Window,
13491        cx: &mut Context<Self>,
13492    ) {
13493        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13494        self.transact(window, cx, |this, window, cx| {
13495            this.select_autoclose_pair(window, cx);
13496            this.change_selections(Default::default(), window, cx, |s| {
13497                s.move_with(|map, selection| {
13498                    if selection.is_empty() {
13499                        let mut cursor = if action.ignore_newlines {
13500                            movement::previous_word_start(map, selection.head())
13501                        } else {
13502                            movement::previous_word_start_or_newline(map, selection.head())
13503                        };
13504                        cursor = movement::adjust_greedy_deletion(
13505                            map,
13506                            selection.head(),
13507                            cursor,
13508                            action.ignore_brackets,
13509                        );
13510                        selection.set_head(cursor, SelectionGoal::None);
13511                    }
13512                });
13513            });
13514            this.insert("", window, cx);
13515        });
13516    }
13517
13518    pub fn delete_to_previous_subword_start(
13519        &mut self,
13520        _: &DeleteToPreviousSubwordStart,
13521        window: &mut Window,
13522        cx: &mut Context<Self>,
13523    ) {
13524        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13525        self.transact(window, cx, |this, window, cx| {
13526            this.select_autoclose_pair(window, cx);
13527            this.change_selections(Default::default(), window, cx, |s| {
13528                s.move_with(|map, selection| {
13529                    if selection.is_empty() {
13530                        let mut cursor = movement::previous_subword_start(map, selection.head());
13531                        cursor =
13532                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13533                        selection.set_head(cursor, SelectionGoal::None);
13534                    }
13535                });
13536            });
13537            this.insert("", window, cx);
13538        });
13539    }
13540
13541    pub fn move_to_next_word_end(
13542        &mut self,
13543        _: &MoveToNextWordEnd,
13544        window: &mut Window,
13545        cx: &mut Context<Self>,
13546    ) {
13547        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13548        self.change_selections(Default::default(), window, cx, |s| {
13549            s.move_cursors_with(|map, head, _| {
13550                (movement::next_word_end(map, head), SelectionGoal::None)
13551            });
13552        })
13553    }
13554
13555    pub fn move_to_next_subword_end(
13556        &mut self,
13557        _: &MoveToNextSubwordEnd,
13558        window: &mut Window,
13559        cx: &mut Context<Self>,
13560    ) {
13561        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13562        self.change_selections(Default::default(), window, cx, |s| {
13563            s.move_cursors_with(|map, head, _| {
13564                (movement::next_subword_end(map, head), SelectionGoal::None)
13565            });
13566        })
13567    }
13568
13569    pub fn select_to_next_word_end(
13570        &mut self,
13571        _: &SelectToNextWordEnd,
13572        window: &mut Window,
13573        cx: &mut Context<Self>,
13574    ) {
13575        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13576        self.change_selections(Default::default(), window, cx, |s| {
13577            s.move_heads_with(|map, head, _| {
13578                (movement::next_word_end(map, head), SelectionGoal::None)
13579            });
13580        })
13581    }
13582
13583    pub fn select_to_next_subword_end(
13584        &mut self,
13585        _: &SelectToNextSubwordEnd,
13586        window: &mut Window,
13587        cx: &mut Context<Self>,
13588    ) {
13589        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13590        self.change_selections(Default::default(), window, cx, |s| {
13591            s.move_heads_with(|map, head, _| {
13592                (movement::next_subword_end(map, head), SelectionGoal::None)
13593            });
13594        })
13595    }
13596
13597    pub fn delete_to_next_word_end(
13598        &mut self,
13599        action: &DeleteToNextWordEnd,
13600        window: &mut Window,
13601        cx: &mut Context<Self>,
13602    ) {
13603        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13604        self.transact(window, cx, |this, window, cx| {
13605            this.change_selections(Default::default(), window, cx, |s| {
13606                s.move_with(|map, selection| {
13607                    if selection.is_empty() {
13608                        let mut cursor = if action.ignore_newlines {
13609                            movement::next_word_end(map, selection.head())
13610                        } else {
13611                            movement::next_word_end_or_newline(map, selection.head())
13612                        };
13613                        cursor = movement::adjust_greedy_deletion(
13614                            map,
13615                            selection.head(),
13616                            cursor,
13617                            action.ignore_brackets,
13618                        );
13619                        selection.set_head(cursor, SelectionGoal::None);
13620                    }
13621                });
13622            });
13623            this.insert("", window, cx);
13624        });
13625    }
13626
13627    pub fn delete_to_next_subword_end(
13628        &mut self,
13629        _: &DeleteToNextSubwordEnd,
13630        window: &mut Window,
13631        cx: &mut Context<Self>,
13632    ) {
13633        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13634        self.transact(window, cx, |this, window, cx| {
13635            this.change_selections(Default::default(), window, cx, |s| {
13636                s.move_with(|map, selection| {
13637                    if selection.is_empty() {
13638                        let mut cursor = movement::next_subword_end(map, selection.head());
13639                        cursor =
13640                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13641                        selection.set_head(cursor, SelectionGoal::None);
13642                    }
13643                });
13644            });
13645            this.insert("", window, cx);
13646        });
13647    }
13648
13649    pub fn move_to_beginning_of_line(
13650        &mut self,
13651        action: &MoveToBeginningOfLine,
13652        window: &mut Window,
13653        cx: &mut Context<Self>,
13654    ) {
13655        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13656        self.change_selections(Default::default(), window, cx, |s| {
13657            s.move_cursors_with(|map, head, _| {
13658                (
13659                    movement::indented_line_beginning(
13660                        map,
13661                        head,
13662                        action.stop_at_soft_wraps,
13663                        action.stop_at_indent,
13664                    ),
13665                    SelectionGoal::None,
13666                )
13667            });
13668        })
13669    }
13670
13671    pub fn select_to_beginning_of_line(
13672        &mut self,
13673        action: &SelectToBeginningOfLine,
13674        window: &mut Window,
13675        cx: &mut Context<Self>,
13676    ) {
13677        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13678        self.change_selections(Default::default(), window, cx, |s| {
13679            s.move_heads_with(|map, head, _| {
13680                (
13681                    movement::indented_line_beginning(
13682                        map,
13683                        head,
13684                        action.stop_at_soft_wraps,
13685                        action.stop_at_indent,
13686                    ),
13687                    SelectionGoal::None,
13688                )
13689            });
13690        });
13691    }
13692
13693    pub fn delete_to_beginning_of_line(
13694        &mut self,
13695        action: &DeleteToBeginningOfLine,
13696        window: &mut Window,
13697        cx: &mut Context<Self>,
13698    ) {
13699        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13700        self.transact(window, cx, |this, window, cx| {
13701            this.change_selections(Default::default(), window, cx, |s| {
13702                s.move_with(|_, selection| {
13703                    selection.reversed = true;
13704                });
13705            });
13706
13707            this.select_to_beginning_of_line(
13708                &SelectToBeginningOfLine {
13709                    stop_at_soft_wraps: false,
13710                    stop_at_indent: action.stop_at_indent,
13711                },
13712                window,
13713                cx,
13714            );
13715            this.backspace(&Backspace, window, cx);
13716        });
13717    }
13718
13719    pub fn move_to_end_of_line(
13720        &mut self,
13721        action: &MoveToEndOfLine,
13722        window: &mut Window,
13723        cx: &mut Context<Self>,
13724    ) {
13725        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13726        self.change_selections(Default::default(), window, cx, |s| {
13727            s.move_cursors_with(|map, head, _| {
13728                (
13729                    movement::line_end(map, head, action.stop_at_soft_wraps),
13730                    SelectionGoal::None,
13731                )
13732            });
13733        })
13734    }
13735
13736    pub fn select_to_end_of_line(
13737        &mut self,
13738        action: &SelectToEndOfLine,
13739        window: &mut Window,
13740        cx: &mut Context<Self>,
13741    ) {
13742        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13743        self.change_selections(Default::default(), window, cx, |s| {
13744            s.move_heads_with(|map, head, _| {
13745                (
13746                    movement::line_end(map, head, action.stop_at_soft_wraps),
13747                    SelectionGoal::None,
13748                )
13749            });
13750        })
13751    }
13752
13753    pub fn delete_to_end_of_line(
13754        &mut self,
13755        _: &DeleteToEndOfLine,
13756        window: &mut Window,
13757        cx: &mut Context<Self>,
13758    ) {
13759        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13760        self.transact(window, cx, |this, window, cx| {
13761            this.select_to_end_of_line(
13762                &SelectToEndOfLine {
13763                    stop_at_soft_wraps: false,
13764                },
13765                window,
13766                cx,
13767            );
13768            this.delete(&Delete, window, cx);
13769        });
13770    }
13771
13772    pub fn cut_to_end_of_line(
13773        &mut self,
13774        action: &CutToEndOfLine,
13775        window: &mut Window,
13776        cx: &mut Context<Self>,
13777    ) {
13778        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13779        self.transact(window, cx, |this, window, cx| {
13780            this.select_to_end_of_line(
13781                &SelectToEndOfLine {
13782                    stop_at_soft_wraps: false,
13783                },
13784                window,
13785                cx,
13786            );
13787            if !action.stop_at_newlines {
13788                this.change_selections(Default::default(), window, cx, |s| {
13789                    s.move_with(|_, sel| {
13790                        if sel.is_empty() {
13791                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13792                        }
13793                    });
13794                });
13795            }
13796            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13797            let item = this.cut_common(false, window, cx);
13798            cx.write_to_clipboard(item);
13799        });
13800    }
13801
13802    pub fn move_to_start_of_paragraph(
13803        &mut self,
13804        _: &MoveToStartOfParagraph,
13805        window: &mut Window,
13806        cx: &mut Context<Self>,
13807    ) {
13808        if matches!(self.mode, EditorMode::SingleLine) {
13809            cx.propagate();
13810            return;
13811        }
13812        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13813        self.change_selections(Default::default(), window, cx, |s| {
13814            s.move_with(|map, selection| {
13815                selection.collapse_to(
13816                    movement::start_of_paragraph(map, selection.head(), 1),
13817                    SelectionGoal::None,
13818                )
13819            });
13820        })
13821    }
13822
13823    pub fn move_to_end_of_paragraph(
13824        &mut self,
13825        _: &MoveToEndOfParagraph,
13826        window: &mut Window,
13827        cx: &mut Context<Self>,
13828    ) {
13829        if matches!(self.mode, EditorMode::SingleLine) {
13830            cx.propagate();
13831            return;
13832        }
13833        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13834        self.change_selections(Default::default(), window, cx, |s| {
13835            s.move_with(|map, selection| {
13836                selection.collapse_to(
13837                    movement::end_of_paragraph(map, selection.head(), 1),
13838                    SelectionGoal::None,
13839                )
13840            });
13841        })
13842    }
13843
13844    pub fn select_to_start_of_paragraph(
13845        &mut self,
13846        _: &SelectToStartOfParagraph,
13847        window: &mut Window,
13848        cx: &mut Context<Self>,
13849    ) {
13850        if matches!(self.mode, EditorMode::SingleLine) {
13851            cx.propagate();
13852            return;
13853        }
13854        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13855        self.change_selections(Default::default(), window, cx, |s| {
13856            s.move_heads_with(|map, head, _| {
13857                (
13858                    movement::start_of_paragraph(map, head, 1),
13859                    SelectionGoal::None,
13860                )
13861            });
13862        })
13863    }
13864
13865    pub fn select_to_end_of_paragraph(
13866        &mut self,
13867        _: &SelectToEndOfParagraph,
13868        window: &mut Window,
13869        cx: &mut Context<Self>,
13870    ) {
13871        if matches!(self.mode, EditorMode::SingleLine) {
13872            cx.propagate();
13873            return;
13874        }
13875        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13876        self.change_selections(Default::default(), window, cx, |s| {
13877            s.move_heads_with(|map, head, _| {
13878                (
13879                    movement::end_of_paragraph(map, head, 1),
13880                    SelectionGoal::None,
13881                )
13882            });
13883        })
13884    }
13885
13886    pub fn move_to_start_of_excerpt(
13887        &mut self,
13888        _: &MoveToStartOfExcerpt,
13889        window: &mut Window,
13890        cx: &mut Context<Self>,
13891    ) {
13892        if matches!(self.mode, EditorMode::SingleLine) {
13893            cx.propagate();
13894            return;
13895        }
13896        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13897        self.change_selections(Default::default(), window, cx, |s| {
13898            s.move_with(|map, selection| {
13899                selection.collapse_to(
13900                    movement::start_of_excerpt(
13901                        map,
13902                        selection.head(),
13903                        workspace::searchable::Direction::Prev,
13904                    ),
13905                    SelectionGoal::None,
13906                )
13907            });
13908        })
13909    }
13910
13911    pub fn move_to_start_of_next_excerpt(
13912        &mut self,
13913        _: &MoveToStartOfNextExcerpt,
13914        window: &mut Window,
13915        cx: &mut Context<Self>,
13916    ) {
13917        if matches!(self.mode, EditorMode::SingleLine) {
13918            cx.propagate();
13919            return;
13920        }
13921
13922        self.change_selections(Default::default(), window, cx, |s| {
13923            s.move_with(|map, selection| {
13924                selection.collapse_to(
13925                    movement::start_of_excerpt(
13926                        map,
13927                        selection.head(),
13928                        workspace::searchable::Direction::Next,
13929                    ),
13930                    SelectionGoal::None,
13931                )
13932            });
13933        })
13934    }
13935
13936    pub fn move_to_end_of_excerpt(
13937        &mut self,
13938        _: &MoveToEndOfExcerpt,
13939        window: &mut Window,
13940        cx: &mut Context<Self>,
13941    ) {
13942        if matches!(self.mode, EditorMode::SingleLine) {
13943            cx.propagate();
13944            return;
13945        }
13946        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13947        self.change_selections(Default::default(), window, cx, |s| {
13948            s.move_with(|map, selection| {
13949                selection.collapse_to(
13950                    movement::end_of_excerpt(
13951                        map,
13952                        selection.head(),
13953                        workspace::searchable::Direction::Next,
13954                    ),
13955                    SelectionGoal::None,
13956                )
13957            });
13958        })
13959    }
13960
13961    pub fn move_to_end_of_previous_excerpt(
13962        &mut self,
13963        _: &MoveToEndOfPreviousExcerpt,
13964        window: &mut Window,
13965        cx: &mut Context<Self>,
13966    ) {
13967        if matches!(self.mode, EditorMode::SingleLine) {
13968            cx.propagate();
13969            return;
13970        }
13971        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13972        self.change_selections(Default::default(), window, cx, |s| {
13973            s.move_with(|map, selection| {
13974                selection.collapse_to(
13975                    movement::end_of_excerpt(
13976                        map,
13977                        selection.head(),
13978                        workspace::searchable::Direction::Prev,
13979                    ),
13980                    SelectionGoal::None,
13981                )
13982            });
13983        })
13984    }
13985
13986    pub fn select_to_start_of_excerpt(
13987        &mut self,
13988        _: &SelectToStartOfExcerpt,
13989        window: &mut Window,
13990        cx: &mut Context<Self>,
13991    ) {
13992        if matches!(self.mode, EditorMode::SingleLine) {
13993            cx.propagate();
13994            return;
13995        }
13996        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13997        self.change_selections(Default::default(), window, cx, |s| {
13998            s.move_heads_with(|map, head, _| {
13999                (
14000                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14001                    SelectionGoal::None,
14002                )
14003            });
14004        })
14005    }
14006
14007    pub fn select_to_start_of_next_excerpt(
14008        &mut self,
14009        _: &SelectToStartOfNextExcerpt,
14010        window: &mut Window,
14011        cx: &mut Context<Self>,
14012    ) {
14013        if matches!(self.mode, EditorMode::SingleLine) {
14014            cx.propagate();
14015            return;
14016        }
14017        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14018        self.change_selections(Default::default(), window, cx, |s| {
14019            s.move_heads_with(|map, head, _| {
14020                (
14021                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14022                    SelectionGoal::None,
14023                )
14024            });
14025        })
14026    }
14027
14028    pub fn select_to_end_of_excerpt(
14029        &mut self,
14030        _: &SelectToEndOfExcerpt,
14031        window: &mut Window,
14032        cx: &mut Context<Self>,
14033    ) {
14034        if matches!(self.mode, EditorMode::SingleLine) {
14035            cx.propagate();
14036            return;
14037        }
14038        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14039        self.change_selections(Default::default(), window, cx, |s| {
14040            s.move_heads_with(|map, head, _| {
14041                (
14042                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14043                    SelectionGoal::None,
14044                )
14045            });
14046        })
14047    }
14048
14049    pub fn select_to_end_of_previous_excerpt(
14050        &mut self,
14051        _: &SelectToEndOfPreviousExcerpt,
14052        window: &mut Window,
14053        cx: &mut Context<Self>,
14054    ) {
14055        if matches!(self.mode, EditorMode::SingleLine) {
14056            cx.propagate();
14057            return;
14058        }
14059        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14060        self.change_selections(Default::default(), window, cx, |s| {
14061            s.move_heads_with(|map, head, _| {
14062                (
14063                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14064                    SelectionGoal::None,
14065                )
14066            });
14067        })
14068    }
14069
14070    pub fn move_to_beginning(
14071        &mut self,
14072        _: &MoveToBeginning,
14073        window: &mut Window,
14074        cx: &mut Context<Self>,
14075    ) {
14076        if matches!(self.mode, EditorMode::SingleLine) {
14077            cx.propagate();
14078            return;
14079        }
14080        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14081        self.change_selections(Default::default(), window, cx, |s| {
14082            s.select_ranges(vec![0..0]);
14083        });
14084    }
14085
14086    pub fn select_to_beginning(
14087        &mut self,
14088        _: &SelectToBeginning,
14089        window: &mut Window,
14090        cx: &mut Context<Self>,
14091    ) {
14092        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14093        selection.set_head(Point::zero(), SelectionGoal::None);
14094        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14095        self.change_selections(Default::default(), window, cx, |s| {
14096            s.select(vec![selection]);
14097        });
14098    }
14099
14100    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14101        if matches!(self.mode, EditorMode::SingleLine) {
14102            cx.propagate();
14103            return;
14104        }
14105        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14106        let cursor = self.buffer.read(cx).read(cx).len();
14107        self.change_selections(Default::default(), window, cx, |s| {
14108            s.select_ranges(vec![cursor..cursor])
14109        });
14110    }
14111
14112    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14113        self.nav_history = nav_history;
14114    }
14115
14116    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14117        self.nav_history.as_ref()
14118    }
14119
14120    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14121        self.push_to_nav_history(
14122            self.selections.newest_anchor().head(),
14123            None,
14124            false,
14125            true,
14126            cx,
14127        );
14128    }
14129
14130    fn push_to_nav_history(
14131        &mut self,
14132        cursor_anchor: Anchor,
14133        new_position: Option<Point>,
14134        is_deactivate: bool,
14135        always: bool,
14136        cx: &mut Context<Self>,
14137    ) {
14138        if let Some(nav_history) = self.nav_history.as_mut() {
14139            let buffer = self.buffer.read(cx).read(cx);
14140            let cursor_position = cursor_anchor.to_point(&buffer);
14141            let scroll_state = self.scroll_manager.anchor();
14142            let scroll_top_row = scroll_state.top_row(&buffer);
14143            drop(buffer);
14144
14145            if let Some(new_position) = new_position {
14146                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14147                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14148                    return;
14149                }
14150            }
14151
14152            nav_history.push(
14153                Some(NavigationData {
14154                    cursor_anchor,
14155                    cursor_position,
14156                    scroll_anchor: scroll_state,
14157                    scroll_top_row,
14158                }),
14159                cx,
14160            );
14161            cx.emit(EditorEvent::PushedToNavHistory {
14162                anchor: cursor_anchor,
14163                is_deactivate,
14164            })
14165        }
14166    }
14167
14168    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14169        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14170        let buffer = self.buffer.read(cx).snapshot(cx);
14171        let mut selection = self.selections.first::<usize>(&self.display_snapshot(cx));
14172        selection.set_head(buffer.len(), SelectionGoal::None);
14173        self.change_selections(Default::default(), window, cx, |s| {
14174            s.select(vec![selection]);
14175        });
14176    }
14177
14178    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14179        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14180        let end = self.buffer.read(cx).read(cx).len();
14181        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14182            s.select_ranges(vec![0..end]);
14183        });
14184    }
14185
14186    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14187        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14188        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14189        let mut selections = self.selections.all::<Point>(&display_map);
14190        let max_point = display_map.buffer_snapshot().max_point();
14191        for selection in &mut selections {
14192            let rows = selection.spanned_rows(true, &display_map);
14193            selection.start = Point::new(rows.start.0, 0);
14194            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14195            selection.reversed = false;
14196        }
14197        self.change_selections(Default::default(), window, cx, |s| {
14198            s.select(selections);
14199        });
14200    }
14201
14202    pub fn split_selection_into_lines(
14203        &mut self,
14204        action: &SplitSelectionIntoLines,
14205        window: &mut Window,
14206        cx: &mut Context<Self>,
14207    ) {
14208        let selections = self
14209            .selections
14210            .all::<Point>(&self.display_snapshot(cx))
14211            .into_iter()
14212            .map(|selection| selection.start..selection.end)
14213            .collect::<Vec<_>>();
14214        self.unfold_ranges(&selections, true, true, cx);
14215
14216        let mut new_selection_ranges = Vec::new();
14217        {
14218            let buffer = self.buffer.read(cx).read(cx);
14219            for selection in selections {
14220                for row in selection.start.row..selection.end.row {
14221                    let line_start = Point::new(row, 0);
14222                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14223
14224                    if action.keep_selections {
14225                        // Keep the selection range for each line
14226                        let selection_start = if row == selection.start.row {
14227                            selection.start
14228                        } else {
14229                            line_start
14230                        };
14231                        new_selection_ranges.push(selection_start..line_end);
14232                    } else {
14233                        // Collapse to cursor at end of line
14234                        new_selection_ranges.push(line_end..line_end);
14235                    }
14236                }
14237
14238                let is_multiline_selection = selection.start.row != selection.end.row;
14239                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14240                // so this action feels more ergonomic when paired with other selection operations
14241                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14242                if !should_skip_last {
14243                    if action.keep_selections {
14244                        if is_multiline_selection {
14245                            let line_start = Point::new(selection.end.row, 0);
14246                            new_selection_ranges.push(line_start..selection.end);
14247                        } else {
14248                            new_selection_ranges.push(selection.start..selection.end);
14249                        }
14250                    } else {
14251                        new_selection_ranges.push(selection.end..selection.end);
14252                    }
14253                }
14254            }
14255        }
14256        self.change_selections(Default::default(), window, cx, |s| {
14257            s.select_ranges(new_selection_ranges);
14258        });
14259    }
14260
14261    pub fn add_selection_above(
14262        &mut self,
14263        action: &AddSelectionAbove,
14264        window: &mut Window,
14265        cx: &mut Context<Self>,
14266    ) {
14267        self.add_selection(true, action.skip_soft_wrap, window, cx);
14268    }
14269
14270    pub fn add_selection_below(
14271        &mut self,
14272        action: &AddSelectionBelow,
14273        window: &mut Window,
14274        cx: &mut Context<Self>,
14275    ) {
14276        self.add_selection(false, action.skip_soft_wrap, window, cx);
14277    }
14278
14279    fn add_selection(
14280        &mut self,
14281        above: bool,
14282        skip_soft_wrap: bool,
14283        window: &mut Window,
14284        cx: &mut Context<Self>,
14285    ) {
14286        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14287
14288        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14289        let all_selections = self.selections.all::<Point>(&display_map);
14290        let text_layout_details = self.text_layout_details(window);
14291
14292        let (mut columnar_selections, new_selections_to_columnarize) = {
14293            if let Some(state) = self.add_selections_state.as_ref() {
14294                let columnar_selection_ids: HashSet<_> = state
14295                    .groups
14296                    .iter()
14297                    .flat_map(|group| group.stack.iter())
14298                    .copied()
14299                    .collect();
14300
14301                all_selections
14302                    .into_iter()
14303                    .partition(|s| columnar_selection_ids.contains(&s.id))
14304            } else {
14305                (Vec::new(), all_selections)
14306            }
14307        };
14308
14309        let mut state = self
14310            .add_selections_state
14311            .take()
14312            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14313
14314        for selection in new_selections_to_columnarize {
14315            let range = selection.display_range(&display_map).sorted();
14316            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14317            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14318            let positions = start_x.min(end_x)..start_x.max(end_x);
14319            let mut stack = Vec::new();
14320            for row in range.start.row().0..=range.end.row().0 {
14321                if let Some(selection) = self.selections.build_columnar_selection(
14322                    &display_map,
14323                    DisplayRow(row),
14324                    &positions,
14325                    selection.reversed,
14326                    &text_layout_details,
14327                ) {
14328                    stack.push(selection.id);
14329                    columnar_selections.push(selection);
14330                }
14331            }
14332            if !stack.is_empty() {
14333                if above {
14334                    stack.reverse();
14335                }
14336                state.groups.push(AddSelectionsGroup { above, stack });
14337            }
14338        }
14339
14340        let mut final_selections = Vec::new();
14341        let end_row = if above {
14342            DisplayRow(0)
14343        } else {
14344            display_map.max_point().row()
14345        };
14346
14347        let mut last_added_item_per_group = HashMap::default();
14348        for group in state.groups.iter_mut() {
14349            if let Some(last_id) = group.stack.last() {
14350                last_added_item_per_group.insert(*last_id, group);
14351            }
14352        }
14353
14354        for selection in columnar_selections {
14355            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14356                if above == group.above {
14357                    let range = selection.display_range(&display_map).sorted();
14358                    debug_assert_eq!(range.start.row(), range.end.row());
14359                    let mut row = range.start.row();
14360                    let positions =
14361                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14362                            Pixels::from(start)..Pixels::from(end)
14363                        } else {
14364                            let start_x =
14365                                display_map.x_for_display_point(range.start, &text_layout_details);
14366                            let end_x =
14367                                display_map.x_for_display_point(range.end, &text_layout_details);
14368                            start_x.min(end_x)..start_x.max(end_x)
14369                        };
14370
14371                    let mut maybe_new_selection = None;
14372                    let direction = if above { -1 } else { 1 };
14373
14374                    while row != end_row {
14375                        if skip_soft_wrap {
14376                            row = display_map
14377                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14378                                .row();
14379                        } else if above {
14380                            row.0 -= 1;
14381                        } else {
14382                            row.0 += 1;
14383                        }
14384
14385                        if let Some(new_selection) = self.selections.build_columnar_selection(
14386                            &display_map,
14387                            row,
14388                            &positions,
14389                            selection.reversed,
14390                            &text_layout_details,
14391                        ) {
14392                            maybe_new_selection = Some(new_selection);
14393                            break;
14394                        }
14395                    }
14396
14397                    if let Some(new_selection) = maybe_new_selection {
14398                        group.stack.push(new_selection.id);
14399                        if above {
14400                            final_selections.push(new_selection);
14401                            final_selections.push(selection);
14402                        } else {
14403                            final_selections.push(selection);
14404                            final_selections.push(new_selection);
14405                        }
14406                    } else {
14407                        final_selections.push(selection);
14408                    }
14409                } else {
14410                    group.stack.pop();
14411                }
14412            } else {
14413                final_selections.push(selection);
14414            }
14415        }
14416
14417        self.change_selections(Default::default(), window, cx, |s| {
14418            s.select(final_selections);
14419        });
14420
14421        let final_selection_ids: HashSet<_> = self
14422            .selections
14423            .all::<Point>(&display_map)
14424            .iter()
14425            .map(|s| s.id)
14426            .collect();
14427        state.groups.retain_mut(|group| {
14428            // selections might get merged above so we remove invalid items from stacks
14429            group.stack.retain(|id| final_selection_ids.contains(id));
14430
14431            // single selection in stack can be treated as initial state
14432            group.stack.len() > 1
14433        });
14434
14435        if !state.groups.is_empty() {
14436            self.add_selections_state = Some(state);
14437        }
14438    }
14439
14440    fn select_match_ranges(
14441        &mut self,
14442        range: Range<usize>,
14443        reversed: bool,
14444        replace_newest: bool,
14445        auto_scroll: Option<Autoscroll>,
14446        window: &mut Window,
14447        cx: &mut Context<Editor>,
14448    ) {
14449        self.unfold_ranges(
14450            std::slice::from_ref(&range),
14451            false,
14452            auto_scroll.is_some(),
14453            cx,
14454        );
14455        let effects = if let Some(scroll) = auto_scroll {
14456            SelectionEffects::scroll(scroll)
14457        } else {
14458            SelectionEffects::no_scroll()
14459        };
14460        self.change_selections(effects, window, cx, |s| {
14461            if replace_newest {
14462                s.delete(s.newest_anchor().id);
14463            }
14464            if reversed {
14465                s.insert_range(range.end..range.start);
14466            } else {
14467                s.insert_range(range);
14468            }
14469        });
14470    }
14471
14472    pub fn select_next_match_internal(
14473        &mut self,
14474        display_map: &DisplaySnapshot,
14475        replace_newest: bool,
14476        autoscroll: Option<Autoscroll>,
14477        window: &mut Window,
14478        cx: &mut Context<Self>,
14479    ) -> Result<()> {
14480        let buffer = display_map.buffer_snapshot();
14481        let mut selections = self.selections.all::<usize>(&display_map);
14482        if let Some(mut select_next_state) = self.select_next_state.take() {
14483            let query = &select_next_state.query;
14484            if !select_next_state.done {
14485                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14486                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14487                let mut next_selected_range = None;
14488
14489                let bytes_after_last_selection =
14490                    buffer.bytes_in_range(last_selection.end..buffer.len());
14491                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14492                let query_matches = query
14493                    .stream_find_iter(bytes_after_last_selection)
14494                    .map(|result| (last_selection.end, result))
14495                    .chain(
14496                        query
14497                            .stream_find_iter(bytes_before_first_selection)
14498                            .map(|result| (0, result)),
14499                    );
14500
14501                for (start_offset, query_match) in query_matches {
14502                    let query_match = query_match.unwrap(); // can only fail due to I/O
14503                    let offset_range =
14504                        start_offset + query_match.start()..start_offset + query_match.end();
14505
14506                    if !select_next_state.wordwise
14507                        || (!buffer.is_inside_word(offset_range.start, None)
14508                            && !buffer.is_inside_word(offset_range.end, None))
14509                    {
14510                        let idx = selections
14511                            .partition_point(|selection| selection.end <= offset_range.start);
14512                        let overlaps = selections
14513                            .get(idx)
14514                            .map_or(false, |selection| selection.start < offset_range.end);
14515
14516                        if !overlaps {
14517                            next_selected_range = Some(offset_range);
14518                            break;
14519                        }
14520                    }
14521                }
14522
14523                if let Some(next_selected_range) = next_selected_range {
14524                    self.select_match_ranges(
14525                        next_selected_range,
14526                        last_selection.reversed,
14527                        replace_newest,
14528                        autoscroll,
14529                        window,
14530                        cx,
14531                    );
14532                } else {
14533                    select_next_state.done = true;
14534                }
14535            }
14536
14537            self.select_next_state = Some(select_next_state);
14538        } else {
14539            let mut only_carets = true;
14540            let mut same_text_selected = true;
14541            let mut selected_text = None;
14542
14543            let mut selections_iter = selections.iter().peekable();
14544            while let Some(selection) = selections_iter.next() {
14545                if selection.start != selection.end {
14546                    only_carets = false;
14547                }
14548
14549                if same_text_selected {
14550                    if selected_text.is_none() {
14551                        selected_text =
14552                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14553                    }
14554
14555                    if let Some(next_selection) = selections_iter.peek() {
14556                        if next_selection.range().len() == selection.range().len() {
14557                            let next_selected_text = buffer
14558                                .text_for_range(next_selection.range())
14559                                .collect::<String>();
14560                            if Some(next_selected_text) != selected_text {
14561                                same_text_selected = false;
14562                                selected_text = None;
14563                            }
14564                        } else {
14565                            same_text_selected = false;
14566                            selected_text = None;
14567                        }
14568                    }
14569                }
14570            }
14571
14572            if only_carets {
14573                for selection in &mut selections {
14574                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14575                    selection.start = word_range.start;
14576                    selection.end = word_range.end;
14577                    selection.goal = SelectionGoal::None;
14578                    selection.reversed = false;
14579                    self.select_match_ranges(
14580                        selection.start..selection.end,
14581                        selection.reversed,
14582                        replace_newest,
14583                        autoscroll,
14584                        window,
14585                        cx,
14586                    );
14587                }
14588
14589                if selections.len() == 1 {
14590                    let selection = selections
14591                        .last()
14592                        .expect("ensured that there's only one selection");
14593                    let query = buffer
14594                        .text_for_range(selection.start..selection.end)
14595                        .collect::<String>();
14596                    let is_empty = query.is_empty();
14597                    let select_state = SelectNextState {
14598                        query: AhoCorasick::new(&[query])?,
14599                        wordwise: true,
14600                        done: is_empty,
14601                    };
14602                    self.select_next_state = Some(select_state);
14603                } else {
14604                    self.select_next_state = None;
14605                }
14606            } else if let Some(selected_text) = selected_text {
14607                self.select_next_state = Some(SelectNextState {
14608                    query: AhoCorasick::new(&[selected_text])?,
14609                    wordwise: false,
14610                    done: false,
14611                });
14612                self.select_next_match_internal(
14613                    display_map,
14614                    replace_newest,
14615                    autoscroll,
14616                    window,
14617                    cx,
14618                )?;
14619            }
14620        }
14621        Ok(())
14622    }
14623
14624    pub fn select_all_matches(
14625        &mut self,
14626        _action: &SelectAllMatches,
14627        window: &mut Window,
14628        cx: &mut Context<Self>,
14629    ) -> Result<()> {
14630        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14631
14632        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14633
14634        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14635        let Some(select_next_state) = self.select_next_state.as_mut() else {
14636            return Ok(());
14637        };
14638        if select_next_state.done {
14639            return Ok(());
14640        }
14641
14642        let mut new_selections = Vec::new();
14643
14644        let reversed = self.selections.oldest::<usize>(&display_map).reversed;
14645        let buffer = display_map.buffer_snapshot();
14646        let query_matches = select_next_state
14647            .query
14648            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14649
14650        for query_match in query_matches.into_iter() {
14651            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14652            let offset_range = if reversed {
14653                query_match.end()..query_match.start()
14654            } else {
14655                query_match.start()..query_match.end()
14656            };
14657
14658            if !select_next_state.wordwise
14659                || (!buffer.is_inside_word(offset_range.start, None)
14660                    && !buffer.is_inside_word(offset_range.end, None))
14661            {
14662                new_selections.push(offset_range.start..offset_range.end);
14663            }
14664        }
14665
14666        select_next_state.done = true;
14667
14668        if new_selections.is_empty() {
14669            log::error!("bug: new_selections is empty in select_all_matches");
14670            return Ok(());
14671        }
14672
14673        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14674        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14675            selections.select_ranges(new_selections)
14676        });
14677
14678        Ok(())
14679    }
14680
14681    pub fn select_next(
14682        &mut self,
14683        action: &SelectNext,
14684        window: &mut Window,
14685        cx: &mut Context<Self>,
14686    ) -> Result<()> {
14687        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14688        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14689        self.select_next_match_internal(
14690            &display_map,
14691            action.replace_newest,
14692            Some(Autoscroll::newest()),
14693            window,
14694            cx,
14695        )?;
14696        Ok(())
14697    }
14698
14699    pub fn select_previous(
14700        &mut self,
14701        action: &SelectPrevious,
14702        window: &mut Window,
14703        cx: &mut Context<Self>,
14704    ) -> Result<()> {
14705        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14706        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14707        let buffer = display_map.buffer_snapshot();
14708        let mut selections = self.selections.all::<usize>(&display_map);
14709        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14710            let query = &select_prev_state.query;
14711            if !select_prev_state.done {
14712                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14713                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14714                let mut next_selected_range = None;
14715                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14716                let bytes_before_last_selection =
14717                    buffer.reversed_bytes_in_range(0..last_selection.start);
14718                let bytes_after_first_selection =
14719                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14720                let query_matches = query
14721                    .stream_find_iter(bytes_before_last_selection)
14722                    .map(|result| (last_selection.start, result))
14723                    .chain(
14724                        query
14725                            .stream_find_iter(bytes_after_first_selection)
14726                            .map(|result| (buffer.len(), result)),
14727                    );
14728                for (end_offset, query_match) in query_matches {
14729                    let query_match = query_match.unwrap(); // can only fail due to I/O
14730                    let offset_range =
14731                        end_offset - query_match.end()..end_offset - query_match.start();
14732
14733                    if !select_prev_state.wordwise
14734                        || (!buffer.is_inside_word(offset_range.start, None)
14735                            && !buffer.is_inside_word(offset_range.end, None))
14736                    {
14737                        next_selected_range = Some(offset_range);
14738                        break;
14739                    }
14740                }
14741
14742                if let Some(next_selected_range) = next_selected_range {
14743                    self.select_match_ranges(
14744                        next_selected_range,
14745                        last_selection.reversed,
14746                        action.replace_newest,
14747                        Some(Autoscroll::newest()),
14748                        window,
14749                        cx,
14750                    );
14751                } else {
14752                    select_prev_state.done = true;
14753                }
14754            }
14755
14756            self.select_prev_state = Some(select_prev_state);
14757        } else {
14758            let mut only_carets = true;
14759            let mut same_text_selected = true;
14760            let mut selected_text = None;
14761
14762            let mut selections_iter = selections.iter().peekable();
14763            while let Some(selection) = selections_iter.next() {
14764                if selection.start != selection.end {
14765                    only_carets = false;
14766                }
14767
14768                if same_text_selected {
14769                    if selected_text.is_none() {
14770                        selected_text =
14771                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14772                    }
14773
14774                    if let Some(next_selection) = selections_iter.peek() {
14775                        if next_selection.range().len() == selection.range().len() {
14776                            let next_selected_text = buffer
14777                                .text_for_range(next_selection.range())
14778                                .collect::<String>();
14779                            if Some(next_selected_text) != selected_text {
14780                                same_text_selected = false;
14781                                selected_text = None;
14782                            }
14783                        } else {
14784                            same_text_selected = false;
14785                            selected_text = None;
14786                        }
14787                    }
14788                }
14789            }
14790
14791            if only_carets {
14792                for selection in &mut selections {
14793                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14794                    selection.start = word_range.start;
14795                    selection.end = word_range.end;
14796                    selection.goal = SelectionGoal::None;
14797                    selection.reversed = false;
14798                    self.select_match_ranges(
14799                        selection.start..selection.end,
14800                        selection.reversed,
14801                        action.replace_newest,
14802                        Some(Autoscroll::newest()),
14803                        window,
14804                        cx,
14805                    );
14806                }
14807                if selections.len() == 1 {
14808                    let selection = selections
14809                        .last()
14810                        .expect("ensured that there's only one selection");
14811                    let query = buffer
14812                        .text_for_range(selection.start..selection.end)
14813                        .collect::<String>();
14814                    let is_empty = query.is_empty();
14815                    let select_state = SelectNextState {
14816                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14817                        wordwise: true,
14818                        done: is_empty,
14819                    };
14820                    self.select_prev_state = Some(select_state);
14821                } else {
14822                    self.select_prev_state = None;
14823                }
14824            } else if let Some(selected_text) = selected_text {
14825                self.select_prev_state = Some(SelectNextState {
14826                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14827                    wordwise: false,
14828                    done: false,
14829                });
14830                self.select_previous(action, window, cx)?;
14831            }
14832        }
14833        Ok(())
14834    }
14835
14836    pub fn find_next_match(
14837        &mut self,
14838        _: &FindNextMatch,
14839        window: &mut Window,
14840        cx: &mut Context<Self>,
14841    ) -> Result<()> {
14842        let selections = self.selections.disjoint_anchors_arc();
14843        match selections.first() {
14844            Some(first) if selections.len() >= 2 => {
14845                self.change_selections(Default::default(), window, cx, |s| {
14846                    s.select_ranges([first.range()]);
14847                });
14848            }
14849            _ => self.select_next(
14850                &SelectNext {
14851                    replace_newest: true,
14852                },
14853                window,
14854                cx,
14855            )?,
14856        }
14857        Ok(())
14858    }
14859
14860    pub fn find_previous_match(
14861        &mut self,
14862        _: &FindPreviousMatch,
14863        window: &mut Window,
14864        cx: &mut Context<Self>,
14865    ) -> Result<()> {
14866        let selections = self.selections.disjoint_anchors_arc();
14867        match selections.last() {
14868            Some(last) if selections.len() >= 2 => {
14869                self.change_selections(Default::default(), window, cx, |s| {
14870                    s.select_ranges([last.range()]);
14871                });
14872            }
14873            _ => self.select_previous(
14874                &SelectPrevious {
14875                    replace_newest: true,
14876                },
14877                window,
14878                cx,
14879            )?,
14880        }
14881        Ok(())
14882    }
14883
14884    pub fn toggle_comments(
14885        &mut self,
14886        action: &ToggleComments,
14887        window: &mut Window,
14888        cx: &mut Context<Self>,
14889    ) {
14890        if self.read_only(cx) {
14891            return;
14892        }
14893        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14894        let text_layout_details = &self.text_layout_details(window);
14895        self.transact(window, cx, |this, window, cx| {
14896            let mut selections = this
14897                .selections
14898                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
14899            let mut edits = Vec::new();
14900            let mut selection_edit_ranges = Vec::new();
14901            let mut last_toggled_row = None;
14902            let snapshot = this.buffer.read(cx).read(cx);
14903            let empty_str: Arc<str> = Arc::default();
14904            let mut suffixes_inserted = Vec::new();
14905            let ignore_indent = action.ignore_indent;
14906
14907            fn comment_prefix_range(
14908                snapshot: &MultiBufferSnapshot,
14909                row: MultiBufferRow,
14910                comment_prefix: &str,
14911                comment_prefix_whitespace: &str,
14912                ignore_indent: bool,
14913            ) -> Range<Point> {
14914                let indent_size = if ignore_indent {
14915                    0
14916                } else {
14917                    snapshot.indent_size_for_line(row).len
14918                };
14919
14920                let start = Point::new(row.0, indent_size);
14921
14922                let mut line_bytes = snapshot
14923                    .bytes_in_range(start..snapshot.max_point())
14924                    .flatten()
14925                    .copied();
14926
14927                // If this line currently begins with the line comment prefix, then record
14928                // the range containing the prefix.
14929                if line_bytes
14930                    .by_ref()
14931                    .take(comment_prefix.len())
14932                    .eq(comment_prefix.bytes())
14933                {
14934                    // Include any whitespace that matches the comment prefix.
14935                    let matching_whitespace_len = line_bytes
14936                        .zip(comment_prefix_whitespace.bytes())
14937                        .take_while(|(a, b)| a == b)
14938                        .count() as u32;
14939                    let end = Point::new(
14940                        start.row,
14941                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14942                    );
14943                    start..end
14944                } else {
14945                    start..start
14946                }
14947            }
14948
14949            fn comment_suffix_range(
14950                snapshot: &MultiBufferSnapshot,
14951                row: MultiBufferRow,
14952                comment_suffix: &str,
14953                comment_suffix_has_leading_space: bool,
14954            ) -> Range<Point> {
14955                let end = Point::new(row.0, snapshot.line_len(row));
14956                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14957
14958                let mut line_end_bytes = snapshot
14959                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14960                    .flatten()
14961                    .copied();
14962
14963                let leading_space_len = if suffix_start_column > 0
14964                    && line_end_bytes.next() == Some(b' ')
14965                    && comment_suffix_has_leading_space
14966                {
14967                    1
14968                } else {
14969                    0
14970                };
14971
14972                // If this line currently begins with the line comment prefix, then record
14973                // the range containing the prefix.
14974                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14975                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14976                    start..end
14977                } else {
14978                    end..end
14979                }
14980            }
14981
14982            // TODO: Handle selections that cross excerpts
14983            for selection in &mut selections {
14984                let start_column = snapshot
14985                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14986                    .len;
14987                let language = if let Some(language) =
14988                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14989                {
14990                    language
14991                } else {
14992                    continue;
14993                };
14994
14995                selection_edit_ranges.clear();
14996
14997                // If multiple selections contain a given row, avoid processing that
14998                // row more than once.
14999                let mut start_row = MultiBufferRow(selection.start.row);
15000                if last_toggled_row == Some(start_row) {
15001                    start_row = start_row.next_row();
15002                }
15003                let end_row =
15004                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15005                        MultiBufferRow(selection.end.row - 1)
15006                    } else {
15007                        MultiBufferRow(selection.end.row)
15008                    };
15009                last_toggled_row = Some(end_row);
15010
15011                if start_row > end_row {
15012                    continue;
15013                }
15014
15015                // If the language has line comments, toggle those.
15016                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15017
15018                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15019                if ignore_indent {
15020                    full_comment_prefixes = full_comment_prefixes
15021                        .into_iter()
15022                        .map(|s| Arc::from(s.trim_end()))
15023                        .collect();
15024                }
15025
15026                if !full_comment_prefixes.is_empty() {
15027                    let first_prefix = full_comment_prefixes
15028                        .first()
15029                        .expect("prefixes is non-empty");
15030                    let prefix_trimmed_lengths = full_comment_prefixes
15031                        .iter()
15032                        .map(|p| p.trim_end_matches(' ').len())
15033                        .collect::<SmallVec<[usize; 4]>>();
15034
15035                    let mut all_selection_lines_are_comments = true;
15036
15037                    for row in start_row.0..=end_row.0 {
15038                        let row = MultiBufferRow(row);
15039                        if start_row < end_row && snapshot.is_line_blank(row) {
15040                            continue;
15041                        }
15042
15043                        let prefix_range = full_comment_prefixes
15044                            .iter()
15045                            .zip(prefix_trimmed_lengths.iter().copied())
15046                            .map(|(prefix, trimmed_prefix_len)| {
15047                                comment_prefix_range(
15048                                    snapshot.deref(),
15049                                    row,
15050                                    &prefix[..trimmed_prefix_len],
15051                                    &prefix[trimmed_prefix_len..],
15052                                    ignore_indent,
15053                                )
15054                            })
15055                            .max_by_key(|range| range.end.column - range.start.column)
15056                            .expect("prefixes is non-empty");
15057
15058                        if prefix_range.is_empty() {
15059                            all_selection_lines_are_comments = false;
15060                        }
15061
15062                        selection_edit_ranges.push(prefix_range);
15063                    }
15064
15065                    if all_selection_lines_are_comments {
15066                        edits.extend(
15067                            selection_edit_ranges
15068                                .iter()
15069                                .cloned()
15070                                .map(|range| (range, empty_str.clone())),
15071                        );
15072                    } else {
15073                        let min_column = selection_edit_ranges
15074                            .iter()
15075                            .map(|range| range.start.column)
15076                            .min()
15077                            .unwrap_or(0);
15078                        edits.extend(selection_edit_ranges.iter().map(|range| {
15079                            let position = Point::new(range.start.row, min_column);
15080                            (position..position, first_prefix.clone())
15081                        }));
15082                    }
15083                } else if let Some(BlockCommentConfig {
15084                    start: full_comment_prefix,
15085                    end: comment_suffix,
15086                    ..
15087                }) = language.block_comment()
15088                {
15089                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15090                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15091                    let prefix_range = comment_prefix_range(
15092                        snapshot.deref(),
15093                        start_row,
15094                        comment_prefix,
15095                        comment_prefix_whitespace,
15096                        ignore_indent,
15097                    );
15098                    let suffix_range = comment_suffix_range(
15099                        snapshot.deref(),
15100                        end_row,
15101                        comment_suffix.trim_start_matches(' '),
15102                        comment_suffix.starts_with(' '),
15103                    );
15104
15105                    if prefix_range.is_empty() || suffix_range.is_empty() {
15106                        edits.push((
15107                            prefix_range.start..prefix_range.start,
15108                            full_comment_prefix.clone(),
15109                        ));
15110                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15111                        suffixes_inserted.push((end_row, comment_suffix.len()));
15112                    } else {
15113                        edits.push((prefix_range, empty_str.clone()));
15114                        edits.push((suffix_range, empty_str.clone()));
15115                    }
15116                } else {
15117                    continue;
15118                }
15119            }
15120
15121            drop(snapshot);
15122            this.buffer.update(cx, |buffer, cx| {
15123                buffer.edit(edits, None, cx);
15124            });
15125
15126            // Adjust selections so that they end before any comment suffixes that
15127            // were inserted.
15128            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15129            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15130            let snapshot = this.buffer.read(cx).read(cx);
15131            for selection in &mut selections {
15132                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15133                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15134                        Ordering::Less => {
15135                            suffixes_inserted.next();
15136                            continue;
15137                        }
15138                        Ordering::Greater => break,
15139                        Ordering::Equal => {
15140                            if selection.end.column == snapshot.line_len(row) {
15141                                if selection.is_empty() {
15142                                    selection.start.column -= suffix_len as u32;
15143                                }
15144                                selection.end.column -= suffix_len as u32;
15145                            }
15146                            break;
15147                        }
15148                    }
15149                }
15150            }
15151
15152            drop(snapshot);
15153            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15154
15155            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15156            let selections_on_single_row = selections.windows(2).all(|selections| {
15157                selections[0].start.row == selections[1].start.row
15158                    && selections[0].end.row == selections[1].end.row
15159                    && selections[0].start.row == selections[0].end.row
15160            });
15161            let selections_selecting = selections
15162                .iter()
15163                .any(|selection| selection.start != selection.end);
15164            let advance_downwards = action.advance_downwards
15165                && selections_on_single_row
15166                && !selections_selecting
15167                && !matches!(this.mode, EditorMode::SingleLine);
15168
15169            if advance_downwards {
15170                let snapshot = this.buffer.read(cx).snapshot(cx);
15171
15172                this.change_selections(Default::default(), window, cx, |s| {
15173                    s.move_cursors_with(|display_snapshot, display_point, _| {
15174                        let mut point = display_point.to_point(display_snapshot);
15175                        point.row += 1;
15176                        point = snapshot.clip_point(point, Bias::Left);
15177                        let display_point = point.to_display_point(display_snapshot);
15178                        let goal = SelectionGoal::HorizontalPosition(
15179                            display_snapshot
15180                                .x_for_display_point(display_point, text_layout_details)
15181                                .into(),
15182                        );
15183                        (display_point, goal)
15184                    })
15185                });
15186            }
15187        });
15188    }
15189
15190    pub fn select_enclosing_symbol(
15191        &mut self,
15192        _: &SelectEnclosingSymbol,
15193        window: &mut Window,
15194        cx: &mut Context<Self>,
15195    ) {
15196        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15197
15198        let buffer = self.buffer.read(cx).snapshot(cx);
15199        let old_selections = self
15200            .selections
15201            .all::<usize>(&self.display_snapshot(cx))
15202            .into_boxed_slice();
15203
15204        fn update_selection(
15205            selection: &Selection<usize>,
15206            buffer_snap: &MultiBufferSnapshot,
15207        ) -> Option<Selection<usize>> {
15208            let cursor = selection.head();
15209            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15210            for symbol in symbols.iter().rev() {
15211                let start = symbol.range.start.to_offset(buffer_snap);
15212                let end = symbol.range.end.to_offset(buffer_snap);
15213                let new_range = start..end;
15214                if start < selection.start || end > selection.end {
15215                    return Some(Selection {
15216                        id: selection.id,
15217                        start: new_range.start,
15218                        end: new_range.end,
15219                        goal: SelectionGoal::None,
15220                        reversed: selection.reversed,
15221                    });
15222                }
15223            }
15224            None
15225        }
15226
15227        let mut selected_larger_symbol = false;
15228        let new_selections = old_selections
15229            .iter()
15230            .map(|selection| match update_selection(selection, &buffer) {
15231                Some(new_selection) => {
15232                    if new_selection.range() != selection.range() {
15233                        selected_larger_symbol = true;
15234                    }
15235                    new_selection
15236                }
15237                None => selection.clone(),
15238            })
15239            .collect::<Vec<_>>();
15240
15241        if selected_larger_symbol {
15242            self.change_selections(Default::default(), window, cx, |s| {
15243                s.select(new_selections);
15244            });
15245        }
15246    }
15247
15248    pub fn select_larger_syntax_node(
15249        &mut self,
15250        _: &SelectLargerSyntaxNode,
15251        window: &mut Window,
15252        cx: &mut Context<Self>,
15253    ) {
15254        let Some(visible_row_count) = self.visible_row_count() else {
15255            return;
15256        };
15257        let old_selections: Box<[_]> = self
15258            .selections
15259            .all::<usize>(&self.display_snapshot(cx))
15260            .into();
15261        if old_selections.is_empty() {
15262            return;
15263        }
15264
15265        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15266
15267        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15268        let buffer = self.buffer.read(cx).snapshot(cx);
15269
15270        let mut selected_larger_node = false;
15271        let mut new_selections = old_selections
15272            .iter()
15273            .map(|selection| {
15274                let old_range = selection.start..selection.end;
15275
15276                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15277                    // manually select word at selection
15278                    if ["string_content", "inline"].contains(&node.kind()) {
15279                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15280                        // ignore if word is already selected
15281                        if !word_range.is_empty() && old_range != word_range {
15282                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15283                            // only select word if start and end point belongs to same word
15284                            if word_range == last_word_range {
15285                                selected_larger_node = true;
15286                                return Selection {
15287                                    id: selection.id,
15288                                    start: word_range.start,
15289                                    end: word_range.end,
15290                                    goal: SelectionGoal::None,
15291                                    reversed: selection.reversed,
15292                                };
15293                            }
15294                        }
15295                    }
15296                }
15297
15298                let mut new_range = old_range.clone();
15299                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15300                    new_range = range;
15301                    if !node.is_named() {
15302                        continue;
15303                    }
15304                    if !display_map.intersects_fold(new_range.start)
15305                        && !display_map.intersects_fold(new_range.end)
15306                    {
15307                        break;
15308                    }
15309                }
15310
15311                selected_larger_node |= new_range != old_range;
15312                Selection {
15313                    id: selection.id,
15314                    start: new_range.start,
15315                    end: new_range.end,
15316                    goal: SelectionGoal::None,
15317                    reversed: selection.reversed,
15318                }
15319            })
15320            .collect::<Vec<_>>();
15321
15322        if !selected_larger_node {
15323            return; // don't put this call in the history
15324        }
15325
15326        // scroll based on transformation done to the last selection created by the user
15327        let (last_old, last_new) = old_selections
15328            .last()
15329            .zip(new_selections.last().cloned())
15330            .expect("old_selections isn't empty");
15331
15332        // revert selection
15333        let is_selection_reversed = {
15334            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15335            new_selections.last_mut().expect("checked above").reversed =
15336                should_newest_selection_be_reversed;
15337            should_newest_selection_be_reversed
15338        };
15339
15340        if selected_larger_node {
15341            self.select_syntax_node_history.disable_clearing = true;
15342            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15343                s.select(new_selections.clone());
15344            });
15345            self.select_syntax_node_history.disable_clearing = false;
15346        }
15347
15348        let start_row = last_new.start.to_display_point(&display_map).row().0;
15349        let end_row = last_new.end.to_display_point(&display_map).row().0;
15350        let selection_height = end_row - start_row + 1;
15351        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15352
15353        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15354        let scroll_behavior = if fits_on_the_screen {
15355            self.request_autoscroll(Autoscroll::fit(), cx);
15356            SelectSyntaxNodeScrollBehavior::FitSelection
15357        } else if is_selection_reversed {
15358            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15359            SelectSyntaxNodeScrollBehavior::CursorTop
15360        } else {
15361            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15362            SelectSyntaxNodeScrollBehavior::CursorBottom
15363        };
15364
15365        self.select_syntax_node_history.push((
15366            old_selections,
15367            scroll_behavior,
15368            is_selection_reversed,
15369        ));
15370    }
15371
15372    pub fn select_smaller_syntax_node(
15373        &mut self,
15374        _: &SelectSmallerSyntaxNode,
15375        window: &mut Window,
15376        cx: &mut Context<Self>,
15377    ) {
15378        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15379
15380        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15381            self.select_syntax_node_history.pop()
15382        {
15383            if let Some(selection) = selections.last_mut() {
15384                selection.reversed = is_selection_reversed;
15385            }
15386
15387            self.select_syntax_node_history.disable_clearing = true;
15388            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15389                s.select(selections.to_vec());
15390            });
15391            self.select_syntax_node_history.disable_clearing = false;
15392
15393            match scroll_behavior {
15394                SelectSyntaxNodeScrollBehavior::CursorTop => {
15395                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15396                }
15397                SelectSyntaxNodeScrollBehavior::FitSelection => {
15398                    self.request_autoscroll(Autoscroll::fit(), cx);
15399                }
15400                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15401                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15402                }
15403            }
15404        }
15405    }
15406
15407    pub fn unwrap_syntax_node(
15408        &mut self,
15409        _: &UnwrapSyntaxNode,
15410        window: &mut Window,
15411        cx: &mut Context<Self>,
15412    ) {
15413        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15414
15415        let buffer = self.buffer.read(cx).snapshot(cx);
15416        let selections = self
15417            .selections
15418            .all::<usize>(&self.display_snapshot(cx))
15419            .into_iter()
15420            // subtracting the offset requires sorting
15421            .sorted_by_key(|i| i.start);
15422
15423        let full_edits = selections
15424            .into_iter()
15425            .filter_map(|selection| {
15426                let child = if selection.is_empty()
15427                    && let Some((_, ancestor_range)) =
15428                        buffer.syntax_ancestor(selection.start..selection.end)
15429                {
15430                    ancestor_range
15431                } else {
15432                    selection.range()
15433                };
15434
15435                let mut parent = child.clone();
15436                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15437                    parent = ancestor_range;
15438                    if parent.start < child.start || parent.end > child.end {
15439                        break;
15440                    }
15441                }
15442
15443                if parent == child {
15444                    return None;
15445                }
15446                let text = buffer.text_for_range(child).collect::<String>();
15447                Some((selection.id, parent, text))
15448            })
15449            .collect::<Vec<_>>();
15450        if full_edits.is_empty() {
15451            return;
15452        }
15453
15454        self.transact(window, cx, |this, window, cx| {
15455            this.buffer.update(cx, |buffer, cx| {
15456                buffer.edit(
15457                    full_edits
15458                        .iter()
15459                        .map(|(_, p, t)| (p.clone(), t.clone()))
15460                        .collect::<Vec<_>>(),
15461                    None,
15462                    cx,
15463                );
15464            });
15465            this.change_selections(Default::default(), window, cx, |s| {
15466                let mut offset = 0;
15467                let mut selections = vec![];
15468                for (id, parent, text) in full_edits {
15469                    let start = parent.start - offset;
15470                    offset += parent.len() - text.len();
15471                    selections.push(Selection {
15472                        id,
15473                        start,
15474                        end: start + text.len(),
15475                        reversed: false,
15476                        goal: Default::default(),
15477                    });
15478                }
15479                s.select(selections);
15480            });
15481        });
15482    }
15483
15484    pub fn select_next_syntax_node(
15485        &mut self,
15486        _: &SelectNextSyntaxNode,
15487        window: &mut Window,
15488        cx: &mut Context<Self>,
15489    ) {
15490        let old_selections: Box<[_]> = self
15491            .selections
15492            .all::<usize>(&self.display_snapshot(cx))
15493            .into();
15494        if old_selections.is_empty() {
15495            return;
15496        }
15497
15498        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15499
15500        let buffer = self.buffer.read(cx).snapshot(cx);
15501        let mut selected_sibling = false;
15502
15503        let new_selections = old_selections
15504            .iter()
15505            .map(|selection| {
15506                let old_range = selection.start..selection.end;
15507
15508                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15509                    let new_range = node.byte_range();
15510                    selected_sibling = true;
15511                    Selection {
15512                        id: selection.id,
15513                        start: new_range.start,
15514                        end: new_range.end,
15515                        goal: SelectionGoal::None,
15516                        reversed: selection.reversed,
15517                    }
15518                } else {
15519                    selection.clone()
15520                }
15521            })
15522            .collect::<Vec<_>>();
15523
15524        if selected_sibling {
15525            self.change_selections(
15526                SelectionEffects::scroll(Autoscroll::fit()),
15527                window,
15528                cx,
15529                |s| {
15530                    s.select(new_selections);
15531                },
15532            );
15533        }
15534    }
15535
15536    pub fn select_prev_syntax_node(
15537        &mut self,
15538        _: &SelectPreviousSyntaxNode,
15539        window: &mut Window,
15540        cx: &mut Context<Self>,
15541    ) {
15542        let old_selections: Box<[_]> = self
15543            .selections
15544            .all::<usize>(&self.display_snapshot(cx))
15545            .into();
15546        if old_selections.is_empty() {
15547            return;
15548        }
15549
15550        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15551
15552        let buffer = self.buffer.read(cx).snapshot(cx);
15553        let mut selected_sibling = false;
15554
15555        let new_selections = old_selections
15556            .iter()
15557            .map(|selection| {
15558                let old_range = selection.start..selection.end;
15559
15560                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15561                    let new_range = node.byte_range();
15562                    selected_sibling = true;
15563                    Selection {
15564                        id: selection.id,
15565                        start: new_range.start,
15566                        end: new_range.end,
15567                        goal: SelectionGoal::None,
15568                        reversed: selection.reversed,
15569                    }
15570                } else {
15571                    selection.clone()
15572                }
15573            })
15574            .collect::<Vec<_>>();
15575
15576        if selected_sibling {
15577            self.change_selections(
15578                SelectionEffects::scroll(Autoscroll::fit()),
15579                window,
15580                cx,
15581                |s| {
15582                    s.select(new_selections);
15583                },
15584            );
15585        }
15586    }
15587
15588    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15589        if !EditorSettings::get_global(cx).gutter.runnables {
15590            self.clear_tasks();
15591            return Task::ready(());
15592        }
15593        let project = self.project().map(Entity::downgrade);
15594        let task_sources = self.lsp_task_sources(cx);
15595        let multi_buffer = self.buffer.downgrade();
15596        cx.spawn_in(window, async move |editor, cx| {
15597            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15598            let Some(project) = project.and_then(|p| p.upgrade()) else {
15599                return;
15600            };
15601            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15602                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15603            }) else {
15604                return;
15605            };
15606
15607            let hide_runnables = project
15608                .update(cx, |project, _| project.is_via_collab())
15609                .unwrap_or(true);
15610            if hide_runnables {
15611                return;
15612            }
15613            let new_rows =
15614                cx.background_spawn({
15615                    let snapshot = display_snapshot.clone();
15616                    async move {
15617                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15618                    }
15619                })
15620                    .await;
15621            let Ok(lsp_tasks) =
15622                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15623            else {
15624                return;
15625            };
15626            let lsp_tasks = lsp_tasks.await;
15627
15628            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15629                lsp_tasks
15630                    .into_iter()
15631                    .flat_map(|(kind, tasks)| {
15632                        tasks.into_iter().filter_map(move |(location, task)| {
15633                            Some((kind.clone(), location?, task))
15634                        })
15635                    })
15636                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15637                        let buffer = location.target.buffer;
15638                        let buffer_snapshot = buffer.read(cx).snapshot();
15639                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15640                            |(excerpt_id, snapshot, _)| {
15641                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15642                                    display_snapshot
15643                                        .buffer_snapshot()
15644                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15645                                } else {
15646                                    None
15647                                }
15648                            },
15649                        );
15650                        if let Some(offset) = offset {
15651                            let task_buffer_range =
15652                                location.target.range.to_point(&buffer_snapshot);
15653                            let context_buffer_range =
15654                                task_buffer_range.to_offset(&buffer_snapshot);
15655                            let context_range = BufferOffset(context_buffer_range.start)
15656                                ..BufferOffset(context_buffer_range.end);
15657
15658                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15659                                .or_insert_with(|| RunnableTasks {
15660                                    templates: Vec::new(),
15661                                    offset,
15662                                    column: task_buffer_range.start.column,
15663                                    extra_variables: HashMap::default(),
15664                                    context_range,
15665                                })
15666                                .templates
15667                                .push((kind, task.original_task().clone()));
15668                        }
15669
15670                        acc
15671                    })
15672            }) else {
15673                return;
15674            };
15675
15676            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15677                buffer.language_settings(cx).tasks.prefer_lsp
15678            }) else {
15679                return;
15680            };
15681
15682            let rows = Self::runnable_rows(
15683                project,
15684                display_snapshot,
15685                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15686                new_rows,
15687                cx.clone(),
15688            )
15689            .await;
15690            editor
15691                .update(cx, |editor, _| {
15692                    editor.clear_tasks();
15693                    for (key, mut value) in rows {
15694                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15695                            value.templates.extend(lsp_tasks.templates);
15696                        }
15697
15698                        editor.insert_tasks(key, value);
15699                    }
15700                    for (key, value) in lsp_tasks_by_rows {
15701                        editor.insert_tasks(key, value);
15702                    }
15703                })
15704                .ok();
15705        })
15706    }
15707    fn fetch_runnable_ranges(
15708        snapshot: &DisplaySnapshot,
15709        range: Range<Anchor>,
15710    ) -> Vec<language::RunnableRange> {
15711        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15712    }
15713
15714    fn runnable_rows(
15715        project: Entity<Project>,
15716        snapshot: DisplaySnapshot,
15717        prefer_lsp: bool,
15718        runnable_ranges: Vec<RunnableRange>,
15719        cx: AsyncWindowContext,
15720    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15721        cx.spawn(async move |cx| {
15722            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15723            for mut runnable in runnable_ranges {
15724                let Some(tasks) = cx
15725                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15726                    .ok()
15727                else {
15728                    continue;
15729                };
15730                let mut tasks = tasks.await;
15731
15732                if prefer_lsp {
15733                    tasks.retain(|(task_kind, _)| {
15734                        !matches!(task_kind, TaskSourceKind::Language { .. })
15735                    });
15736                }
15737                if tasks.is_empty() {
15738                    continue;
15739                }
15740
15741                let point = runnable
15742                    .run_range
15743                    .start
15744                    .to_point(&snapshot.buffer_snapshot());
15745                let Some(row) = snapshot
15746                    .buffer_snapshot()
15747                    .buffer_line_for_row(MultiBufferRow(point.row))
15748                    .map(|(_, range)| range.start.row)
15749                else {
15750                    continue;
15751                };
15752
15753                let context_range =
15754                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15755                runnable_rows.push((
15756                    (runnable.buffer_id, row),
15757                    RunnableTasks {
15758                        templates: tasks,
15759                        offset: snapshot
15760                            .buffer_snapshot()
15761                            .anchor_before(runnable.run_range.start),
15762                        context_range,
15763                        column: point.column,
15764                        extra_variables: runnable.extra_captures,
15765                    },
15766                ));
15767            }
15768            runnable_rows
15769        })
15770    }
15771
15772    fn templates_with_tags(
15773        project: &Entity<Project>,
15774        runnable: &mut Runnable,
15775        cx: &mut App,
15776    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15777        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15778            let (worktree_id, file) = project
15779                .buffer_for_id(runnable.buffer, cx)
15780                .and_then(|buffer| buffer.read(cx).file())
15781                .map(|file| (file.worktree_id(cx), file.clone()))
15782                .unzip();
15783
15784            (
15785                project.task_store().read(cx).task_inventory().cloned(),
15786                worktree_id,
15787                file,
15788            )
15789        });
15790
15791        let tags = mem::take(&mut runnable.tags);
15792        let language = runnable.language.clone();
15793        cx.spawn(async move |cx| {
15794            let mut templates_with_tags = Vec::new();
15795            if let Some(inventory) = inventory {
15796                for RunnableTag(tag) in tags {
15797                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15798                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15799                    }) else {
15800                        return templates_with_tags;
15801                    };
15802                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15803                        move |(_, template)| {
15804                            template.tags.iter().any(|source_tag| source_tag == &tag)
15805                        },
15806                    ));
15807                }
15808            }
15809            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15810
15811            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15812                // Strongest source wins; if we have worktree tag binding, prefer that to
15813                // global and language bindings;
15814                // if we have a global binding, prefer that to language binding.
15815                let first_mismatch = templates_with_tags
15816                    .iter()
15817                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15818                if let Some(index) = first_mismatch {
15819                    templates_with_tags.truncate(index);
15820                }
15821            }
15822
15823            templates_with_tags
15824        })
15825    }
15826
15827    pub fn move_to_enclosing_bracket(
15828        &mut self,
15829        _: &MoveToEnclosingBracket,
15830        window: &mut Window,
15831        cx: &mut Context<Self>,
15832    ) {
15833        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15834        self.change_selections(Default::default(), window, cx, |s| {
15835            s.move_offsets_with(|snapshot, selection| {
15836                let Some(enclosing_bracket_ranges) =
15837                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15838                else {
15839                    return;
15840                };
15841
15842                let mut best_length = usize::MAX;
15843                let mut best_inside = false;
15844                let mut best_in_bracket_range = false;
15845                let mut best_destination = None;
15846                for (open, close) in enclosing_bracket_ranges {
15847                    let close = close.to_inclusive();
15848                    let length = close.end() - open.start;
15849                    let inside = selection.start >= open.end && selection.end <= *close.start();
15850                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15851                        || close.contains(&selection.head());
15852
15853                    // If best is next to a bracket and current isn't, skip
15854                    if !in_bracket_range && best_in_bracket_range {
15855                        continue;
15856                    }
15857
15858                    // Prefer smaller lengths unless best is inside and current isn't
15859                    if length > best_length && (best_inside || !inside) {
15860                        continue;
15861                    }
15862
15863                    best_length = length;
15864                    best_inside = inside;
15865                    best_in_bracket_range = in_bracket_range;
15866                    best_destination = Some(
15867                        if close.contains(&selection.start) && close.contains(&selection.end) {
15868                            if inside { open.end } else { open.start }
15869                        } else if inside {
15870                            *close.start()
15871                        } else {
15872                            *close.end()
15873                        },
15874                    );
15875                }
15876
15877                if let Some(destination) = best_destination {
15878                    selection.collapse_to(destination, SelectionGoal::None);
15879                }
15880            })
15881        });
15882    }
15883
15884    pub fn undo_selection(
15885        &mut self,
15886        _: &UndoSelection,
15887        window: &mut Window,
15888        cx: &mut Context<Self>,
15889    ) {
15890        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15891        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15892            self.selection_history.mode = SelectionHistoryMode::Undoing;
15893            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15894                this.end_selection(window, cx);
15895                this.change_selections(
15896                    SelectionEffects::scroll(Autoscroll::newest()),
15897                    window,
15898                    cx,
15899                    |s| s.select_anchors(entry.selections.to_vec()),
15900                );
15901            });
15902            self.selection_history.mode = SelectionHistoryMode::Normal;
15903
15904            self.select_next_state = entry.select_next_state;
15905            self.select_prev_state = entry.select_prev_state;
15906            self.add_selections_state = entry.add_selections_state;
15907        }
15908    }
15909
15910    pub fn redo_selection(
15911        &mut self,
15912        _: &RedoSelection,
15913        window: &mut Window,
15914        cx: &mut Context<Self>,
15915    ) {
15916        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15917        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15918            self.selection_history.mode = SelectionHistoryMode::Redoing;
15919            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15920                this.end_selection(window, cx);
15921                this.change_selections(
15922                    SelectionEffects::scroll(Autoscroll::newest()),
15923                    window,
15924                    cx,
15925                    |s| s.select_anchors(entry.selections.to_vec()),
15926                );
15927            });
15928            self.selection_history.mode = SelectionHistoryMode::Normal;
15929
15930            self.select_next_state = entry.select_next_state;
15931            self.select_prev_state = entry.select_prev_state;
15932            self.add_selections_state = entry.add_selections_state;
15933        }
15934    }
15935
15936    pub fn expand_excerpts(
15937        &mut self,
15938        action: &ExpandExcerpts,
15939        _: &mut Window,
15940        cx: &mut Context<Self>,
15941    ) {
15942        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15943    }
15944
15945    pub fn expand_excerpts_down(
15946        &mut self,
15947        action: &ExpandExcerptsDown,
15948        _: &mut Window,
15949        cx: &mut Context<Self>,
15950    ) {
15951        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15952    }
15953
15954    pub fn expand_excerpts_up(
15955        &mut self,
15956        action: &ExpandExcerptsUp,
15957        _: &mut Window,
15958        cx: &mut Context<Self>,
15959    ) {
15960        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15961    }
15962
15963    pub fn expand_excerpts_for_direction(
15964        &mut self,
15965        lines: u32,
15966        direction: ExpandExcerptDirection,
15967
15968        cx: &mut Context<Self>,
15969    ) {
15970        let selections = self.selections.disjoint_anchors_arc();
15971
15972        let lines = if lines == 0 {
15973            EditorSettings::get_global(cx).expand_excerpt_lines
15974        } else {
15975            lines
15976        };
15977
15978        self.buffer.update(cx, |buffer, cx| {
15979            let snapshot = buffer.snapshot(cx);
15980            let mut excerpt_ids = selections
15981                .iter()
15982                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15983                .collect::<Vec<_>>();
15984            excerpt_ids.sort();
15985            excerpt_ids.dedup();
15986            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15987        })
15988    }
15989
15990    pub fn expand_excerpt(
15991        &mut self,
15992        excerpt: ExcerptId,
15993        direction: ExpandExcerptDirection,
15994        window: &mut Window,
15995        cx: &mut Context<Self>,
15996    ) {
15997        let current_scroll_position = self.scroll_position(cx);
15998        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15999        let mut scroll = None;
16000
16001        if direction == ExpandExcerptDirection::Down {
16002            let multi_buffer = self.buffer.read(cx);
16003            let snapshot = multi_buffer.snapshot(cx);
16004            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16005                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16006                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16007            {
16008                let buffer_snapshot = buffer.read(cx).snapshot();
16009                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16010                let last_row = buffer_snapshot.max_point().row;
16011                let lines_below = last_row.saturating_sub(excerpt_end_row);
16012                if lines_below >= lines_to_expand {
16013                    scroll = Some(
16014                        current_scroll_position
16015                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
16016                    );
16017                }
16018            }
16019        }
16020        if direction == ExpandExcerptDirection::Up
16021            && self
16022                .buffer
16023                .read(cx)
16024                .snapshot(cx)
16025                .excerpt_before(excerpt)
16026                .is_none()
16027        {
16028            scroll = Some(current_scroll_position);
16029        }
16030
16031        self.buffer.update(cx, |buffer, cx| {
16032            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16033        });
16034
16035        if let Some(new_scroll_position) = scroll {
16036            self.set_scroll_position(new_scroll_position, window, cx);
16037        }
16038    }
16039
16040    pub fn go_to_singleton_buffer_point(
16041        &mut self,
16042        point: Point,
16043        window: &mut Window,
16044        cx: &mut Context<Self>,
16045    ) {
16046        self.go_to_singleton_buffer_range(point..point, window, cx);
16047    }
16048
16049    pub fn go_to_singleton_buffer_range(
16050        &mut self,
16051        range: Range<Point>,
16052        window: &mut Window,
16053        cx: &mut Context<Self>,
16054    ) {
16055        let multibuffer = self.buffer().read(cx);
16056        let Some(buffer) = multibuffer.as_singleton() else {
16057            return;
16058        };
16059        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16060            return;
16061        };
16062        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16063            return;
16064        };
16065        self.change_selections(
16066            SelectionEffects::default().nav_history(true),
16067            window,
16068            cx,
16069            |s| s.select_anchor_ranges([start..end]),
16070        );
16071    }
16072
16073    pub fn go_to_diagnostic(
16074        &mut self,
16075        action: &GoToDiagnostic,
16076        window: &mut Window,
16077        cx: &mut Context<Self>,
16078    ) {
16079        if !self.diagnostics_enabled() {
16080            return;
16081        }
16082        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16083        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16084    }
16085
16086    pub fn go_to_prev_diagnostic(
16087        &mut self,
16088        action: &GoToPreviousDiagnostic,
16089        window: &mut Window,
16090        cx: &mut Context<Self>,
16091    ) {
16092        if !self.diagnostics_enabled() {
16093            return;
16094        }
16095        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16096        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16097    }
16098
16099    pub fn go_to_diagnostic_impl(
16100        &mut self,
16101        direction: Direction,
16102        severity: GoToDiagnosticSeverityFilter,
16103        window: &mut Window,
16104        cx: &mut Context<Self>,
16105    ) {
16106        let buffer = self.buffer.read(cx).snapshot(cx);
16107        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
16108
16109        let mut active_group_id = None;
16110        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16111            && active_group.active_range.start.to_offset(&buffer) == selection.start
16112        {
16113            active_group_id = Some(active_group.group_id);
16114        }
16115
16116        fn filtered<'a>(
16117            severity: GoToDiagnosticSeverityFilter,
16118            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
16119        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
16120            diagnostics
16121                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16122                .filter(|entry| entry.range.start != entry.range.end)
16123                .filter(|entry| !entry.diagnostic.is_unnecessary)
16124        }
16125
16126        let before = filtered(
16127            severity,
16128            buffer
16129                .diagnostics_in_range(0..selection.start)
16130                .filter(|entry| entry.range.start <= selection.start),
16131        );
16132        let after = filtered(
16133            severity,
16134            buffer
16135                .diagnostics_in_range(selection.start..buffer.len())
16136                .filter(|entry| entry.range.start >= selection.start),
16137        );
16138
16139        let mut found: Option<DiagnosticEntryRef<usize>> = None;
16140        if direction == Direction::Prev {
16141            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16142            {
16143                for diagnostic in prev_diagnostics.into_iter().rev() {
16144                    if diagnostic.range.start != selection.start
16145                        || active_group_id
16146                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16147                    {
16148                        found = Some(diagnostic);
16149                        break 'outer;
16150                    }
16151                }
16152            }
16153        } else {
16154            for diagnostic in after.chain(before) {
16155                if diagnostic.range.start != selection.start
16156                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16157                {
16158                    found = Some(diagnostic);
16159                    break;
16160                }
16161            }
16162        }
16163        let Some(next_diagnostic) = found else {
16164            return;
16165        };
16166
16167        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16168        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16169            return;
16170        };
16171        let snapshot = self.snapshot(window, cx);
16172        if snapshot.intersects_fold(next_diagnostic.range.start) {
16173            self.unfold_ranges(
16174                std::slice::from_ref(&next_diagnostic.range),
16175                true,
16176                false,
16177                cx,
16178            );
16179        }
16180        self.change_selections(Default::default(), window, cx, |s| {
16181            s.select_ranges(vec![
16182                next_diagnostic.range.start..next_diagnostic.range.start,
16183            ])
16184        });
16185        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16186        self.refresh_edit_prediction(false, true, window, cx);
16187    }
16188
16189    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16190        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16191        let snapshot = self.snapshot(window, cx);
16192        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16193        self.go_to_hunk_before_or_after_position(
16194            &snapshot,
16195            selection.head(),
16196            Direction::Next,
16197            window,
16198            cx,
16199        );
16200    }
16201
16202    pub fn go_to_hunk_before_or_after_position(
16203        &mut self,
16204        snapshot: &EditorSnapshot,
16205        position: Point,
16206        direction: Direction,
16207        window: &mut Window,
16208        cx: &mut Context<Editor>,
16209    ) {
16210        let row = if direction == Direction::Next {
16211            self.hunk_after_position(snapshot, position)
16212                .map(|hunk| hunk.row_range.start)
16213        } else {
16214            self.hunk_before_position(snapshot, position)
16215        };
16216
16217        if let Some(row) = row {
16218            let destination = Point::new(row.0, 0);
16219            let autoscroll = Autoscroll::center();
16220
16221            self.unfold_ranges(&[destination..destination], false, false, cx);
16222            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16223                s.select_ranges([destination..destination]);
16224            });
16225        }
16226    }
16227
16228    fn hunk_after_position(
16229        &mut self,
16230        snapshot: &EditorSnapshot,
16231        position: Point,
16232    ) -> Option<MultiBufferDiffHunk> {
16233        snapshot
16234            .buffer_snapshot()
16235            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16236            .find(|hunk| hunk.row_range.start.0 > position.row)
16237            .or_else(|| {
16238                snapshot
16239                    .buffer_snapshot()
16240                    .diff_hunks_in_range(Point::zero()..position)
16241                    .find(|hunk| hunk.row_range.end.0 < position.row)
16242            })
16243    }
16244
16245    fn go_to_prev_hunk(
16246        &mut self,
16247        _: &GoToPreviousHunk,
16248        window: &mut Window,
16249        cx: &mut Context<Self>,
16250    ) {
16251        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16252        let snapshot = self.snapshot(window, cx);
16253        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16254        self.go_to_hunk_before_or_after_position(
16255            &snapshot,
16256            selection.head(),
16257            Direction::Prev,
16258            window,
16259            cx,
16260        );
16261    }
16262
16263    fn hunk_before_position(
16264        &mut self,
16265        snapshot: &EditorSnapshot,
16266        position: Point,
16267    ) -> Option<MultiBufferRow> {
16268        snapshot
16269            .buffer_snapshot()
16270            .diff_hunk_before(position)
16271            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16272    }
16273
16274    fn go_to_next_change(
16275        &mut self,
16276        _: &GoToNextChange,
16277        window: &mut Window,
16278        cx: &mut Context<Self>,
16279    ) {
16280        if let Some(selections) = self
16281            .change_list
16282            .next_change(1, Direction::Next)
16283            .map(|s| s.to_vec())
16284        {
16285            self.change_selections(Default::default(), window, cx, |s| {
16286                let map = s.display_snapshot();
16287                s.select_display_ranges(selections.iter().map(|a| {
16288                    let point = a.to_display_point(&map);
16289                    point..point
16290                }))
16291            })
16292        }
16293    }
16294
16295    fn go_to_previous_change(
16296        &mut self,
16297        _: &GoToPreviousChange,
16298        window: &mut Window,
16299        cx: &mut Context<Self>,
16300    ) {
16301        if let Some(selections) = self
16302            .change_list
16303            .next_change(1, Direction::Prev)
16304            .map(|s| s.to_vec())
16305        {
16306            self.change_selections(Default::default(), window, cx, |s| {
16307                let map = s.display_snapshot();
16308                s.select_display_ranges(selections.iter().map(|a| {
16309                    let point = a.to_display_point(&map);
16310                    point..point
16311                }))
16312            })
16313        }
16314    }
16315
16316    pub fn go_to_next_document_highlight(
16317        &mut self,
16318        _: &GoToNextDocumentHighlight,
16319        window: &mut Window,
16320        cx: &mut Context<Self>,
16321    ) {
16322        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16323    }
16324
16325    pub fn go_to_prev_document_highlight(
16326        &mut self,
16327        _: &GoToPreviousDocumentHighlight,
16328        window: &mut Window,
16329        cx: &mut Context<Self>,
16330    ) {
16331        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16332    }
16333
16334    pub fn go_to_document_highlight_before_or_after_position(
16335        &mut self,
16336        direction: Direction,
16337        window: &mut Window,
16338        cx: &mut Context<Editor>,
16339    ) {
16340        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16341        let snapshot = self.snapshot(window, cx);
16342        let buffer = &snapshot.buffer_snapshot();
16343        let position = self
16344            .selections
16345            .newest::<Point>(&snapshot.display_snapshot)
16346            .head();
16347        let anchor_position = buffer.anchor_after(position);
16348
16349        // Get all document highlights (both read and write)
16350        let mut all_highlights = Vec::new();
16351
16352        if let Some((_, read_highlights)) = self
16353            .background_highlights
16354            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16355        {
16356            all_highlights.extend(read_highlights.iter());
16357        }
16358
16359        if let Some((_, write_highlights)) = self
16360            .background_highlights
16361            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16362        {
16363            all_highlights.extend(write_highlights.iter());
16364        }
16365
16366        if all_highlights.is_empty() {
16367            return;
16368        }
16369
16370        // Sort highlights by position
16371        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16372
16373        let target_highlight = match direction {
16374            Direction::Next => {
16375                // Find the first highlight after the current position
16376                all_highlights
16377                    .iter()
16378                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16379            }
16380            Direction::Prev => {
16381                // Find the last highlight before the current position
16382                all_highlights
16383                    .iter()
16384                    .rev()
16385                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16386            }
16387        };
16388
16389        if let Some(highlight) = target_highlight {
16390            let destination = highlight.start.to_point(buffer);
16391            let autoscroll = Autoscroll::center();
16392
16393            self.unfold_ranges(&[destination..destination], false, false, cx);
16394            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16395                s.select_ranges([destination..destination]);
16396            });
16397        }
16398    }
16399
16400    fn go_to_line<T: 'static>(
16401        &mut self,
16402        position: Anchor,
16403        highlight_color: Option<Hsla>,
16404        window: &mut Window,
16405        cx: &mut Context<Self>,
16406    ) {
16407        let snapshot = self.snapshot(window, cx).display_snapshot;
16408        let position = position.to_point(&snapshot.buffer_snapshot());
16409        let start = snapshot
16410            .buffer_snapshot()
16411            .clip_point(Point::new(position.row, 0), Bias::Left);
16412        let end = start + Point::new(1, 0);
16413        let start = snapshot.buffer_snapshot().anchor_before(start);
16414        let end = snapshot.buffer_snapshot().anchor_before(end);
16415
16416        self.highlight_rows::<T>(
16417            start..end,
16418            highlight_color
16419                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16420            Default::default(),
16421            cx,
16422        );
16423
16424        if self.buffer.read(cx).is_singleton() {
16425            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16426        }
16427    }
16428
16429    pub fn go_to_definition(
16430        &mut self,
16431        _: &GoToDefinition,
16432        window: &mut Window,
16433        cx: &mut Context<Self>,
16434    ) -> Task<Result<Navigated>> {
16435        let definition =
16436            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16437        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16438        cx.spawn_in(window, async move |editor, cx| {
16439            if definition.await? == Navigated::Yes {
16440                return Ok(Navigated::Yes);
16441            }
16442            match fallback_strategy {
16443                GoToDefinitionFallback::None => Ok(Navigated::No),
16444                GoToDefinitionFallback::FindAllReferences => {
16445                    match editor.update_in(cx, |editor, window, cx| {
16446                        editor.find_all_references(&FindAllReferences, window, cx)
16447                    })? {
16448                        Some(references) => references.await,
16449                        None => Ok(Navigated::No),
16450                    }
16451                }
16452            }
16453        })
16454    }
16455
16456    pub fn go_to_declaration(
16457        &mut self,
16458        _: &GoToDeclaration,
16459        window: &mut Window,
16460        cx: &mut Context<Self>,
16461    ) -> Task<Result<Navigated>> {
16462        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16463    }
16464
16465    pub fn go_to_declaration_split(
16466        &mut self,
16467        _: &GoToDeclaration,
16468        window: &mut Window,
16469        cx: &mut Context<Self>,
16470    ) -> Task<Result<Navigated>> {
16471        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16472    }
16473
16474    pub fn go_to_implementation(
16475        &mut self,
16476        _: &GoToImplementation,
16477        window: &mut Window,
16478        cx: &mut Context<Self>,
16479    ) -> Task<Result<Navigated>> {
16480        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16481    }
16482
16483    pub fn go_to_implementation_split(
16484        &mut self,
16485        _: &GoToImplementationSplit,
16486        window: &mut Window,
16487        cx: &mut Context<Self>,
16488    ) -> Task<Result<Navigated>> {
16489        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16490    }
16491
16492    pub fn go_to_type_definition(
16493        &mut self,
16494        _: &GoToTypeDefinition,
16495        window: &mut Window,
16496        cx: &mut Context<Self>,
16497    ) -> Task<Result<Navigated>> {
16498        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16499    }
16500
16501    pub fn go_to_definition_split(
16502        &mut self,
16503        _: &GoToDefinitionSplit,
16504        window: &mut Window,
16505        cx: &mut Context<Self>,
16506    ) -> Task<Result<Navigated>> {
16507        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16508    }
16509
16510    pub fn go_to_type_definition_split(
16511        &mut self,
16512        _: &GoToTypeDefinitionSplit,
16513        window: &mut Window,
16514        cx: &mut Context<Self>,
16515    ) -> Task<Result<Navigated>> {
16516        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16517    }
16518
16519    fn go_to_definition_of_kind(
16520        &mut self,
16521        kind: GotoDefinitionKind,
16522        split: bool,
16523        window: &mut Window,
16524        cx: &mut Context<Self>,
16525    ) -> Task<Result<Navigated>> {
16526        let Some(provider) = self.semantics_provider.clone() else {
16527            return Task::ready(Ok(Navigated::No));
16528        };
16529        let head = self
16530            .selections
16531            .newest::<usize>(&self.display_snapshot(cx))
16532            .head();
16533        let buffer = self.buffer.read(cx);
16534        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16535            return Task::ready(Ok(Navigated::No));
16536        };
16537        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16538            return Task::ready(Ok(Navigated::No));
16539        };
16540
16541        cx.spawn_in(window, async move |editor, cx| {
16542            let Some(definitions) = definitions.await? else {
16543                return Ok(Navigated::No);
16544            };
16545            let navigated = editor
16546                .update_in(cx, |editor, window, cx| {
16547                    editor.navigate_to_hover_links(
16548                        Some(kind),
16549                        definitions
16550                            .into_iter()
16551                            .filter(|location| {
16552                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16553                            })
16554                            .map(HoverLink::Text)
16555                            .collect::<Vec<_>>(),
16556                        split,
16557                        window,
16558                        cx,
16559                    )
16560                })?
16561                .await?;
16562            anyhow::Ok(navigated)
16563        })
16564    }
16565
16566    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16567        let selection = self.selections.newest_anchor();
16568        let head = selection.head();
16569        let tail = selection.tail();
16570
16571        let Some((buffer, start_position)) =
16572            self.buffer.read(cx).text_anchor_for_position(head, cx)
16573        else {
16574            return;
16575        };
16576
16577        let end_position = if head != tail {
16578            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16579                return;
16580            };
16581            Some(pos)
16582        } else {
16583            None
16584        };
16585
16586        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16587            let url = if let Some(end_pos) = end_position {
16588                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16589            } else {
16590                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16591            };
16592
16593            if let Some(url) = url {
16594                cx.update(|window, cx| {
16595                    if parse_zed_link(&url, cx).is_some() {
16596                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16597                    } else {
16598                        cx.open_url(&url);
16599                    }
16600                })?;
16601            }
16602
16603            anyhow::Ok(())
16604        });
16605
16606        url_finder.detach();
16607    }
16608
16609    pub fn open_selected_filename(
16610        &mut self,
16611        _: &OpenSelectedFilename,
16612        window: &mut Window,
16613        cx: &mut Context<Self>,
16614    ) {
16615        let Some(workspace) = self.workspace() else {
16616            return;
16617        };
16618
16619        let position = self.selections.newest_anchor().head();
16620
16621        let Some((buffer, buffer_position)) =
16622            self.buffer.read(cx).text_anchor_for_position(position, cx)
16623        else {
16624            return;
16625        };
16626
16627        let project = self.project.clone();
16628
16629        cx.spawn_in(window, async move |_, cx| {
16630            let result = find_file(&buffer, project, buffer_position, cx).await;
16631
16632            if let Some((_, path)) = result {
16633                workspace
16634                    .update_in(cx, |workspace, window, cx| {
16635                        workspace.open_resolved_path(path, window, cx)
16636                    })?
16637                    .await?;
16638            }
16639            anyhow::Ok(())
16640        })
16641        .detach();
16642    }
16643
16644    pub(crate) fn navigate_to_hover_links(
16645        &mut self,
16646        kind: Option<GotoDefinitionKind>,
16647        definitions: Vec<HoverLink>,
16648        split: bool,
16649        window: &mut Window,
16650        cx: &mut Context<Editor>,
16651    ) -> Task<Result<Navigated>> {
16652        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16653        let mut first_url_or_file = None;
16654        let definitions: Vec<_> = definitions
16655            .into_iter()
16656            .filter_map(|def| match def {
16657                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16658                HoverLink::InlayHint(lsp_location, server_id) => {
16659                    let computation =
16660                        self.compute_target_location(lsp_location, server_id, window, cx);
16661                    Some(cx.background_spawn(computation))
16662                }
16663                HoverLink::Url(url) => {
16664                    first_url_or_file = Some(Either::Left(url));
16665                    None
16666                }
16667                HoverLink::File(path) => {
16668                    first_url_or_file = Some(Either::Right(path));
16669                    None
16670                }
16671            })
16672            .collect();
16673
16674        let workspace = self.workspace();
16675
16676        cx.spawn_in(window, async move |editor, cx| {
16677            let locations: Vec<Location> = future::join_all(definitions)
16678                .await
16679                .into_iter()
16680                .filter_map(|location| location.transpose())
16681                .collect::<Result<_>>()
16682                .context("location tasks")?;
16683            let mut locations = cx.update(|_, cx| {
16684                locations
16685                    .into_iter()
16686                    .map(|location| {
16687                        let buffer = location.buffer.read(cx);
16688                        (location.buffer, location.range.to_point(buffer))
16689                    })
16690                    .into_group_map()
16691            })?;
16692            let mut num_locations = 0;
16693            for ranges in locations.values_mut() {
16694                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16695                ranges.dedup();
16696                num_locations += ranges.len();
16697            }
16698
16699            if num_locations > 1 {
16700                let Some(workspace) = workspace else {
16701                    return Ok(Navigated::No);
16702                };
16703
16704                let tab_kind = match kind {
16705                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16706                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16707                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16708                    Some(GotoDefinitionKind::Type) => "Types",
16709                };
16710                let title = editor
16711                    .update_in(cx, |_, _, cx| {
16712                        let target = locations
16713                            .iter()
16714                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16715                            .map(|(buffer, location)| {
16716                                buffer
16717                                    .read(cx)
16718                                    .text_for_range(location.clone())
16719                                    .collect::<String>()
16720                            })
16721                            .filter(|text| !text.contains('\n'))
16722                            .unique()
16723                            .take(3)
16724                            .join(", ");
16725                        if target.is_empty() {
16726                            tab_kind.to_owned()
16727                        } else {
16728                            format!("{tab_kind} for {target}")
16729                        }
16730                    })
16731                    .context("buffer title")?;
16732
16733                let opened = workspace
16734                    .update_in(cx, |workspace, window, cx| {
16735                        Self::open_locations_in_multibuffer(
16736                            workspace,
16737                            locations,
16738                            title,
16739                            split,
16740                            MultibufferSelectionMode::First,
16741                            window,
16742                            cx,
16743                        )
16744                    })
16745                    .is_ok();
16746
16747                anyhow::Ok(Navigated::from_bool(opened))
16748            } else if num_locations == 0 {
16749                // If there is one url or file, open it directly
16750                match first_url_or_file {
16751                    Some(Either::Left(url)) => {
16752                        cx.update(|_, cx| cx.open_url(&url))?;
16753                        Ok(Navigated::Yes)
16754                    }
16755                    Some(Either::Right(path)) => {
16756                        let Some(workspace) = workspace else {
16757                            return Ok(Navigated::No);
16758                        };
16759
16760                        workspace
16761                            .update_in(cx, |workspace, window, cx| {
16762                                workspace.open_resolved_path(path, window, cx)
16763                            })?
16764                            .await?;
16765                        Ok(Navigated::Yes)
16766                    }
16767                    None => Ok(Navigated::No),
16768                }
16769            } else {
16770                let Some(workspace) = workspace else {
16771                    return Ok(Navigated::No);
16772                };
16773
16774                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16775                let target_range = target_ranges.first().unwrap().clone();
16776
16777                editor.update_in(cx, |editor, window, cx| {
16778                    let range = target_range.to_point(target_buffer.read(cx));
16779                    let range = editor.range_for_match(&range, false);
16780                    let range = collapse_multiline_range(range);
16781
16782                    if !split
16783                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16784                    {
16785                        editor.go_to_singleton_buffer_range(range, window, cx);
16786                    } else {
16787                        let pane = workspace.read(cx).active_pane().clone();
16788                        window.defer(cx, move |window, cx| {
16789                            let target_editor: Entity<Self> =
16790                                workspace.update(cx, |workspace, cx| {
16791                                    let pane = if split {
16792                                        workspace.adjacent_pane(window, cx)
16793                                    } else {
16794                                        workspace.active_pane().clone()
16795                                    };
16796
16797                                    workspace.open_project_item(
16798                                        pane,
16799                                        target_buffer.clone(),
16800                                        true,
16801                                        true,
16802                                        window,
16803                                        cx,
16804                                    )
16805                                });
16806                            target_editor.update(cx, |target_editor, cx| {
16807                                // When selecting a definition in a different buffer, disable the nav history
16808                                // to avoid creating a history entry at the previous cursor location.
16809                                pane.update(cx, |pane, _| pane.disable_history());
16810                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16811                                pane.update(cx, |pane, _| pane.enable_history());
16812                            });
16813                        });
16814                    }
16815                    Navigated::Yes
16816                })
16817            }
16818        })
16819    }
16820
16821    fn compute_target_location(
16822        &self,
16823        lsp_location: lsp::Location,
16824        server_id: LanguageServerId,
16825        window: &mut Window,
16826        cx: &mut Context<Self>,
16827    ) -> Task<anyhow::Result<Option<Location>>> {
16828        let Some(project) = self.project.clone() else {
16829            return Task::ready(Ok(None));
16830        };
16831
16832        cx.spawn_in(window, async move |editor, cx| {
16833            let location_task = editor.update(cx, |_, cx| {
16834                project.update(cx, |project, cx| {
16835                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16836                })
16837            })?;
16838            let location = Some({
16839                let target_buffer_handle = location_task.await.context("open local buffer")?;
16840                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16841                    let target_start = target_buffer
16842                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16843                    let target_end = target_buffer
16844                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16845                    target_buffer.anchor_after(target_start)
16846                        ..target_buffer.anchor_before(target_end)
16847                })?;
16848                Location {
16849                    buffer: target_buffer_handle,
16850                    range,
16851                }
16852            });
16853            Ok(location)
16854        })
16855    }
16856
16857    fn go_to_next_reference(
16858        &mut self,
16859        _: &GoToNextReference,
16860        window: &mut Window,
16861        cx: &mut Context<Self>,
16862    ) {
16863        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
16864        if let Some(task) = task {
16865            task.detach();
16866        };
16867    }
16868
16869    fn go_to_prev_reference(
16870        &mut self,
16871        _: &GoToPreviousReference,
16872        window: &mut Window,
16873        cx: &mut Context<Self>,
16874    ) {
16875        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
16876        if let Some(task) = task {
16877            task.detach();
16878        };
16879    }
16880
16881    pub fn go_to_reference_before_or_after_position(
16882        &mut self,
16883        direction: Direction,
16884        count: usize,
16885        window: &mut Window,
16886        cx: &mut Context<Self>,
16887    ) -> Option<Task<Result<()>>> {
16888        let selection = self.selections.newest_anchor();
16889        let head = selection.head();
16890
16891        let multi_buffer = self.buffer.read(cx);
16892
16893        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
16894        let workspace = self.workspace()?;
16895        let project = workspace.read(cx).project().clone();
16896        let references =
16897            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
16898        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
16899            let Some(locations) = references.await? else {
16900                return Ok(());
16901            };
16902
16903            if locations.is_empty() {
16904                // totally normal - the cursor may be on something which is not
16905                // a symbol (e.g. a keyword)
16906                log::info!("no references found under cursor");
16907                return Ok(());
16908            }
16909
16910            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
16911
16912            let multi_buffer_snapshot =
16913                multi_buffer.read_with(cx, |multi_buffer, cx| multi_buffer.snapshot(cx))?;
16914
16915            let (locations, current_location_index) =
16916                multi_buffer.update(cx, |multi_buffer, cx| {
16917                    let mut locations = locations
16918                        .into_iter()
16919                        .filter_map(|loc| {
16920                            let start = multi_buffer.buffer_anchor_to_anchor(
16921                                &loc.buffer,
16922                                loc.range.start,
16923                                cx,
16924                            )?;
16925                            let end = multi_buffer.buffer_anchor_to_anchor(
16926                                &loc.buffer,
16927                                loc.range.end,
16928                                cx,
16929                            )?;
16930                            Some(start..end)
16931                        })
16932                        .collect::<Vec<_>>();
16933
16934                    // There is an O(n) implementation, but given this list will be
16935                    // small (usually <100 items), the extra O(log(n)) factor isn't
16936                    // worth the (surprisingly large amount of) extra complexity.
16937                    locations
16938                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
16939
16940                    let head_offset = head.to_offset(&multi_buffer_snapshot);
16941
16942                    let current_location_index = locations.iter().position(|loc| {
16943                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
16944                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
16945                    });
16946
16947                    (locations, current_location_index)
16948                })?;
16949
16950            let Some(current_location_index) = current_location_index else {
16951                // This indicates something has gone wrong, because we already
16952                // handle the "no references" case above
16953                log::error!(
16954                    "failed to find current reference under cursor. Total references: {}",
16955                    locations.len()
16956                );
16957                return Ok(());
16958            };
16959
16960            let destination_location_index = match direction {
16961                Direction::Next => (current_location_index + count) % locations.len(),
16962                Direction::Prev => {
16963                    (current_location_index + locations.len() - count % locations.len())
16964                        % locations.len()
16965                }
16966            };
16967
16968            // TODO(cameron): is this needed?
16969            // the thinking is to avoid "jumping to the current location" (avoid
16970            // polluting "jumplist" in vim terms)
16971            if current_location_index == destination_location_index {
16972                return Ok(());
16973            }
16974
16975            let Range { start, end } = locations[destination_location_index];
16976
16977            editor.update_in(cx, |editor, window, cx| {
16978                let effects = SelectionEffects::default();
16979
16980                editor.unfold_ranges(&[start..end], false, false, cx);
16981                editor.change_selections(effects, window, cx, |s| {
16982                    s.select_ranges([start..start]);
16983                });
16984            })?;
16985
16986            Ok(())
16987        }))
16988    }
16989
16990    pub fn find_all_references(
16991        &mut self,
16992        _: &FindAllReferences,
16993        window: &mut Window,
16994        cx: &mut Context<Self>,
16995    ) -> Option<Task<Result<Navigated>>> {
16996        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
16997        let multi_buffer = self.buffer.read(cx);
16998        let head = selection.head();
16999
17000        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17001        let head_anchor = multi_buffer_snapshot.anchor_at(
17002            head,
17003            if head < selection.tail() {
17004                Bias::Right
17005            } else {
17006                Bias::Left
17007            },
17008        );
17009
17010        match self
17011            .find_all_references_task_sources
17012            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17013        {
17014            Ok(_) => {
17015                log::info!(
17016                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
17017                );
17018                return None;
17019            }
17020            Err(i) => {
17021                self.find_all_references_task_sources.insert(i, head_anchor);
17022            }
17023        }
17024
17025        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
17026        let workspace = self.workspace()?;
17027        let project = workspace.read(cx).project().clone();
17028        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
17029        Some(cx.spawn_in(window, async move |editor, cx| {
17030            let _cleanup = cx.on_drop(&editor, move |editor, _| {
17031                if let Ok(i) = editor
17032                    .find_all_references_task_sources
17033                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17034                {
17035                    editor.find_all_references_task_sources.remove(i);
17036                }
17037            });
17038
17039            let Some(locations) = references.await? else {
17040                return anyhow::Ok(Navigated::No);
17041            };
17042            let mut locations = cx.update(|_, cx| {
17043                locations
17044                    .into_iter()
17045                    .map(|location| {
17046                        let buffer = location.buffer.read(cx);
17047                        (location.buffer, location.range.to_point(buffer))
17048                    })
17049                    .into_group_map()
17050            })?;
17051            if locations.is_empty() {
17052                return anyhow::Ok(Navigated::No);
17053            }
17054            for ranges in locations.values_mut() {
17055                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17056                ranges.dedup();
17057            }
17058
17059            workspace.update_in(cx, |workspace, window, cx| {
17060                let target = locations
17061                    .iter()
17062                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17063                    .map(|(buffer, location)| {
17064                        buffer
17065                            .read(cx)
17066                            .text_for_range(location.clone())
17067                            .collect::<String>()
17068                    })
17069                    .filter(|text| !text.contains('\n'))
17070                    .unique()
17071                    .take(3)
17072                    .join(", ");
17073                let title = if target.is_empty() {
17074                    "References".to_owned()
17075                } else {
17076                    format!("References to {target}")
17077                };
17078                Self::open_locations_in_multibuffer(
17079                    workspace,
17080                    locations,
17081                    title,
17082                    false,
17083                    MultibufferSelectionMode::First,
17084                    window,
17085                    cx,
17086                );
17087                Navigated::Yes
17088            })
17089        }))
17090    }
17091
17092    /// Opens a multibuffer with the given project locations in it
17093    pub fn open_locations_in_multibuffer(
17094        workspace: &mut Workspace,
17095        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
17096        title: String,
17097        split: bool,
17098        multibuffer_selection_mode: MultibufferSelectionMode,
17099        window: &mut Window,
17100        cx: &mut Context<Workspace>,
17101    ) {
17102        if locations.is_empty() {
17103            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
17104            return;
17105        }
17106
17107        let capability = workspace.project().read(cx).capability();
17108        let mut ranges = <Vec<Range<Anchor>>>::new();
17109
17110        // a key to find existing multibuffer editors with the same set of locations
17111        // to prevent us from opening more and more multibuffer tabs for searches and the like
17112        let mut key = (title.clone(), vec![]);
17113        let excerpt_buffer = cx.new(|cx| {
17114            let key = &mut key.1;
17115            let mut multibuffer = MultiBuffer::new(capability);
17116            for (buffer, mut ranges_for_buffer) in locations {
17117                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17118                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17119                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17120                    PathKey::for_buffer(&buffer, cx),
17121                    buffer.clone(),
17122                    ranges_for_buffer,
17123                    multibuffer_context_lines(cx),
17124                    cx,
17125                );
17126                ranges.extend(new_ranges)
17127            }
17128
17129            multibuffer.with_title(title)
17130        });
17131        let existing = workspace.active_pane().update(cx, |pane, cx| {
17132            pane.items()
17133                .filter_map(|item| item.downcast::<Editor>())
17134                .find(|editor| {
17135                    editor
17136                        .read(cx)
17137                        .lookup_key
17138                        .as_ref()
17139                        .and_then(|it| {
17140                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17141                        })
17142                        .is_some_and(|it| *it == key)
17143                })
17144        });
17145        let editor = existing.unwrap_or_else(|| {
17146            cx.new(|cx| {
17147                let mut editor = Editor::for_multibuffer(
17148                    excerpt_buffer,
17149                    Some(workspace.project().clone()),
17150                    window,
17151                    cx,
17152                );
17153                editor.lookup_key = Some(Box::new(key));
17154                editor
17155            })
17156        });
17157        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17158            MultibufferSelectionMode::First => {
17159                if let Some(first_range) = ranges.first() {
17160                    editor.change_selections(
17161                        SelectionEffects::no_scroll(),
17162                        window,
17163                        cx,
17164                        |selections| {
17165                            selections.clear_disjoint();
17166                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17167                        },
17168                    );
17169                }
17170                editor.highlight_background::<Self>(
17171                    &ranges,
17172                    |theme| theme.colors().editor_highlighted_line_background,
17173                    cx,
17174                );
17175            }
17176            MultibufferSelectionMode::All => {
17177                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17178                    selections.clear_disjoint();
17179                    selections.select_anchor_ranges(ranges);
17180                });
17181            }
17182        });
17183
17184        let item = Box::new(editor);
17185        let item_id = item.item_id();
17186
17187        if split {
17188            let pane = workspace.adjacent_pane(window, cx);
17189            workspace.add_item(pane, item, None, true, true, window, cx);
17190        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
17191            let (preview_item_id, preview_item_idx) =
17192                workspace.active_pane().read_with(cx, |pane, _| {
17193                    (pane.preview_item_id(), pane.preview_item_idx())
17194                });
17195
17196            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
17197
17198            if let Some(preview_item_id) = preview_item_id {
17199                workspace.active_pane().update(cx, |pane, cx| {
17200                    pane.remove_item(preview_item_id, false, false, window, cx);
17201                });
17202            }
17203        } else {
17204            workspace.add_item_to_active_pane(item, None, true, window, cx);
17205        }
17206        workspace.active_pane().update(cx, |pane, cx| {
17207            pane.set_preview_item_id(Some(item_id), cx);
17208        });
17209    }
17210
17211    pub fn rename(
17212        &mut self,
17213        _: &Rename,
17214        window: &mut Window,
17215        cx: &mut Context<Self>,
17216    ) -> Option<Task<Result<()>>> {
17217        use language::ToOffset as _;
17218
17219        let provider = self.semantics_provider.clone()?;
17220        let selection = self.selections.newest_anchor().clone();
17221        let (cursor_buffer, cursor_buffer_position) = self
17222            .buffer
17223            .read(cx)
17224            .text_anchor_for_position(selection.head(), cx)?;
17225        let (tail_buffer, cursor_buffer_position_end) = self
17226            .buffer
17227            .read(cx)
17228            .text_anchor_for_position(selection.tail(), cx)?;
17229        if tail_buffer != cursor_buffer {
17230            return None;
17231        }
17232
17233        let snapshot = cursor_buffer.read(cx).snapshot();
17234        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17235        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17236        let prepare_rename = provider
17237            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17238            .unwrap_or_else(|| Task::ready(Ok(None)));
17239        drop(snapshot);
17240
17241        Some(cx.spawn_in(window, async move |this, cx| {
17242            let rename_range = if let Some(range) = prepare_rename.await? {
17243                Some(range)
17244            } else {
17245                this.update(cx, |this, cx| {
17246                    let buffer = this.buffer.read(cx).snapshot(cx);
17247                    let mut buffer_highlights = this
17248                        .document_highlights_for_position(selection.head(), &buffer)
17249                        .filter(|highlight| {
17250                            highlight.start.excerpt_id == selection.head().excerpt_id
17251                                && highlight.end.excerpt_id == selection.head().excerpt_id
17252                        });
17253                    buffer_highlights
17254                        .next()
17255                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17256                })?
17257            };
17258            if let Some(rename_range) = rename_range {
17259                this.update_in(cx, |this, window, cx| {
17260                    let snapshot = cursor_buffer.read(cx).snapshot();
17261                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17262                    let cursor_offset_in_rename_range =
17263                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17264                    let cursor_offset_in_rename_range_end =
17265                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17266
17267                    this.take_rename(false, window, cx);
17268                    let buffer = this.buffer.read(cx).read(cx);
17269                    let cursor_offset = selection.head().to_offset(&buffer);
17270                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
17271                    let rename_end = rename_start + rename_buffer_range.len();
17272                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17273                    let mut old_highlight_id = None;
17274                    let old_name: Arc<str> = buffer
17275                        .chunks(rename_start..rename_end, true)
17276                        .map(|chunk| {
17277                            if old_highlight_id.is_none() {
17278                                old_highlight_id = chunk.syntax_highlight_id;
17279                            }
17280                            chunk.text
17281                        })
17282                        .collect::<String>()
17283                        .into();
17284
17285                    drop(buffer);
17286
17287                    // Position the selection in the rename editor so that it matches the current selection.
17288                    this.show_local_selections = false;
17289                    let rename_editor = cx.new(|cx| {
17290                        let mut editor = Editor::single_line(window, cx);
17291                        editor.buffer.update(cx, |buffer, cx| {
17292                            buffer.edit([(0..0, old_name.clone())], None, cx)
17293                        });
17294                        let rename_selection_range = match cursor_offset_in_rename_range
17295                            .cmp(&cursor_offset_in_rename_range_end)
17296                        {
17297                            Ordering::Equal => {
17298                                editor.select_all(&SelectAll, window, cx);
17299                                return editor;
17300                            }
17301                            Ordering::Less => {
17302                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17303                            }
17304                            Ordering::Greater => {
17305                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17306                            }
17307                        };
17308                        if rename_selection_range.end > old_name.len() {
17309                            editor.select_all(&SelectAll, window, cx);
17310                        } else {
17311                            editor.change_selections(Default::default(), window, cx, |s| {
17312                                s.select_ranges([rename_selection_range]);
17313                            });
17314                        }
17315                        editor
17316                    });
17317                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17318                        if e == &EditorEvent::Focused {
17319                            cx.emit(EditorEvent::FocusedIn)
17320                        }
17321                    })
17322                    .detach();
17323
17324                    let write_highlights =
17325                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17326                    let read_highlights =
17327                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17328                    let ranges = write_highlights
17329                        .iter()
17330                        .flat_map(|(_, ranges)| ranges.iter())
17331                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17332                        .cloned()
17333                        .collect();
17334
17335                    this.highlight_text::<Rename>(
17336                        ranges,
17337                        HighlightStyle {
17338                            fade_out: Some(0.6),
17339                            ..Default::default()
17340                        },
17341                        cx,
17342                    );
17343                    let rename_focus_handle = rename_editor.focus_handle(cx);
17344                    window.focus(&rename_focus_handle);
17345                    let block_id = this.insert_blocks(
17346                        [BlockProperties {
17347                            style: BlockStyle::Flex,
17348                            placement: BlockPlacement::Below(range.start),
17349                            height: Some(1),
17350                            render: Arc::new({
17351                                let rename_editor = rename_editor.clone();
17352                                move |cx: &mut BlockContext| {
17353                                    let mut text_style = cx.editor_style.text.clone();
17354                                    if let Some(highlight_style) = old_highlight_id
17355                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17356                                    {
17357                                        text_style = text_style.highlight(highlight_style);
17358                                    }
17359                                    div()
17360                                        .block_mouse_except_scroll()
17361                                        .pl(cx.anchor_x)
17362                                        .child(EditorElement::new(
17363                                            &rename_editor,
17364                                            EditorStyle {
17365                                                background: cx.theme().system().transparent,
17366                                                local_player: cx.editor_style.local_player,
17367                                                text: text_style,
17368                                                scrollbar_width: cx.editor_style.scrollbar_width,
17369                                                syntax: cx.editor_style.syntax.clone(),
17370                                                status: cx.editor_style.status.clone(),
17371                                                inlay_hints_style: HighlightStyle {
17372                                                    font_weight: Some(FontWeight::BOLD),
17373                                                    ..make_inlay_hints_style(cx.app)
17374                                                },
17375                                                edit_prediction_styles: make_suggestion_styles(
17376                                                    cx.app,
17377                                                ),
17378                                                ..EditorStyle::default()
17379                                            },
17380                                        ))
17381                                        .into_any_element()
17382                                }
17383                            }),
17384                            priority: 0,
17385                        }],
17386                        Some(Autoscroll::fit()),
17387                        cx,
17388                    )[0];
17389                    this.pending_rename = Some(RenameState {
17390                        range,
17391                        old_name,
17392                        editor: rename_editor,
17393                        block_id,
17394                    });
17395                })?;
17396            }
17397
17398            Ok(())
17399        }))
17400    }
17401
17402    pub fn confirm_rename(
17403        &mut self,
17404        _: &ConfirmRename,
17405        window: &mut Window,
17406        cx: &mut Context<Self>,
17407    ) -> Option<Task<Result<()>>> {
17408        let rename = self.take_rename(false, window, cx)?;
17409        let workspace = self.workspace()?.downgrade();
17410        let (buffer, start) = self
17411            .buffer
17412            .read(cx)
17413            .text_anchor_for_position(rename.range.start, cx)?;
17414        let (end_buffer, _) = self
17415            .buffer
17416            .read(cx)
17417            .text_anchor_for_position(rename.range.end, cx)?;
17418        if buffer != end_buffer {
17419            return None;
17420        }
17421
17422        let old_name = rename.old_name;
17423        let new_name = rename.editor.read(cx).text(cx);
17424
17425        let rename = self.semantics_provider.as_ref()?.perform_rename(
17426            &buffer,
17427            start,
17428            new_name.clone(),
17429            cx,
17430        )?;
17431
17432        Some(cx.spawn_in(window, async move |editor, cx| {
17433            let project_transaction = rename.await?;
17434            Self::open_project_transaction(
17435                &editor,
17436                workspace,
17437                project_transaction,
17438                format!("Rename: {}{}", old_name, new_name),
17439                cx,
17440            )
17441            .await?;
17442
17443            editor.update(cx, |editor, cx| {
17444                editor.refresh_document_highlights(cx);
17445            })?;
17446            Ok(())
17447        }))
17448    }
17449
17450    fn take_rename(
17451        &mut self,
17452        moving_cursor: bool,
17453        window: &mut Window,
17454        cx: &mut Context<Self>,
17455    ) -> Option<RenameState> {
17456        let rename = self.pending_rename.take()?;
17457        if rename.editor.focus_handle(cx).is_focused(window) {
17458            window.focus(&self.focus_handle);
17459        }
17460
17461        self.remove_blocks(
17462            [rename.block_id].into_iter().collect(),
17463            Some(Autoscroll::fit()),
17464            cx,
17465        );
17466        self.clear_highlights::<Rename>(cx);
17467        self.show_local_selections = true;
17468
17469        if moving_cursor {
17470            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17471                editor
17472                    .selections
17473                    .newest::<usize>(&editor.display_snapshot(cx))
17474                    .head()
17475            });
17476
17477            // Update the selection to match the position of the selection inside
17478            // the rename editor.
17479            let snapshot = self.buffer.read(cx).read(cx);
17480            let rename_range = rename.range.to_offset(&snapshot);
17481            let cursor_in_editor = snapshot
17482                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17483                .min(rename_range.end);
17484            drop(snapshot);
17485
17486            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17487                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17488            });
17489        } else {
17490            self.refresh_document_highlights(cx);
17491        }
17492
17493        Some(rename)
17494    }
17495
17496    pub fn pending_rename(&self) -> Option<&RenameState> {
17497        self.pending_rename.as_ref()
17498    }
17499
17500    fn format(
17501        &mut self,
17502        _: &Format,
17503        window: &mut Window,
17504        cx: &mut Context<Self>,
17505    ) -> Option<Task<Result<()>>> {
17506        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17507
17508        let project = match &self.project {
17509            Some(project) => project.clone(),
17510            None => return None,
17511        };
17512
17513        Some(self.perform_format(
17514            project,
17515            FormatTrigger::Manual,
17516            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17517            window,
17518            cx,
17519        ))
17520    }
17521
17522    fn format_selections(
17523        &mut self,
17524        _: &FormatSelections,
17525        window: &mut Window,
17526        cx: &mut Context<Self>,
17527    ) -> Option<Task<Result<()>>> {
17528        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17529
17530        let project = match &self.project {
17531            Some(project) => project.clone(),
17532            None => return None,
17533        };
17534
17535        let ranges = self
17536            .selections
17537            .all_adjusted(&self.display_snapshot(cx))
17538            .into_iter()
17539            .map(|selection| selection.range())
17540            .collect_vec();
17541
17542        Some(self.perform_format(
17543            project,
17544            FormatTrigger::Manual,
17545            FormatTarget::Ranges(ranges),
17546            window,
17547            cx,
17548        ))
17549    }
17550
17551    fn perform_format(
17552        &mut self,
17553        project: Entity<Project>,
17554        trigger: FormatTrigger,
17555        target: FormatTarget,
17556        window: &mut Window,
17557        cx: &mut Context<Self>,
17558    ) -> Task<Result<()>> {
17559        let buffer = self.buffer.clone();
17560        let (buffers, target) = match target {
17561            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17562            FormatTarget::Ranges(selection_ranges) => {
17563                let multi_buffer = buffer.read(cx);
17564                let snapshot = multi_buffer.read(cx);
17565                let mut buffers = HashSet::default();
17566                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17567                    BTreeMap::new();
17568                for selection_range in selection_ranges {
17569                    for (buffer, buffer_range, _) in
17570                        snapshot.range_to_buffer_ranges(selection_range)
17571                    {
17572                        let buffer_id = buffer.remote_id();
17573                        let start = buffer.anchor_before(buffer_range.start);
17574                        let end = buffer.anchor_after(buffer_range.end);
17575                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17576                        buffer_id_to_ranges
17577                            .entry(buffer_id)
17578                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17579                            .or_insert_with(|| vec![start..end]);
17580                    }
17581                }
17582                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17583            }
17584        };
17585
17586        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17587        let selections_prev = transaction_id_prev
17588            .and_then(|transaction_id_prev| {
17589                // default to selections as they were after the last edit, if we have them,
17590                // instead of how they are now.
17591                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17592                // will take you back to where you made the last edit, instead of staying where you scrolled
17593                self.selection_history
17594                    .transaction(transaction_id_prev)
17595                    .map(|t| t.0.clone())
17596            })
17597            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17598
17599        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17600        let format = project.update(cx, |project, cx| {
17601            project.format(buffers, target, true, trigger, cx)
17602        });
17603
17604        cx.spawn_in(window, async move |editor, cx| {
17605            let transaction = futures::select_biased! {
17606                transaction = format.log_err().fuse() => transaction,
17607                () = timeout => {
17608                    log::warn!("timed out waiting for formatting");
17609                    None
17610                }
17611            };
17612
17613            buffer
17614                .update(cx, |buffer, cx| {
17615                    if let Some(transaction) = transaction
17616                        && !buffer.is_singleton()
17617                    {
17618                        buffer.push_transaction(&transaction.0, cx);
17619                    }
17620                    cx.notify();
17621                })
17622                .ok();
17623
17624            if let Some(transaction_id_now) =
17625                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17626            {
17627                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17628                if has_new_transaction {
17629                    _ = editor.update(cx, |editor, _| {
17630                        editor
17631                            .selection_history
17632                            .insert_transaction(transaction_id_now, selections_prev);
17633                    });
17634                }
17635            }
17636
17637            Ok(())
17638        })
17639    }
17640
17641    fn organize_imports(
17642        &mut self,
17643        _: &OrganizeImports,
17644        window: &mut Window,
17645        cx: &mut Context<Self>,
17646    ) -> Option<Task<Result<()>>> {
17647        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17648        let project = match &self.project {
17649            Some(project) => project.clone(),
17650            None => return None,
17651        };
17652        Some(self.perform_code_action_kind(
17653            project,
17654            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17655            window,
17656            cx,
17657        ))
17658    }
17659
17660    fn perform_code_action_kind(
17661        &mut self,
17662        project: Entity<Project>,
17663        kind: CodeActionKind,
17664        window: &mut Window,
17665        cx: &mut Context<Self>,
17666    ) -> Task<Result<()>> {
17667        let buffer = self.buffer.clone();
17668        let buffers = buffer.read(cx).all_buffers();
17669        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17670        let apply_action = project.update(cx, |project, cx| {
17671            project.apply_code_action_kind(buffers, kind, true, cx)
17672        });
17673        cx.spawn_in(window, async move |_, cx| {
17674            let transaction = futures::select_biased! {
17675                () = timeout => {
17676                    log::warn!("timed out waiting for executing code action");
17677                    None
17678                }
17679                transaction = apply_action.log_err().fuse() => transaction,
17680            };
17681            buffer
17682                .update(cx, |buffer, cx| {
17683                    // check if we need this
17684                    if let Some(transaction) = transaction
17685                        && !buffer.is_singleton()
17686                    {
17687                        buffer.push_transaction(&transaction.0, cx);
17688                    }
17689                    cx.notify();
17690                })
17691                .ok();
17692            Ok(())
17693        })
17694    }
17695
17696    pub fn restart_language_server(
17697        &mut self,
17698        _: &RestartLanguageServer,
17699        _: &mut Window,
17700        cx: &mut Context<Self>,
17701    ) {
17702        if let Some(project) = self.project.clone() {
17703            self.buffer.update(cx, |multi_buffer, cx| {
17704                project.update(cx, |project, cx| {
17705                    project.restart_language_servers_for_buffers(
17706                        multi_buffer.all_buffers().into_iter().collect(),
17707                        HashSet::default(),
17708                        cx,
17709                    );
17710                });
17711            })
17712        }
17713    }
17714
17715    pub fn stop_language_server(
17716        &mut self,
17717        _: &StopLanguageServer,
17718        _: &mut Window,
17719        cx: &mut Context<Self>,
17720    ) {
17721        if let Some(project) = self.project.clone() {
17722            self.buffer.update(cx, |multi_buffer, cx| {
17723                project.update(cx, |project, cx| {
17724                    project.stop_language_servers_for_buffers(
17725                        multi_buffer.all_buffers().into_iter().collect(),
17726                        HashSet::default(),
17727                        cx,
17728                    );
17729                });
17730            });
17731            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
17732        }
17733    }
17734
17735    fn cancel_language_server_work(
17736        workspace: &mut Workspace,
17737        _: &actions::CancelLanguageServerWork,
17738        _: &mut Window,
17739        cx: &mut Context<Workspace>,
17740    ) {
17741        let project = workspace.project();
17742        let buffers = workspace
17743            .active_item(cx)
17744            .and_then(|item| item.act_as::<Editor>(cx))
17745            .map_or(HashSet::default(), |editor| {
17746                editor.read(cx).buffer.read(cx).all_buffers()
17747            });
17748        project.update(cx, |project, cx| {
17749            project.cancel_language_server_work_for_buffers(buffers, cx);
17750        });
17751    }
17752
17753    fn show_character_palette(
17754        &mut self,
17755        _: &ShowCharacterPalette,
17756        window: &mut Window,
17757        _: &mut Context<Self>,
17758    ) {
17759        window.show_character_palette();
17760    }
17761
17762    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17763        if !self.diagnostics_enabled() {
17764            return;
17765        }
17766
17767        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17768            let buffer = self.buffer.read(cx).snapshot(cx);
17769            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17770            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17771            let is_valid = buffer
17772                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17773                .any(|entry| {
17774                    entry.diagnostic.is_primary
17775                        && !entry.range.is_empty()
17776                        && entry.range.start == primary_range_start
17777                        && entry.diagnostic.message == active_diagnostics.active_message
17778                });
17779
17780            if !is_valid {
17781                self.dismiss_diagnostics(cx);
17782            }
17783        }
17784    }
17785
17786    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17787        match &self.active_diagnostics {
17788            ActiveDiagnostic::Group(group) => Some(group),
17789            _ => None,
17790        }
17791    }
17792
17793    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17794        if !self.diagnostics_enabled() {
17795            return;
17796        }
17797        self.dismiss_diagnostics(cx);
17798        self.active_diagnostics = ActiveDiagnostic::All;
17799    }
17800
17801    fn activate_diagnostics(
17802        &mut self,
17803        buffer_id: BufferId,
17804        diagnostic: DiagnosticEntryRef<'_, usize>,
17805        window: &mut Window,
17806        cx: &mut Context<Self>,
17807    ) {
17808        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17809            return;
17810        }
17811        self.dismiss_diagnostics(cx);
17812        let snapshot = self.snapshot(window, cx);
17813        let buffer = self.buffer.read(cx).snapshot(cx);
17814        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17815            return;
17816        };
17817
17818        let diagnostic_group = buffer
17819            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17820            .collect::<Vec<_>>();
17821
17822        let blocks =
17823            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17824
17825        let blocks = self.display_map.update(cx, |display_map, cx| {
17826            display_map.insert_blocks(blocks, cx).into_iter().collect()
17827        });
17828        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17829            active_range: buffer.anchor_before(diagnostic.range.start)
17830                ..buffer.anchor_after(diagnostic.range.end),
17831            active_message: diagnostic.diagnostic.message.clone(),
17832            group_id: diagnostic.diagnostic.group_id,
17833            blocks,
17834        });
17835        cx.notify();
17836    }
17837
17838    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17839        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17840            return;
17841        };
17842
17843        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17844        if let ActiveDiagnostic::Group(group) = prev {
17845            self.display_map.update(cx, |display_map, cx| {
17846                display_map.remove_blocks(group.blocks, cx);
17847            });
17848            cx.notify();
17849        }
17850    }
17851
17852    /// Disable inline diagnostics rendering for this editor.
17853    pub fn disable_inline_diagnostics(&mut self) {
17854        self.inline_diagnostics_enabled = false;
17855        self.inline_diagnostics_update = Task::ready(());
17856        self.inline_diagnostics.clear();
17857    }
17858
17859    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17860        self.diagnostics_enabled = false;
17861        self.dismiss_diagnostics(cx);
17862        self.inline_diagnostics_update = Task::ready(());
17863        self.inline_diagnostics.clear();
17864    }
17865
17866    pub fn disable_word_completions(&mut self) {
17867        self.word_completions_enabled = false;
17868    }
17869
17870    pub fn diagnostics_enabled(&self) -> bool {
17871        self.diagnostics_enabled && self.mode.is_full()
17872    }
17873
17874    pub fn inline_diagnostics_enabled(&self) -> bool {
17875        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17876    }
17877
17878    pub fn show_inline_diagnostics(&self) -> bool {
17879        self.show_inline_diagnostics
17880    }
17881
17882    pub fn toggle_inline_diagnostics(
17883        &mut self,
17884        _: &ToggleInlineDiagnostics,
17885        window: &mut Window,
17886        cx: &mut Context<Editor>,
17887    ) {
17888        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17889        self.refresh_inline_diagnostics(false, window, cx);
17890    }
17891
17892    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17893        self.diagnostics_max_severity = severity;
17894        self.display_map.update(cx, |display_map, _| {
17895            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17896        });
17897    }
17898
17899    pub fn toggle_diagnostics(
17900        &mut self,
17901        _: &ToggleDiagnostics,
17902        window: &mut Window,
17903        cx: &mut Context<Editor>,
17904    ) {
17905        if !self.diagnostics_enabled() {
17906            return;
17907        }
17908
17909        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17910            EditorSettings::get_global(cx)
17911                .diagnostics_max_severity
17912                .filter(|severity| severity != &DiagnosticSeverity::Off)
17913                .unwrap_or(DiagnosticSeverity::Hint)
17914        } else {
17915            DiagnosticSeverity::Off
17916        };
17917        self.set_max_diagnostics_severity(new_severity, cx);
17918        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17919            self.active_diagnostics = ActiveDiagnostic::None;
17920            self.inline_diagnostics_update = Task::ready(());
17921            self.inline_diagnostics.clear();
17922        } else {
17923            self.refresh_inline_diagnostics(false, window, cx);
17924        }
17925
17926        cx.notify();
17927    }
17928
17929    pub fn toggle_minimap(
17930        &mut self,
17931        _: &ToggleMinimap,
17932        window: &mut Window,
17933        cx: &mut Context<Editor>,
17934    ) {
17935        if self.supports_minimap(cx) {
17936            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17937        }
17938    }
17939
17940    fn refresh_inline_diagnostics(
17941        &mut self,
17942        debounce: bool,
17943        window: &mut Window,
17944        cx: &mut Context<Self>,
17945    ) {
17946        let max_severity = ProjectSettings::get_global(cx)
17947            .diagnostics
17948            .inline
17949            .max_severity
17950            .unwrap_or(self.diagnostics_max_severity);
17951
17952        if !self.inline_diagnostics_enabled()
17953            || !self.diagnostics_enabled()
17954            || !self.show_inline_diagnostics
17955            || max_severity == DiagnosticSeverity::Off
17956        {
17957            self.inline_diagnostics_update = Task::ready(());
17958            self.inline_diagnostics.clear();
17959            return;
17960        }
17961
17962        let debounce_ms = ProjectSettings::get_global(cx)
17963            .diagnostics
17964            .inline
17965            .update_debounce_ms;
17966        let debounce = if debounce && debounce_ms > 0 {
17967            Some(Duration::from_millis(debounce_ms))
17968        } else {
17969            None
17970        };
17971        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17972            if let Some(debounce) = debounce {
17973                cx.background_executor().timer(debounce).await;
17974            }
17975            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17976                editor
17977                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17978                    .ok()
17979            }) else {
17980                return;
17981            };
17982
17983            let new_inline_diagnostics = cx
17984                .background_spawn(async move {
17985                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17986                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17987                        let message = diagnostic_entry
17988                            .diagnostic
17989                            .message
17990                            .split_once('\n')
17991                            .map(|(line, _)| line)
17992                            .map(SharedString::new)
17993                            .unwrap_or_else(|| {
17994                                SharedString::new(&*diagnostic_entry.diagnostic.message)
17995                            });
17996                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17997                        let (Ok(i) | Err(i)) = inline_diagnostics
17998                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17999                        inline_diagnostics.insert(
18000                            i,
18001                            (
18002                                start_anchor,
18003                                InlineDiagnostic {
18004                                    message,
18005                                    group_id: diagnostic_entry.diagnostic.group_id,
18006                                    start: diagnostic_entry.range.start.to_point(&snapshot),
18007                                    is_primary: diagnostic_entry.diagnostic.is_primary,
18008                                    severity: diagnostic_entry.diagnostic.severity,
18009                                },
18010                            ),
18011                        );
18012                    }
18013                    inline_diagnostics
18014                })
18015                .await;
18016
18017            editor
18018                .update(cx, |editor, cx| {
18019                    editor.inline_diagnostics = new_inline_diagnostics;
18020                    cx.notify();
18021                })
18022                .ok();
18023        });
18024    }
18025
18026    fn pull_diagnostics(
18027        &mut self,
18028        buffer_id: Option<BufferId>,
18029        window: &Window,
18030        cx: &mut Context<Self>,
18031    ) -> Option<()> {
18032        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
18033            return None;
18034        }
18035        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
18036            .diagnostics
18037            .lsp_pull_diagnostics;
18038        if !pull_diagnostics_settings.enabled {
18039            return None;
18040        }
18041        let project = self.project()?.downgrade();
18042        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
18043        let mut buffers = self.buffer.read(cx).all_buffers();
18044        buffers.retain(|buffer| {
18045            let buffer_id_to_retain = buffer.read(cx).remote_id();
18046            buffer_id.is_none_or(|buffer_id| buffer_id == buffer_id_to_retain)
18047                && self.registered_buffers.contains_key(&buffer_id_to_retain)
18048        });
18049        if buffers.is_empty() {
18050            self.pull_diagnostics_task = Task::ready(());
18051            return None;
18052        }
18053
18054        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
18055            cx.background_executor().timer(debounce).await;
18056
18057            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
18058                buffers
18059                    .into_iter()
18060                    .filter_map(|buffer| {
18061                        project
18062                            .update(cx, |project, cx| {
18063                                project.lsp_store().update(cx, |lsp_store, cx| {
18064                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
18065                                })
18066                            })
18067                            .ok()
18068                    })
18069                    .collect::<FuturesUnordered<_>>()
18070            }) else {
18071                return;
18072            };
18073
18074            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
18075                match pull_task {
18076                    Ok(()) => {
18077                        if editor
18078                            .update_in(cx, |editor, window, cx| {
18079                                editor.update_diagnostics_state(window, cx);
18080                            })
18081                            .is_err()
18082                        {
18083                            return;
18084                        }
18085                    }
18086                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
18087                }
18088            }
18089        });
18090
18091        Some(())
18092    }
18093
18094    pub fn set_selections_from_remote(
18095        &mut self,
18096        selections: Vec<Selection<Anchor>>,
18097        pending_selection: Option<Selection<Anchor>>,
18098        window: &mut Window,
18099        cx: &mut Context<Self>,
18100    ) {
18101        let old_cursor_position = self.selections.newest_anchor().head();
18102        self.selections
18103            .change_with(&self.display_snapshot(cx), |s| {
18104                s.select_anchors(selections);
18105                if let Some(pending_selection) = pending_selection {
18106                    s.set_pending(pending_selection, SelectMode::Character);
18107                } else {
18108                    s.clear_pending();
18109                }
18110            });
18111        self.selections_did_change(
18112            false,
18113            &old_cursor_position,
18114            SelectionEffects::default(),
18115            window,
18116            cx,
18117        );
18118    }
18119
18120    pub fn transact(
18121        &mut self,
18122        window: &mut Window,
18123        cx: &mut Context<Self>,
18124        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
18125    ) -> Option<TransactionId> {
18126        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18127            this.start_transaction_at(Instant::now(), window, cx);
18128            update(this, window, cx);
18129            this.end_transaction_at(Instant::now(), cx)
18130        })
18131    }
18132
18133    pub fn start_transaction_at(
18134        &mut self,
18135        now: Instant,
18136        window: &mut Window,
18137        cx: &mut Context<Self>,
18138    ) -> Option<TransactionId> {
18139        self.end_selection(window, cx);
18140        if let Some(tx_id) = self
18141            .buffer
18142            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18143        {
18144            self.selection_history
18145                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18146            cx.emit(EditorEvent::TransactionBegun {
18147                transaction_id: tx_id,
18148            });
18149            Some(tx_id)
18150        } else {
18151            None
18152        }
18153    }
18154
18155    pub fn end_transaction_at(
18156        &mut self,
18157        now: Instant,
18158        cx: &mut Context<Self>,
18159    ) -> Option<TransactionId> {
18160        if let Some(transaction_id) = self
18161            .buffer
18162            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18163        {
18164            if let Some((_, end_selections)) =
18165                self.selection_history.transaction_mut(transaction_id)
18166            {
18167                *end_selections = Some(self.selections.disjoint_anchors_arc());
18168            } else {
18169                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18170            }
18171
18172            cx.emit(EditorEvent::Edited { transaction_id });
18173            Some(transaction_id)
18174        } else {
18175            None
18176        }
18177    }
18178
18179    pub fn modify_transaction_selection_history(
18180        &mut self,
18181        transaction_id: TransactionId,
18182        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18183    ) -> bool {
18184        self.selection_history
18185            .transaction_mut(transaction_id)
18186            .map(modify)
18187            .is_some()
18188    }
18189
18190    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18191        if self.selection_mark_mode {
18192            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18193                s.move_with(|_, sel| {
18194                    sel.collapse_to(sel.head(), SelectionGoal::None);
18195                });
18196            })
18197        }
18198        self.selection_mark_mode = true;
18199        cx.notify();
18200    }
18201
18202    pub fn swap_selection_ends(
18203        &mut self,
18204        _: &actions::SwapSelectionEnds,
18205        window: &mut Window,
18206        cx: &mut Context<Self>,
18207    ) {
18208        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18209            s.move_with(|_, sel| {
18210                if sel.start != sel.end {
18211                    sel.reversed = !sel.reversed
18212                }
18213            });
18214        });
18215        self.request_autoscroll(Autoscroll::newest(), cx);
18216        cx.notify();
18217    }
18218
18219    pub fn toggle_focus(
18220        workspace: &mut Workspace,
18221        _: &actions::ToggleFocus,
18222        window: &mut Window,
18223        cx: &mut Context<Workspace>,
18224    ) {
18225        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18226            return;
18227        };
18228        workspace.activate_item(&item, true, true, window, cx);
18229    }
18230
18231    pub fn toggle_fold(
18232        &mut self,
18233        _: &actions::ToggleFold,
18234        window: &mut Window,
18235        cx: &mut Context<Self>,
18236    ) {
18237        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18238            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18239            let selection = self.selections.newest::<Point>(&display_map);
18240
18241            let range = if selection.is_empty() {
18242                let point = selection.head().to_display_point(&display_map);
18243                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18244                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18245                    .to_point(&display_map);
18246                start..end
18247            } else {
18248                selection.range()
18249            };
18250            if display_map.folds_in_range(range).next().is_some() {
18251                self.unfold_lines(&Default::default(), window, cx)
18252            } else {
18253                self.fold(&Default::default(), window, cx)
18254            }
18255        } else {
18256            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18257            let buffer_ids: HashSet<_> = self
18258                .selections
18259                .disjoint_anchor_ranges()
18260                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18261                .collect();
18262
18263            let should_unfold = buffer_ids
18264                .iter()
18265                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18266
18267            for buffer_id in buffer_ids {
18268                if should_unfold {
18269                    self.unfold_buffer(buffer_id, cx);
18270                } else {
18271                    self.fold_buffer(buffer_id, cx);
18272                }
18273            }
18274        }
18275    }
18276
18277    pub fn toggle_fold_recursive(
18278        &mut self,
18279        _: &actions::ToggleFoldRecursive,
18280        window: &mut Window,
18281        cx: &mut Context<Self>,
18282    ) {
18283        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
18284
18285        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18286        let range = if selection.is_empty() {
18287            let point = selection.head().to_display_point(&display_map);
18288            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18289            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18290                .to_point(&display_map);
18291            start..end
18292        } else {
18293            selection.range()
18294        };
18295        if display_map.folds_in_range(range).next().is_some() {
18296            self.unfold_recursive(&Default::default(), window, cx)
18297        } else {
18298            self.fold_recursive(&Default::default(), window, cx)
18299        }
18300    }
18301
18302    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18303        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18304            let mut to_fold = Vec::new();
18305            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18306            let selections = self.selections.all_adjusted(&display_map);
18307
18308            for selection in selections {
18309                let range = selection.range().sorted();
18310                let buffer_start_row = range.start.row;
18311
18312                if range.start.row != range.end.row {
18313                    let mut found = false;
18314                    let mut row = range.start.row;
18315                    while row <= range.end.row {
18316                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18317                        {
18318                            found = true;
18319                            row = crease.range().end.row + 1;
18320                            to_fold.push(crease);
18321                        } else {
18322                            row += 1
18323                        }
18324                    }
18325                    if found {
18326                        continue;
18327                    }
18328                }
18329
18330                for row in (0..=range.start.row).rev() {
18331                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18332                        && crease.range().end.row >= buffer_start_row
18333                    {
18334                        to_fold.push(crease);
18335                        if row <= range.start.row {
18336                            break;
18337                        }
18338                    }
18339                }
18340            }
18341
18342            self.fold_creases(to_fold, true, window, cx);
18343        } else {
18344            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18345            let buffer_ids = self
18346                .selections
18347                .disjoint_anchor_ranges()
18348                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18349                .collect::<HashSet<_>>();
18350            for buffer_id in buffer_ids {
18351                self.fold_buffer(buffer_id, cx);
18352            }
18353        }
18354    }
18355
18356    pub fn toggle_fold_all(
18357        &mut self,
18358        _: &actions::ToggleFoldAll,
18359        window: &mut Window,
18360        cx: &mut Context<Self>,
18361    ) {
18362        if self.buffer.read(cx).is_singleton() {
18363            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18364            let has_folds = display_map
18365                .folds_in_range(0..display_map.buffer_snapshot().len())
18366                .next()
18367                .is_some();
18368
18369            if has_folds {
18370                self.unfold_all(&actions::UnfoldAll, window, cx);
18371            } else {
18372                self.fold_all(&actions::FoldAll, window, cx);
18373            }
18374        } else {
18375            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18376            let should_unfold = buffer_ids
18377                .iter()
18378                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18379
18380            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18381                editor
18382                    .update_in(cx, |editor, _, cx| {
18383                        for buffer_id in buffer_ids {
18384                            if should_unfold {
18385                                editor.unfold_buffer(buffer_id, cx);
18386                            } else {
18387                                editor.fold_buffer(buffer_id, cx);
18388                            }
18389                        }
18390                    })
18391                    .ok();
18392            });
18393        }
18394    }
18395
18396    fn fold_at_level(
18397        &mut self,
18398        fold_at: &FoldAtLevel,
18399        window: &mut Window,
18400        cx: &mut Context<Self>,
18401    ) {
18402        if !self.buffer.read(cx).is_singleton() {
18403            return;
18404        }
18405
18406        let fold_at_level = fold_at.0;
18407        let snapshot = self.buffer.read(cx).snapshot(cx);
18408        let mut to_fold = Vec::new();
18409        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18410
18411        let row_ranges_to_keep: Vec<Range<u32>> = self
18412            .selections
18413            .all::<Point>(&self.display_snapshot(cx))
18414            .into_iter()
18415            .map(|sel| sel.start.row..sel.end.row)
18416            .collect();
18417
18418        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18419            while start_row < end_row {
18420                match self
18421                    .snapshot(window, cx)
18422                    .crease_for_buffer_row(MultiBufferRow(start_row))
18423                {
18424                    Some(crease) => {
18425                        let nested_start_row = crease.range().start.row + 1;
18426                        let nested_end_row = crease.range().end.row;
18427
18428                        if current_level < fold_at_level {
18429                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18430                        } else if current_level == fold_at_level {
18431                            // Fold iff there is no selection completely contained within the fold region
18432                            if !row_ranges_to_keep.iter().any(|selection| {
18433                                selection.end >= nested_start_row
18434                                    && selection.start <= nested_end_row
18435                            }) {
18436                                to_fold.push(crease);
18437                            }
18438                        }
18439
18440                        start_row = nested_end_row + 1;
18441                    }
18442                    None => start_row += 1,
18443                }
18444            }
18445        }
18446
18447        self.fold_creases(to_fold, true, window, cx);
18448    }
18449
18450    pub fn fold_at_level_1(
18451        &mut self,
18452        _: &actions::FoldAtLevel1,
18453        window: &mut Window,
18454        cx: &mut Context<Self>,
18455    ) {
18456        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18457    }
18458
18459    pub fn fold_at_level_2(
18460        &mut self,
18461        _: &actions::FoldAtLevel2,
18462        window: &mut Window,
18463        cx: &mut Context<Self>,
18464    ) {
18465        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18466    }
18467
18468    pub fn fold_at_level_3(
18469        &mut self,
18470        _: &actions::FoldAtLevel3,
18471        window: &mut Window,
18472        cx: &mut Context<Self>,
18473    ) {
18474        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18475    }
18476
18477    pub fn fold_at_level_4(
18478        &mut self,
18479        _: &actions::FoldAtLevel4,
18480        window: &mut Window,
18481        cx: &mut Context<Self>,
18482    ) {
18483        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18484    }
18485
18486    pub fn fold_at_level_5(
18487        &mut self,
18488        _: &actions::FoldAtLevel5,
18489        window: &mut Window,
18490        cx: &mut Context<Self>,
18491    ) {
18492        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18493    }
18494
18495    pub fn fold_at_level_6(
18496        &mut self,
18497        _: &actions::FoldAtLevel6,
18498        window: &mut Window,
18499        cx: &mut Context<Self>,
18500    ) {
18501        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18502    }
18503
18504    pub fn fold_at_level_7(
18505        &mut self,
18506        _: &actions::FoldAtLevel7,
18507        window: &mut Window,
18508        cx: &mut Context<Self>,
18509    ) {
18510        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18511    }
18512
18513    pub fn fold_at_level_8(
18514        &mut self,
18515        _: &actions::FoldAtLevel8,
18516        window: &mut Window,
18517        cx: &mut Context<Self>,
18518    ) {
18519        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18520    }
18521
18522    pub fn fold_at_level_9(
18523        &mut self,
18524        _: &actions::FoldAtLevel9,
18525        window: &mut Window,
18526        cx: &mut Context<Self>,
18527    ) {
18528        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18529    }
18530
18531    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18532        if self.buffer.read(cx).is_singleton() {
18533            let mut fold_ranges = Vec::new();
18534            let snapshot = self.buffer.read(cx).snapshot(cx);
18535
18536            for row in 0..snapshot.max_row().0 {
18537                if let Some(foldable_range) = self
18538                    .snapshot(window, cx)
18539                    .crease_for_buffer_row(MultiBufferRow(row))
18540                {
18541                    fold_ranges.push(foldable_range);
18542                }
18543            }
18544
18545            self.fold_creases(fold_ranges, true, window, cx);
18546        } else {
18547            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18548                editor
18549                    .update_in(cx, |editor, _, cx| {
18550                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18551                            editor.fold_buffer(buffer_id, cx);
18552                        }
18553                    })
18554                    .ok();
18555            });
18556        }
18557    }
18558
18559    pub fn fold_function_bodies(
18560        &mut self,
18561        _: &actions::FoldFunctionBodies,
18562        window: &mut Window,
18563        cx: &mut Context<Self>,
18564    ) {
18565        let snapshot = self.buffer.read(cx).snapshot(cx);
18566
18567        let ranges = snapshot
18568            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18569            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18570            .collect::<Vec<_>>();
18571
18572        let creases = ranges
18573            .into_iter()
18574            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18575            .collect();
18576
18577        self.fold_creases(creases, true, window, cx);
18578    }
18579
18580    pub fn fold_recursive(
18581        &mut self,
18582        _: &actions::FoldRecursive,
18583        window: &mut Window,
18584        cx: &mut Context<Self>,
18585    ) {
18586        let mut to_fold = Vec::new();
18587        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18588        let selections = self.selections.all_adjusted(&display_map);
18589
18590        for selection in selections {
18591            let range = selection.range().sorted();
18592            let buffer_start_row = range.start.row;
18593
18594            if range.start.row != range.end.row {
18595                let mut found = false;
18596                for row in range.start.row..=range.end.row {
18597                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18598                        found = true;
18599                        to_fold.push(crease);
18600                    }
18601                }
18602                if found {
18603                    continue;
18604                }
18605            }
18606
18607            for row in (0..=range.start.row).rev() {
18608                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18609                    if crease.range().end.row >= buffer_start_row {
18610                        to_fold.push(crease);
18611                    } else {
18612                        break;
18613                    }
18614                }
18615            }
18616        }
18617
18618        self.fold_creases(to_fold, true, window, cx);
18619    }
18620
18621    pub fn fold_at(
18622        &mut self,
18623        buffer_row: MultiBufferRow,
18624        window: &mut Window,
18625        cx: &mut Context<Self>,
18626    ) {
18627        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18628
18629        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18630            let autoscroll = self
18631                .selections
18632                .all::<Point>(&display_map)
18633                .iter()
18634                .any(|selection| crease.range().overlaps(&selection.range()));
18635
18636            self.fold_creases(vec![crease], autoscroll, window, cx);
18637        }
18638    }
18639
18640    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18641        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18642            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18643            let buffer = display_map.buffer_snapshot();
18644            let selections = self.selections.all::<Point>(&display_map);
18645            let ranges = selections
18646                .iter()
18647                .map(|s| {
18648                    let range = s.display_range(&display_map).sorted();
18649                    let mut start = range.start.to_point(&display_map);
18650                    let mut end = range.end.to_point(&display_map);
18651                    start.column = 0;
18652                    end.column = buffer.line_len(MultiBufferRow(end.row));
18653                    start..end
18654                })
18655                .collect::<Vec<_>>();
18656
18657            self.unfold_ranges(&ranges, true, true, cx);
18658        } else {
18659            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18660            let buffer_ids = self
18661                .selections
18662                .disjoint_anchor_ranges()
18663                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18664                .collect::<HashSet<_>>();
18665            for buffer_id in buffer_ids {
18666                self.unfold_buffer(buffer_id, cx);
18667            }
18668        }
18669    }
18670
18671    pub fn unfold_recursive(
18672        &mut self,
18673        _: &UnfoldRecursive,
18674        _window: &mut Window,
18675        cx: &mut Context<Self>,
18676    ) {
18677        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18678        let selections = self.selections.all::<Point>(&display_map);
18679        let ranges = selections
18680            .iter()
18681            .map(|s| {
18682                let mut range = s.display_range(&display_map).sorted();
18683                *range.start.column_mut() = 0;
18684                *range.end.column_mut() = display_map.line_len(range.end.row());
18685                let start = range.start.to_point(&display_map);
18686                let end = range.end.to_point(&display_map);
18687                start..end
18688            })
18689            .collect::<Vec<_>>();
18690
18691        self.unfold_ranges(&ranges, true, true, cx);
18692    }
18693
18694    pub fn unfold_at(
18695        &mut self,
18696        buffer_row: MultiBufferRow,
18697        _window: &mut Window,
18698        cx: &mut Context<Self>,
18699    ) {
18700        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18701
18702        let intersection_range = Point::new(buffer_row.0, 0)
18703            ..Point::new(
18704                buffer_row.0,
18705                display_map.buffer_snapshot().line_len(buffer_row),
18706            );
18707
18708        let autoscroll = self
18709            .selections
18710            .all::<Point>(&display_map)
18711            .iter()
18712            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18713
18714        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18715    }
18716
18717    pub fn unfold_all(
18718        &mut self,
18719        _: &actions::UnfoldAll,
18720        _window: &mut Window,
18721        cx: &mut Context<Self>,
18722    ) {
18723        if self.buffer.read(cx).is_singleton() {
18724            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18725            self.unfold_ranges(&[0..display_map.buffer_snapshot().len()], true, true, cx);
18726        } else {
18727            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18728                editor
18729                    .update(cx, |editor, cx| {
18730                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18731                            editor.unfold_buffer(buffer_id, cx);
18732                        }
18733                    })
18734                    .ok();
18735            });
18736        }
18737    }
18738
18739    pub fn fold_selected_ranges(
18740        &mut self,
18741        _: &FoldSelectedRanges,
18742        window: &mut Window,
18743        cx: &mut Context<Self>,
18744    ) {
18745        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18746        let selections = self.selections.all_adjusted(&display_map);
18747        let ranges = selections
18748            .into_iter()
18749            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18750            .collect::<Vec<_>>();
18751        self.fold_creases(ranges, true, window, cx);
18752    }
18753
18754    pub fn fold_ranges<T: ToOffset + Clone>(
18755        &mut self,
18756        ranges: Vec<Range<T>>,
18757        auto_scroll: bool,
18758        window: &mut Window,
18759        cx: &mut Context<Self>,
18760    ) {
18761        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18762        let ranges = ranges
18763            .into_iter()
18764            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18765            .collect::<Vec<_>>();
18766        self.fold_creases(ranges, auto_scroll, window, cx);
18767    }
18768
18769    pub fn fold_creases<T: ToOffset + Clone>(
18770        &mut self,
18771        creases: Vec<Crease<T>>,
18772        auto_scroll: bool,
18773        _window: &mut Window,
18774        cx: &mut Context<Self>,
18775    ) {
18776        if creases.is_empty() {
18777            return;
18778        }
18779
18780        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18781
18782        if auto_scroll {
18783            self.request_autoscroll(Autoscroll::fit(), cx);
18784        }
18785
18786        cx.notify();
18787
18788        self.scrollbar_marker_state.dirty = true;
18789        self.folds_did_change(cx);
18790    }
18791
18792    /// Removes any folds whose ranges intersect any of the given ranges.
18793    pub fn unfold_ranges<T: ToOffset + Clone>(
18794        &mut self,
18795        ranges: &[Range<T>],
18796        inclusive: bool,
18797        auto_scroll: bool,
18798        cx: &mut Context<Self>,
18799    ) {
18800        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18801            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18802        });
18803        self.folds_did_change(cx);
18804    }
18805
18806    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18807        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18808            return;
18809        }
18810        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18811        self.display_map.update(cx, |display_map, cx| {
18812            display_map.fold_buffers([buffer_id], cx)
18813        });
18814        cx.emit(EditorEvent::BufferFoldToggled {
18815            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18816            folded: true,
18817        });
18818        cx.notify();
18819    }
18820
18821    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18822        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18823            return;
18824        }
18825        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18826        self.display_map.update(cx, |display_map, cx| {
18827            display_map.unfold_buffers([buffer_id], cx);
18828        });
18829        cx.emit(EditorEvent::BufferFoldToggled {
18830            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18831            folded: false,
18832        });
18833        cx.notify();
18834    }
18835
18836    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18837        self.display_map.read(cx).is_buffer_folded(buffer)
18838    }
18839
18840    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18841        self.display_map.read(cx).folded_buffers()
18842    }
18843
18844    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18845        self.display_map.update(cx, |display_map, cx| {
18846            display_map.disable_header_for_buffer(buffer_id, cx);
18847        });
18848        cx.notify();
18849    }
18850
18851    /// Removes any folds with the given ranges.
18852    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18853        &mut self,
18854        ranges: &[Range<T>],
18855        type_id: TypeId,
18856        auto_scroll: bool,
18857        cx: &mut Context<Self>,
18858    ) {
18859        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18860            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18861        });
18862        self.folds_did_change(cx);
18863    }
18864
18865    fn remove_folds_with<T: ToOffset + Clone>(
18866        &mut self,
18867        ranges: &[Range<T>],
18868        auto_scroll: bool,
18869        cx: &mut Context<Self>,
18870        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18871    ) {
18872        if ranges.is_empty() {
18873            return;
18874        }
18875
18876        let mut buffers_affected = HashSet::default();
18877        let multi_buffer = self.buffer().read(cx);
18878        for range in ranges {
18879            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18880                buffers_affected.insert(buffer.read(cx).remote_id());
18881            };
18882        }
18883
18884        self.display_map.update(cx, update);
18885
18886        if auto_scroll {
18887            self.request_autoscroll(Autoscroll::fit(), cx);
18888        }
18889
18890        cx.notify();
18891        self.scrollbar_marker_state.dirty = true;
18892        self.active_indent_guides_state.dirty = true;
18893    }
18894
18895    pub fn update_renderer_widths(
18896        &mut self,
18897        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18898        cx: &mut Context<Self>,
18899    ) -> bool {
18900        self.display_map
18901            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18902    }
18903
18904    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18905        self.display_map.read(cx).fold_placeholder.clone()
18906    }
18907
18908    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18909        self.buffer.update(cx, |buffer, cx| {
18910            buffer.set_all_diff_hunks_expanded(cx);
18911        });
18912    }
18913
18914    pub fn expand_all_diff_hunks(
18915        &mut self,
18916        _: &ExpandAllDiffHunks,
18917        _window: &mut Window,
18918        cx: &mut Context<Self>,
18919    ) {
18920        self.buffer.update(cx, |buffer, cx| {
18921            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18922        });
18923    }
18924
18925    pub fn collapse_all_diff_hunks(
18926        &mut self,
18927        _: &CollapseAllDiffHunks,
18928        _window: &mut Window,
18929        cx: &mut Context<Self>,
18930    ) {
18931        self.buffer.update(cx, |buffer, cx| {
18932            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18933        });
18934    }
18935
18936    pub fn toggle_selected_diff_hunks(
18937        &mut self,
18938        _: &ToggleSelectedDiffHunks,
18939        _window: &mut Window,
18940        cx: &mut Context<Self>,
18941    ) {
18942        let ranges: Vec<_> = self
18943            .selections
18944            .disjoint_anchors()
18945            .iter()
18946            .map(|s| s.range())
18947            .collect();
18948        self.toggle_diff_hunks_in_ranges(ranges, cx);
18949    }
18950
18951    pub fn diff_hunks_in_ranges<'a>(
18952        &'a self,
18953        ranges: &'a [Range<Anchor>],
18954        buffer: &'a MultiBufferSnapshot,
18955    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18956        ranges.iter().flat_map(move |range| {
18957            let end_excerpt_id = range.end.excerpt_id;
18958            let range = range.to_point(buffer);
18959            let mut peek_end = range.end;
18960            if range.end.row < buffer.max_row().0 {
18961                peek_end = Point::new(range.end.row + 1, 0);
18962            }
18963            buffer
18964                .diff_hunks_in_range(range.start..peek_end)
18965                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18966        })
18967    }
18968
18969    pub fn has_stageable_diff_hunks_in_ranges(
18970        &self,
18971        ranges: &[Range<Anchor>],
18972        snapshot: &MultiBufferSnapshot,
18973    ) -> bool {
18974        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18975        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18976    }
18977
18978    pub fn toggle_staged_selected_diff_hunks(
18979        &mut self,
18980        _: &::git::ToggleStaged,
18981        _: &mut Window,
18982        cx: &mut Context<Self>,
18983    ) {
18984        let snapshot = self.buffer.read(cx).snapshot(cx);
18985        let ranges: Vec<_> = self
18986            .selections
18987            .disjoint_anchors()
18988            .iter()
18989            .map(|s| s.range())
18990            .collect();
18991        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18992        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18993    }
18994
18995    pub fn set_render_diff_hunk_controls(
18996        &mut self,
18997        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18998        cx: &mut Context<Self>,
18999    ) {
19000        self.render_diff_hunk_controls = render_diff_hunk_controls;
19001        cx.notify();
19002    }
19003
19004    pub fn stage_and_next(
19005        &mut self,
19006        _: &::git::StageAndNext,
19007        window: &mut Window,
19008        cx: &mut Context<Self>,
19009    ) {
19010        self.do_stage_or_unstage_and_next(true, window, cx);
19011    }
19012
19013    pub fn unstage_and_next(
19014        &mut self,
19015        _: &::git::UnstageAndNext,
19016        window: &mut Window,
19017        cx: &mut Context<Self>,
19018    ) {
19019        self.do_stage_or_unstage_and_next(false, window, cx);
19020    }
19021
19022    pub fn stage_or_unstage_diff_hunks(
19023        &mut self,
19024        stage: bool,
19025        ranges: Vec<Range<Anchor>>,
19026        cx: &mut Context<Self>,
19027    ) {
19028        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
19029        cx.spawn(async move |this, cx| {
19030            task.await?;
19031            this.update(cx, |this, cx| {
19032                let snapshot = this.buffer.read(cx).snapshot(cx);
19033                let chunk_by = this
19034                    .diff_hunks_in_ranges(&ranges, &snapshot)
19035                    .chunk_by(|hunk| hunk.buffer_id);
19036                for (buffer_id, hunks) in &chunk_by {
19037                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
19038                }
19039            })
19040        })
19041        .detach_and_log_err(cx);
19042    }
19043
19044    fn save_buffers_for_ranges_if_needed(
19045        &mut self,
19046        ranges: &[Range<Anchor>],
19047        cx: &mut Context<Editor>,
19048    ) -> Task<Result<()>> {
19049        let multibuffer = self.buffer.read(cx);
19050        let snapshot = multibuffer.read(cx);
19051        let buffer_ids: HashSet<_> = ranges
19052            .iter()
19053            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
19054            .collect();
19055        drop(snapshot);
19056
19057        let mut buffers = HashSet::default();
19058        for buffer_id in buffer_ids {
19059            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
19060                let buffer = buffer_entity.read(cx);
19061                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
19062                {
19063                    buffers.insert(buffer_entity);
19064                }
19065            }
19066        }
19067
19068        if let Some(project) = &self.project {
19069            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
19070        } else {
19071            Task::ready(Ok(()))
19072        }
19073    }
19074
19075    fn do_stage_or_unstage_and_next(
19076        &mut self,
19077        stage: bool,
19078        window: &mut Window,
19079        cx: &mut Context<Self>,
19080    ) {
19081        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
19082
19083        if ranges.iter().any(|range| range.start != range.end) {
19084            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19085            return;
19086        }
19087
19088        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19089        let snapshot = self.snapshot(window, cx);
19090        let position = self
19091            .selections
19092            .newest::<Point>(&snapshot.display_snapshot)
19093            .head();
19094        let mut row = snapshot
19095            .buffer_snapshot()
19096            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
19097            .find(|hunk| hunk.row_range.start.0 > position.row)
19098            .map(|hunk| hunk.row_range.start);
19099
19100        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
19101        // Outside of the project diff editor, wrap around to the beginning.
19102        if !all_diff_hunks_expanded {
19103            row = row.or_else(|| {
19104                snapshot
19105                    .buffer_snapshot()
19106                    .diff_hunks_in_range(Point::zero()..position)
19107                    .find(|hunk| hunk.row_range.end.0 < position.row)
19108                    .map(|hunk| hunk.row_range.start)
19109            });
19110        }
19111
19112        if let Some(row) = row {
19113            let destination = Point::new(row.0, 0);
19114            let autoscroll = Autoscroll::center();
19115
19116            self.unfold_ranges(&[destination..destination], false, false, cx);
19117            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
19118                s.select_ranges([destination..destination]);
19119            });
19120        }
19121    }
19122
19123    fn do_stage_or_unstage(
19124        &self,
19125        stage: bool,
19126        buffer_id: BufferId,
19127        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
19128        cx: &mut App,
19129    ) -> Option<()> {
19130        let project = self.project()?;
19131        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19132        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19133        let buffer_snapshot = buffer.read(cx).snapshot();
19134        let file_exists = buffer_snapshot
19135            .file()
19136            .is_some_and(|file| file.disk_state().exists());
19137        diff.update(cx, |diff, cx| {
19138            diff.stage_or_unstage_hunks(
19139                stage,
19140                &hunks
19141                    .map(|hunk| buffer_diff::DiffHunk {
19142                        buffer_range: hunk.buffer_range,
19143                        diff_base_byte_range: hunk.diff_base_byte_range,
19144                        secondary_status: hunk.secondary_status,
19145                        range: Point::zero()..Point::zero(), // unused
19146                    })
19147                    .collect::<Vec<_>>(),
19148                &buffer_snapshot,
19149                file_exists,
19150                cx,
19151            )
19152        });
19153        None
19154    }
19155
19156    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19157        let ranges: Vec<_> = self
19158            .selections
19159            .disjoint_anchors()
19160            .iter()
19161            .map(|s| s.range())
19162            .collect();
19163        self.buffer
19164            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19165    }
19166
19167    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19168        self.buffer.update(cx, |buffer, cx| {
19169            let ranges = vec![Anchor::min()..Anchor::max()];
19170            if !buffer.all_diff_hunks_expanded()
19171                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19172            {
19173                buffer.collapse_diff_hunks(ranges, cx);
19174                true
19175            } else {
19176                false
19177            }
19178        })
19179    }
19180
19181    fn toggle_diff_hunks_in_ranges(
19182        &mut self,
19183        ranges: Vec<Range<Anchor>>,
19184        cx: &mut Context<Editor>,
19185    ) {
19186        self.buffer.update(cx, |buffer, cx| {
19187            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
19188            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
19189        })
19190    }
19191
19192    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
19193        self.buffer.update(cx, |buffer, cx| {
19194            let snapshot = buffer.snapshot(cx);
19195            let excerpt_id = range.end.excerpt_id;
19196            let point_range = range.to_point(&snapshot);
19197            let expand = !buffer.single_hunk_is_expanded(range, cx);
19198            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
19199        })
19200    }
19201
19202    pub(crate) fn apply_all_diff_hunks(
19203        &mut self,
19204        _: &ApplyAllDiffHunks,
19205        window: &mut Window,
19206        cx: &mut Context<Self>,
19207    ) {
19208        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19209
19210        let buffers = self.buffer.read(cx).all_buffers();
19211        for branch_buffer in buffers {
19212            branch_buffer.update(cx, |branch_buffer, cx| {
19213                branch_buffer.merge_into_base(Vec::new(), cx);
19214            });
19215        }
19216
19217        if let Some(project) = self.project.clone() {
19218            self.save(
19219                SaveOptions {
19220                    format: true,
19221                    autosave: false,
19222                },
19223                project,
19224                window,
19225                cx,
19226            )
19227            .detach_and_log_err(cx);
19228        }
19229    }
19230
19231    pub(crate) fn apply_selected_diff_hunks(
19232        &mut self,
19233        _: &ApplyDiffHunk,
19234        window: &mut Window,
19235        cx: &mut Context<Self>,
19236    ) {
19237        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19238        let snapshot = self.snapshot(window, cx);
19239        let hunks = snapshot.hunks_for_ranges(
19240            self.selections
19241                .all(&snapshot.display_snapshot)
19242                .into_iter()
19243                .map(|selection| selection.range()),
19244        );
19245        let mut ranges_by_buffer = HashMap::default();
19246        self.transact(window, cx, |editor, _window, cx| {
19247            for hunk in hunks {
19248                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19249                    ranges_by_buffer
19250                        .entry(buffer.clone())
19251                        .or_insert_with(Vec::new)
19252                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19253                }
19254            }
19255
19256            for (buffer, ranges) in ranges_by_buffer {
19257                buffer.update(cx, |buffer, cx| {
19258                    buffer.merge_into_base(ranges, cx);
19259                });
19260            }
19261        });
19262
19263        if let Some(project) = self.project.clone() {
19264            self.save(
19265                SaveOptions {
19266                    format: true,
19267                    autosave: false,
19268                },
19269                project,
19270                window,
19271                cx,
19272            )
19273            .detach_and_log_err(cx);
19274        }
19275    }
19276
19277    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19278        if hovered != self.gutter_hovered {
19279            self.gutter_hovered = hovered;
19280            cx.notify();
19281        }
19282    }
19283
19284    pub fn insert_blocks(
19285        &mut self,
19286        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19287        autoscroll: Option<Autoscroll>,
19288        cx: &mut Context<Self>,
19289    ) -> Vec<CustomBlockId> {
19290        let blocks = self
19291            .display_map
19292            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19293        if let Some(autoscroll) = autoscroll {
19294            self.request_autoscroll(autoscroll, cx);
19295        }
19296        cx.notify();
19297        blocks
19298    }
19299
19300    pub fn resize_blocks(
19301        &mut self,
19302        heights: HashMap<CustomBlockId, u32>,
19303        autoscroll: Option<Autoscroll>,
19304        cx: &mut Context<Self>,
19305    ) {
19306        self.display_map
19307            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19308        if let Some(autoscroll) = autoscroll {
19309            self.request_autoscroll(autoscroll, cx);
19310        }
19311        cx.notify();
19312    }
19313
19314    pub fn replace_blocks(
19315        &mut self,
19316        renderers: HashMap<CustomBlockId, RenderBlock>,
19317        autoscroll: Option<Autoscroll>,
19318        cx: &mut Context<Self>,
19319    ) {
19320        self.display_map
19321            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19322        if let Some(autoscroll) = autoscroll {
19323            self.request_autoscroll(autoscroll, cx);
19324        }
19325        cx.notify();
19326    }
19327
19328    pub fn remove_blocks(
19329        &mut self,
19330        block_ids: HashSet<CustomBlockId>,
19331        autoscroll: Option<Autoscroll>,
19332        cx: &mut Context<Self>,
19333    ) {
19334        self.display_map.update(cx, |display_map, cx| {
19335            display_map.remove_blocks(block_ids, cx)
19336        });
19337        if let Some(autoscroll) = autoscroll {
19338            self.request_autoscroll(autoscroll, cx);
19339        }
19340        cx.notify();
19341    }
19342
19343    pub fn row_for_block(
19344        &self,
19345        block_id: CustomBlockId,
19346        cx: &mut Context<Self>,
19347    ) -> Option<DisplayRow> {
19348        self.display_map
19349            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19350    }
19351
19352    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19353        self.focused_block = Some(focused_block);
19354    }
19355
19356    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19357        self.focused_block.take()
19358    }
19359
19360    pub fn insert_creases(
19361        &mut self,
19362        creases: impl IntoIterator<Item = Crease<Anchor>>,
19363        cx: &mut Context<Self>,
19364    ) -> Vec<CreaseId> {
19365        self.display_map
19366            .update(cx, |map, cx| map.insert_creases(creases, cx))
19367    }
19368
19369    pub fn remove_creases(
19370        &mut self,
19371        ids: impl IntoIterator<Item = CreaseId>,
19372        cx: &mut Context<Self>,
19373    ) -> Vec<(CreaseId, Range<Anchor>)> {
19374        self.display_map
19375            .update(cx, |map, cx| map.remove_creases(ids, cx))
19376    }
19377
19378    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19379        self.display_map
19380            .update(cx, |map, cx| map.snapshot(cx))
19381            .longest_row()
19382    }
19383
19384    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19385        self.display_map
19386            .update(cx, |map, cx| map.snapshot(cx))
19387            .max_point()
19388    }
19389
19390    pub fn text(&self, cx: &App) -> String {
19391        self.buffer.read(cx).read(cx).text()
19392    }
19393
19394    pub fn is_empty(&self, cx: &App) -> bool {
19395        self.buffer.read(cx).read(cx).is_empty()
19396    }
19397
19398    pub fn text_option(&self, cx: &App) -> Option<String> {
19399        let text = self.text(cx);
19400        let text = text.trim();
19401
19402        if text.is_empty() {
19403            return None;
19404        }
19405
19406        Some(text.to_string())
19407    }
19408
19409    pub fn set_text(
19410        &mut self,
19411        text: impl Into<Arc<str>>,
19412        window: &mut Window,
19413        cx: &mut Context<Self>,
19414    ) {
19415        self.transact(window, cx, |this, _, cx| {
19416            this.buffer
19417                .read(cx)
19418                .as_singleton()
19419                .expect("you can only call set_text on editors for singleton buffers")
19420                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19421        });
19422    }
19423
19424    pub fn display_text(&self, cx: &mut App) -> String {
19425        self.display_map
19426            .update(cx, |map, cx| map.snapshot(cx))
19427            .text()
19428    }
19429
19430    fn create_minimap(
19431        &self,
19432        minimap_settings: MinimapSettings,
19433        window: &mut Window,
19434        cx: &mut Context<Self>,
19435    ) -> Option<Entity<Self>> {
19436        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19437            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19438    }
19439
19440    fn initialize_new_minimap(
19441        &self,
19442        minimap_settings: MinimapSettings,
19443        window: &mut Window,
19444        cx: &mut Context<Self>,
19445    ) -> Entity<Self> {
19446        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19447
19448        let mut minimap = Editor::new_internal(
19449            EditorMode::Minimap {
19450                parent: cx.weak_entity(),
19451            },
19452            self.buffer.clone(),
19453            None,
19454            Some(self.display_map.clone()),
19455            window,
19456            cx,
19457        );
19458        minimap.scroll_manager.clone_state(&self.scroll_manager);
19459        minimap.set_text_style_refinement(TextStyleRefinement {
19460            font_size: Some(MINIMAP_FONT_SIZE),
19461            font_weight: Some(MINIMAP_FONT_WEIGHT),
19462            ..Default::default()
19463        });
19464        minimap.update_minimap_configuration(minimap_settings, cx);
19465        cx.new(|_| minimap)
19466    }
19467
19468    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19469        let current_line_highlight = minimap_settings
19470            .current_line_highlight
19471            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19472        self.set_current_line_highlight(Some(current_line_highlight));
19473    }
19474
19475    pub fn minimap(&self) -> Option<&Entity<Self>> {
19476        self.minimap
19477            .as_ref()
19478            .filter(|_| self.minimap_visibility.visible())
19479    }
19480
19481    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19482        let mut wrap_guides = smallvec![];
19483
19484        if self.show_wrap_guides == Some(false) {
19485            return wrap_guides;
19486        }
19487
19488        let settings = self.buffer.read(cx).language_settings(cx);
19489        if settings.show_wrap_guides {
19490            match self.soft_wrap_mode(cx) {
19491                SoftWrap::Column(soft_wrap) => {
19492                    wrap_guides.push((soft_wrap as usize, true));
19493                }
19494                SoftWrap::Bounded(soft_wrap) => {
19495                    wrap_guides.push((soft_wrap as usize, true));
19496                }
19497                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19498            }
19499            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19500        }
19501
19502        wrap_guides
19503    }
19504
19505    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19506        let settings = self.buffer.read(cx).language_settings(cx);
19507        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19508        match mode {
19509            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19510                SoftWrap::None
19511            }
19512            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19513            language_settings::SoftWrap::PreferredLineLength => {
19514                SoftWrap::Column(settings.preferred_line_length)
19515            }
19516            language_settings::SoftWrap::Bounded => {
19517                SoftWrap::Bounded(settings.preferred_line_length)
19518            }
19519        }
19520    }
19521
19522    pub fn set_soft_wrap_mode(
19523        &mut self,
19524        mode: language_settings::SoftWrap,
19525
19526        cx: &mut Context<Self>,
19527    ) {
19528        self.soft_wrap_mode_override = Some(mode);
19529        cx.notify();
19530    }
19531
19532    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19533        self.hard_wrap = hard_wrap;
19534        cx.notify();
19535    }
19536
19537    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19538        self.text_style_refinement = Some(style);
19539    }
19540
19541    /// called by the Element so we know what style we were most recently rendered with.
19542    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19543        // We intentionally do not inform the display map about the minimap style
19544        // so that wrapping is not recalculated and stays consistent for the editor
19545        // and its linked minimap.
19546        if !self.mode.is_minimap() {
19547            let font = style.text.font();
19548            let font_size = style.text.font_size.to_pixels(window.rem_size());
19549            let display_map = self
19550                .placeholder_display_map
19551                .as_ref()
19552                .filter(|_| self.is_empty(cx))
19553                .unwrap_or(&self.display_map);
19554
19555            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19556        }
19557        self.style = Some(style);
19558    }
19559
19560    pub fn style(&self) -> Option<&EditorStyle> {
19561        self.style.as_ref()
19562    }
19563
19564    // Called by the element. This method is not designed to be called outside of the editor
19565    // element's layout code because it does not notify when rewrapping is computed synchronously.
19566    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19567        if self.is_empty(cx) {
19568            self.placeholder_display_map
19569                .as_ref()
19570                .map_or(false, |display_map| {
19571                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19572                })
19573        } else {
19574            self.display_map
19575                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19576        }
19577    }
19578
19579    pub fn set_soft_wrap(&mut self) {
19580        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19581    }
19582
19583    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19584        if self.soft_wrap_mode_override.is_some() {
19585            self.soft_wrap_mode_override.take();
19586        } else {
19587            let soft_wrap = match self.soft_wrap_mode(cx) {
19588                SoftWrap::GitDiff => return,
19589                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19590                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19591                    language_settings::SoftWrap::None
19592                }
19593            };
19594            self.soft_wrap_mode_override = Some(soft_wrap);
19595        }
19596        cx.notify();
19597    }
19598
19599    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19600        let Some(workspace) = self.workspace() else {
19601            return;
19602        };
19603        let fs = workspace.read(cx).app_state().fs.clone();
19604        let current_show = TabBarSettings::get_global(cx).show;
19605        update_settings_file(fs, cx, move |setting, _| {
19606            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19607        });
19608    }
19609
19610    pub fn toggle_indent_guides(
19611        &mut self,
19612        _: &ToggleIndentGuides,
19613        _: &mut Window,
19614        cx: &mut Context<Self>,
19615    ) {
19616        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19617            self.buffer
19618                .read(cx)
19619                .language_settings(cx)
19620                .indent_guides
19621                .enabled
19622        });
19623        self.show_indent_guides = Some(!currently_enabled);
19624        cx.notify();
19625    }
19626
19627    fn should_show_indent_guides(&self) -> Option<bool> {
19628        self.show_indent_guides
19629    }
19630
19631    pub fn toggle_line_numbers(
19632        &mut self,
19633        _: &ToggleLineNumbers,
19634        _: &mut Window,
19635        cx: &mut Context<Self>,
19636    ) {
19637        let mut editor_settings = EditorSettings::get_global(cx).clone();
19638        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19639        EditorSettings::override_global(editor_settings, cx);
19640    }
19641
19642    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19643        if let Some(show_line_numbers) = self.show_line_numbers {
19644            return show_line_numbers;
19645        }
19646        EditorSettings::get_global(cx).gutter.line_numbers
19647    }
19648
19649    pub fn relative_line_numbers(&self, cx: &mut App) -> RelativeLineNumbers {
19650        match (
19651            self.use_relative_line_numbers,
19652            EditorSettings::get_global(cx).relative_line_numbers,
19653        ) {
19654            (None, setting) => setting,
19655            (Some(false), _) => RelativeLineNumbers::Disabled,
19656            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
19657            (Some(true), _) => RelativeLineNumbers::Enabled,
19658        }
19659    }
19660
19661    pub fn toggle_relative_line_numbers(
19662        &mut self,
19663        _: &ToggleRelativeLineNumbers,
19664        _: &mut Window,
19665        cx: &mut Context<Self>,
19666    ) {
19667        let is_relative = self.relative_line_numbers(cx);
19668        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
19669    }
19670
19671    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19672        self.use_relative_line_numbers = is_relative;
19673        cx.notify();
19674    }
19675
19676    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19677        self.show_gutter = show_gutter;
19678        cx.notify();
19679    }
19680
19681    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19682        self.show_scrollbars = ScrollbarAxes {
19683            horizontal: show,
19684            vertical: show,
19685        };
19686        cx.notify();
19687    }
19688
19689    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19690        self.show_scrollbars.vertical = show;
19691        cx.notify();
19692    }
19693
19694    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19695        self.show_scrollbars.horizontal = show;
19696        cx.notify();
19697    }
19698
19699    pub fn set_minimap_visibility(
19700        &mut self,
19701        minimap_visibility: MinimapVisibility,
19702        window: &mut Window,
19703        cx: &mut Context<Self>,
19704    ) {
19705        if self.minimap_visibility != minimap_visibility {
19706            if minimap_visibility.visible() && self.minimap.is_none() {
19707                let minimap_settings = EditorSettings::get_global(cx).minimap;
19708                self.minimap =
19709                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19710            }
19711            self.minimap_visibility = minimap_visibility;
19712            cx.notify();
19713        }
19714    }
19715
19716    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19717        self.set_show_scrollbars(false, cx);
19718        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19719    }
19720
19721    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19722        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19723    }
19724
19725    /// Normally the text in full mode and auto height editors is padded on the
19726    /// left side by roughly half a character width for improved hit testing.
19727    ///
19728    /// Use this method to disable this for cases where this is not wanted (e.g.
19729    /// if you want to align the editor text with some other text above or below)
19730    /// or if you want to add this padding to single-line editors.
19731    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19732        self.offset_content = offset_content;
19733        cx.notify();
19734    }
19735
19736    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19737        self.show_line_numbers = Some(show_line_numbers);
19738        cx.notify();
19739    }
19740
19741    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19742        self.disable_expand_excerpt_buttons = true;
19743        cx.notify();
19744    }
19745
19746    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19747        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19748        cx.notify();
19749    }
19750
19751    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19752        self.show_code_actions = Some(show_code_actions);
19753        cx.notify();
19754    }
19755
19756    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19757        self.show_runnables = Some(show_runnables);
19758        cx.notify();
19759    }
19760
19761    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19762        self.show_breakpoints = Some(show_breakpoints);
19763        cx.notify();
19764    }
19765
19766    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19767        if self.display_map.read(cx).masked != masked {
19768            self.display_map.update(cx, |map, _| map.masked = masked);
19769        }
19770        cx.notify()
19771    }
19772
19773    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19774        self.show_wrap_guides = Some(show_wrap_guides);
19775        cx.notify();
19776    }
19777
19778    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19779        self.show_indent_guides = Some(show_indent_guides);
19780        cx.notify();
19781    }
19782
19783    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19784        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19785            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19786                && let Some(dir) = file.abs_path(cx).parent()
19787            {
19788                return Some(dir.to_owned());
19789            }
19790        }
19791
19792        None
19793    }
19794
19795    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19796        self.active_excerpt(cx)?
19797            .1
19798            .read(cx)
19799            .file()
19800            .and_then(|f| f.as_local())
19801    }
19802
19803    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19804        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19805            let buffer = buffer.read(cx);
19806            if let Some(project_path) = buffer.project_path(cx) {
19807                let project = self.project()?.read(cx);
19808                project.absolute_path(&project_path, cx)
19809            } else {
19810                buffer
19811                    .file()
19812                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19813            }
19814        })
19815    }
19816
19817    pub fn reveal_in_finder(
19818        &mut self,
19819        _: &RevealInFileManager,
19820        _window: &mut Window,
19821        cx: &mut Context<Self>,
19822    ) {
19823        if let Some(target) = self.target_file(cx) {
19824            cx.reveal_path(&target.abs_path(cx));
19825        }
19826    }
19827
19828    pub fn copy_path(
19829        &mut self,
19830        _: &zed_actions::workspace::CopyPath,
19831        _window: &mut Window,
19832        cx: &mut Context<Self>,
19833    ) {
19834        if let Some(path) = self.target_file_abs_path(cx)
19835            && let Some(path) = path.to_str()
19836        {
19837            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19838        } else {
19839            cx.propagate();
19840        }
19841    }
19842
19843    pub fn copy_relative_path(
19844        &mut self,
19845        _: &zed_actions::workspace::CopyRelativePath,
19846        _window: &mut Window,
19847        cx: &mut Context<Self>,
19848    ) {
19849        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19850            let project = self.project()?.read(cx);
19851            let path = buffer.read(cx).file()?.path();
19852            let path = path.display(project.path_style(cx));
19853            Some(path)
19854        }) {
19855            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19856        } else {
19857            cx.propagate();
19858        }
19859    }
19860
19861    /// Returns the project path for the editor's buffer, if any buffer is
19862    /// opened in the editor.
19863    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19864        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19865            buffer.read(cx).project_path(cx)
19866        } else {
19867            None
19868        }
19869    }
19870
19871    // Returns true if the editor handled a go-to-line request
19872    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19873        maybe!({
19874            let breakpoint_store = self.breakpoint_store.as_ref()?;
19875
19876            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19877            else {
19878                self.clear_row_highlights::<ActiveDebugLine>();
19879                return None;
19880            };
19881
19882            let position = active_stack_frame.position;
19883            let buffer_id = position.buffer_id?;
19884            let snapshot = self
19885                .project
19886                .as_ref()?
19887                .read(cx)
19888                .buffer_for_id(buffer_id, cx)?
19889                .read(cx)
19890                .snapshot();
19891
19892            let mut handled = false;
19893            for (id, ExcerptRange { context, .. }) in
19894                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19895            {
19896                if context.start.cmp(&position, &snapshot).is_ge()
19897                    || context.end.cmp(&position, &snapshot).is_lt()
19898                {
19899                    continue;
19900                }
19901                let snapshot = self.buffer.read(cx).snapshot(cx);
19902                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19903
19904                handled = true;
19905                self.clear_row_highlights::<ActiveDebugLine>();
19906
19907                self.go_to_line::<ActiveDebugLine>(
19908                    multibuffer_anchor,
19909                    Some(cx.theme().colors().editor_debugger_active_line_background),
19910                    window,
19911                    cx,
19912                );
19913
19914                cx.notify();
19915            }
19916
19917            handled.then_some(())
19918        })
19919        .is_some()
19920    }
19921
19922    pub fn copy_file_name_without_extension(
19923        &mut self,
19924        _: &CopyFileNameWithoutExtension,
19925        _: &mut Window,
19926        cx: &mut Context<Self>,
19927    ) {
19928        if let Some(file) = self.target_file(cx)
19929            && let Some(file_stem) = file.path().file_stem()
19930        {
19931            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
19932        }
19933    }
19934
19935    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19936        if let Some(file) = self.target_file(cx)
19937            && let Some(name) = file.path().file_name()
19938        {
19939            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19940        }
19941    }
19942
19943    pub fn toggle_git_blame(
19944        &mut self,
19945        _: &::git::Blame,
19946        window: &mut Window,
19947        cx: &mut Context<Self>,
19948    ) {
19949        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19950
19951        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19952            self.start_git_blame(true, window, cx);
19953        }
19954
19955        cx.notify();
19956    }
19957
19958    pub fn toggle_git_blame_inline(
19959        &mut self,
19960        _: &ToggleGitBlameInline,
19961        window: &mut Window,
19962        cx: &mut Context<Self>,
19963    ) {
19964        self.toggle_git_blame_inline_internal(true, window, cx);
19965        cx.notify();
19966    }
19967
19968    pub fn open_git_blame_commit(
19969        &mut self,
19970        _: &OpenGitBlameCommit,
19971        window: &mut Window,
19972        cx: &mut Context<Self>,
19973    ) {
19974        self.open_git_blame_commit_internal(window, cx);
19975    }
19976
19977    fn open_git_blame_commit_internal(
19978        &mut self,
19979        window: &mut Window,
19980        cx: &mut Context<Self>,
19981    ) -> Option<()> {
19982        let blame = self.blame.as_ref()?;
19983        let snapshot = self.snapshot(window, cx);
19984        let cursor = self
19985            .selections
19986            .newest::<Point>(&snapshot.display_snapshot)
19987            .head();
19988        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
19989        let (_, blame_entry) = blame
19990            .update(cx, |blame, cx| {
19991                blame
19992                    .blame_for_rows(
19993                        &[RowInfo {
19994                            buffer_id: Some(buffer.remote_id()),
19995                            buffer_row: Some(point.row),
19996                            ..Default::default()
19997                        }],
19998                        cx,
19999                    )
20000                    .next()
20001            })
20002            .flatten()?;
20003        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20004        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
20005        let workspace = self.workspace()?.downgrade();
20006        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
20007        None
20008    }
20009
20010    pub fn git_blame_inline_enabled(&self) -> bool {
20011        self.git_blame_inline_enabled
20012    }
20013
20014    pub fn toggle_selection_menu(
20015        &mut self,
20016        _: &ToggleSelectionMenu,
20017        _: &mut Window,
20018        cx: &mut Context<Self>,
20019    ) {
20020        self.show_selection_menu = self
20021            .show_selection_menu
20022            .map(|show_selections_menu| !show_selections_menu)
20023            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
20024
20025        cx.notify();
20026    }
20027
20028    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
20029        self.show_selection_menu
20030            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
20031    }
20032
20033    fn start_git_blame(
20034        &mut self,
20035        user_triggered: bool,
20036        window: &mut Window,
20037        cx: &mut Context<Self>,
20038    ) {
20039        if let Some(project) = self.project() {
20040            if let Some(buffer) = self.buffer().read(cx).as_singleton()
20041                && buffer.read(cx).file().is_none()
20042            {
20043                return;
20044            }
20045
20046            let focused = self.focus_handle(cx).contains_focused(window, cx);
20047
20048            let project = project.clone();
20049            let blame = cx
20050                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
20051            self.blame_subscription =
20052                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
20053            self.blame = Some(blame);
20054        }
20055    }
20056
20057    fn toggle_git_blame_inline_internal(
20058        &mut self,
20059        user_triggered: bool,
20060        window: &mut Window,
20061        cx: &mut Context<Self>,
20062    ) {
20063        if self.git_blame_inline_enabled {
20064            self.git_blame_inline_enabled = false;
20065            self.show_git_blame_inline = false;
20066            self.show_git_blame_inline_delay_task.take();
20067        } else {
20068            self.git_blame_inline_enabled = true;
20069            self.start_git_blame_inline(user_triggered, window, cx);
20070        }
20071
20072        cx.notify();
20073    }
20074
20075    fn start_git_blame_inline(
20076        &mut self,
20077        user_triggered: bool,
20078        window: &mut Window,
20079        cx: &mut Context<Self>,
20080    ) {
20081        self.start_git_blame(user_triggered, window, cx);
20082
20083        if ProjectSettings::get_global(cx)
20084            .git
20085            .inline_blame_delay()
20086            .is_some()
20087        {
20088            self.start_inline_blame_timer(window, cx);
20089        } else {
20090            self.show_git_blame_inline = true
20091        }
20092    }
20093
20094    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
20095        self.blame.as_ref()
20096    }
20097
20098    pub fn show_git_blame_gutter(&self) -> bool {
20099        self.show_git_blame_gutter
20100    }
20101
20102    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
20103        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
20104    }
20105
20106    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
20107        self.show_git_blame_inline
20108            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
20109            && !self.newest_selection_head_on_empty_line(cx)
20110            && self.has_blame_entries(cx)
20111    }
20112
20113    fn has_blame_entries(&self, cx: &App) -> bool {
20114        self.blame()
20115            .is_some_and(|blame| blame.read(cx).has_generated_entries())
20116    }
20117
20118    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
20119        let cursor_anchor = self.selections.newest_anchor().head();
20120
20121        let snapshot = self.buffer.read(cx).snapshot(cx);
20122        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
20123
20124        snapshot.line_len(buffer_row) == 0
20125    }
20126
20127    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
20128        let buffer_and_selection = maybe!({
20129            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20130            let selection_range = selection.range();
20131
20132            let multi_buffer = self.buffer().read(cx);
20133            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20134            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
20135
20136            let (buffer, range, _) = if selection.reversed {
20137                buffer_ranges.first()
20138            } else {
20139                buffer_ranges.last()
20140            }?;
20141
20142            let selection = text::ToPoint::to_point(&range.start, buffer).row
20143                ..text::ToPoint::to_point(&range.end, buffer).row;
20144            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
20145        });
20146
20147        let Some((buffer, selection)) = buffer_and_selection else {
20148            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
20149        };
20150
20151        let Some(project) = self.project() else {
20152            return Task::ready(Err(anyhow!("editor does not have project")));
20153        };
20154
20155        project.update(cx, |project, cx| {
20156            project.get_permalink_to_line(&buffer, selection, cx)
20157        })
20158    }
20159
20160    pub fn copy_permalink_to_line(
20161        &mut self,
20162        _: &CopyPermalinkToLine,
20163        window: &mut Window,
20164        cx: &mut Context<Self>,
20165    ) {
20166        let permalink_task = self.get_permalink_to_line(cx);
20167        let workspace = self.workspace();
20168
20169        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20170            Ok(permalink) => {
20171                cx.update(|_, cx| {
20172                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
20173                })
20174                .ok();
20175            }
20176            Err(err) => {
20177                let message = format!("Failed to copy permalink: {err}");
20178
20179                anyhow::Result::<()>::Err(err).log_err();
20180
20181                if let Some(workspace) = workspace {
20182                    workspace
20183                        .update_in(cx, |workspace, _, cx| {
20184                            struct CopyPermalinkToLine;
20185
20186                            workspace.show_toast(
20187                                Toast::new(
20188                                    NotificationId::unique::<CopyPermalinkToLine>(),
20189                                    message,
20190                                ),
20191                                cx,
20192                            )
20193                        })
20194                        .ok();
20195                }
20196            }
20197        })
20198        .detach();
20199    }
20200
20201    pub fn copy_file_location(
20202        &mut self,
20203        _: &CopyFileLocation,
20204        _: &mut Window,
20205        cx: &mut Context<Self>,
20206    ) {
20207        let selection = self
20208            .selections
20209            .newest::<Point>(&self.display_snapshot(cx))
20210            .start
20211            .row
20212            + 1;
20213        if let Some(file) = self.target_file(cx) {
20214            let path = file.path().display(file.path_style(cx));
20215            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
20216        }
20217    }
20218
20219    pub fn open_permalink_to_line(
20220        &mut self,
20221        _: &OpenPermalinkToLine,
20222        window: &mut Window,
20223        cx: &mut Context<Self>,
20224    ) {
20225        let permalink_task = self.get_permalink_to_line(cx);
20226        let workspace = self.workspace();
20227
20228        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20229            Ok(permalink) => {
20230                cx.update(|_, cx| {
20231                    cx.open_url(permalink.as_ref());
20232                })
20233                .ok();
20234            }
20235            Err(err) => {
20236                let message = format!("Failed to open permalink: {err}");
20237
20238                anyhow::Result::<()>::Err(err).log_err();
20239
20240                if let Some(workspace) = workspace {
20241                    workspace
20242                        .update(cx, |workspace, cx| {
20243                            struct OpenPermalinkToLine;
20244
20245                            workspace.show_toast(
20246                                Toast::new(
20247                                    NotificationId::unique::<OpenPermalinkToLine>(),
20248                                    message,
20249                                ),
20250                                cx,
20251                            )
20252                        })
20253                        .ok();
20254                }
20255            }
20256        })
20257        .detach();
20258    }
20259
20260    pub fn insert_uuid_v4(
20261        &mut self,
20262        _: &InsertUuidV4,
20263        window: &mut Window,
20264        cx: &mut Context<Self>,
20265    ) {
20266        self.insert_uuid(UuidVersion::V4, window, cx);
20267    }
20268
20269    pub fn insert_uuid_v7(
20270        &mut self,
20271        _: &InsertUuidV7,
20272        window: &mut Window,
20273        cx: &mut Context<Self>,
20274    ) {
20275        self.insert_uuid(UuidVersion::V7, window, cx);
20276    }
20277
20278    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20279        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20280        self.transact(window, cx, |this, window, cx| {
20281            let edits = this
20282                .selections
20283                .all::<Point>(&this.display_snapshot(cx))
20284                .into_iter()
20285                .map(|selection| {
20286                    let uuid = match version {
20287                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20288                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20289                    };
20290
20291                    (selection.range(), uuid.to_string())
20292                });
20293            this.edit(edits, cx);
20294            this.refresh_edit_prediction(true, false, window, cx);
20295        });
20296    }
20297
20298    pub fn open_selections_in_multibuffer(
20299        &mut self,
20300        _: &OpenSelectionsInMultibuffer,
20301        window: &mut Window,
20302        cx: &mut Context<Self>,
20303    ) {
20304        let multibuffer = self.buffer.read(cx);
20305
20306        let Some(buffer) = multibuffer.as_singleton() else {
20307            return;
20308        };
20309
20310        let Some(workspace) = self.workspace() else {
20311            return;
20312        };
20313
20314        let title = multibuffer.title(cx).to_string();
20315
20316        let locations = self
20317            .selections
20318            .all_anchors(&self.display_snapshot(cx))
20319            .iter()
20320            .map(|selection| {
20321                (
20322                    buffer.clone(),
20323                    (selection.start.text_anchor..selection.end.text_anchor)
20324                        .to_point(buffer.read(cx)),
20325                )
20326            })
20327            .into_group_map();
20328
20329        cx.spawn_in(window, async move |_, cx| {
20330            workspace.update_in(cx, |workspace, window, cx| {
20331                Self::open_locations_in_multibuffer(
20332                    workspace,
20333                    locations,
20334                    format!("Selections for '{title}'"),
20335                    false,
20336                    MultibufferSelectionMode::All,
20337                    window,
20338                    cx,
20339                );
20340            })
20341        })
20342        .detach();
20343    }
20344
20345    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20346    /// last highlight added will be used.
20347    ///
20348    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20349    pub fn highlight_rows<T: 'static>(
20350        &mut self,
20351        range: Range<Anchor>,
20352        color: Hsla,
20353        options: RowHighlightOptions,
20354        cx: &mut Context<Self>,
20355    ) {
20356        let snapshot = self.buffer().read(cx).snapshot(cx);
20357        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20358        let ix = row_highlights.binary_search_by(|highlight| {
20359            Ordering::Equal
20360                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20361                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20362        });
20363
20364        if let Err(mut ix) = ix {
20365            let index = post_inc(&mut self.highlight_order);
20366
20367            // If this range intersects with the preceding highlight, then merge it with
20368            // the preceding highlight. Otherwise insert a new highlight.
20369            let mut merged = false;
20370            if ix > 0 {
20371                let prev_highlight = &mut row_highlights[ix - 1];
20372                if prev_highlight
20373                    .range
20374                    .end
20375                    .cmp(&range.start, &snapshot)
20376                    .is_ge()
20377                {
20378                    ix -= 1;
20379                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20380                        prev_highlight.range.end = range.end;
20381                    }
20382                    merged = true;
20383                    prev_highlight.index = index;
20384                    prev_highlight.color = color;
20385                    prev_highlight.options = options;
20386                }
20387            }
20388
20389            if !merged {
20390                row_highlights.insert(
20391                    ix,
20392                    RowHighlight {
20393                        range,
20394                        index,
20395                        color,
20396                        options,
20397                        type_id: TypeId::of::<T>(),
20398                    },
20399                );
20400            }
20401
20402            // If any of the following highlights intersect with this one, merge them.
20403            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20404                let highlight = &row_highlights[ix];
20405                if next_highlight
20406                    .range
20407                    .start
20408                    .cmp(&highlight.range.end, &snapshot)
20409                    .is_le()
20410                {
20411                    if next_highlight
20412                        .range
20413                        .end
20414                        .cmp(&highlight.range.end, &snapshot)
20415                        .is_gt()
20416                    {
20417                        row_highlights[ix].range.end = next_highlight.range.end;
20418                    }
20419                    row_highlights.remove(ix + 1);
20420                } else {
20421                    break;
20422                }
20423            }
20424        }
20425    }
20426
20427    /// Remove any highlighted row ranges of the given type that intersect the
20428    /// given ranges.
20429    pub fn remove_highlighted_rows<T: 'static>(
20430        &mut self,
20431        ranges_to_remove: Vec<Range<Anchor>>,
20432        cx: &mut Context<Self>,
20433    ) {
20434        let snapshot = self.buffer().read(cx).snapshot(cx);
20435        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20436        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20437        row_highlights.retain(|highlight| {
20438            while let Some(range_to_remove) = ranges_to_remove.peek() {
20439                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20440                    Ordering::Less | Ordering::Equal => {
20441                        ranges_to_remove.next();
20442                    }
20443                    Ordering::Greater => {
20444                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20445                            Ordering::Less | Ordering::Equal => {
20446                                return false;
20447                            }
20448                            Ordering::Greater => break,
20449                        }
20450                    }
20451                }
20452            }
20453
20454            true
20455        })
20456    }
20457
20458    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20459    pub fn clear_row_highlights<T: 'static>(&mut self) {
20460        self.highlighted_rows.remove(&TypeId::of::<T>());
20461    }
20462
20463    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20464    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20465        self.highlighted_rows
20466            .get(&TypeId::of::<T>())
20467            .map_or(&[] as &[_], |vec| vec.as_slice())
20468            .iter()
20469            .map(|highlight| (highlight.range.clone(), highlight.color))
20470    }
20471
20472    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20473    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20474    /// Allows to ignore certain kinds of highlights.
20475    pub fn highlighted_display_rows(
20476        &self,
20477        window: &mut Window,
20478        cx: &mut App,
20479    ) -> BTreeMap<DisplayRow, LineHighlight> {
20480        let snapshot = self.snapshot(window, cx);
20481        let mut used_highlight_orders = HashMap::default();
20482        self.highlighted_rows
20483            .iter()
20484            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20485            .fold(
20486                BTreeMap::<DisplayRow, LineHighlight>::new(),
20487                |mut unique_rows, highlight| {
20488                    let start = highlight.range.start.to_display_point(&snapshot);
20489                    let end = highlight.range.end.to_display_point(&snapshot);
20490                    let start_row = start.row().0;
20491                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20492                        && end.column() == 0
20493                    {
20494                        end.row().0.saturating_sub(1)
20495                    } else {
20496                        end.row().0
20497                    };
20498                    for row in start_row..=end_row {
20499                        let used_index =
20500                            used_highlight_orders.entry(row).or_insert(highlight.index);
20501                        if highlight.index >= *used_index {
20502                            *used_index = highlight.index;
20503                            unique_rows.insert(
20504                                DisplayRow(row),
20505                                LineHighlight {
20506                                    include_gutter: highlight.options.include_gutter,
20507                                    border: None,
20508                                    background: highlight.color.into(),
20509                                    type_id: Some(highlight.type_id),
20510                                },
20511                            );
20512                        }
20513                    }
20514                    unique_rows
20515                },
20516            )
20517    }
20518
20519    pub fn highlighted_display_row_for_autoscroll(
20520        &self,
20521        snapshot: &DisplaySnapshot,
20522    ) -> Option<DisplayRow> {
20523        self.highlighted_rows
20524            .values()
20525            .flat_map(|highlighted_rows| highlighted_rows.iter())
20526            .filter_map(|highlight| {
20527                if highlight.options.autoscroll {
20528                    Some(highlight.range.start.to_display_point(snapshot).row())
20529                } else {
20530                    None
20531                }
20532            })
20533            .min()
20534    }
20535
20536    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20537        self.highlight_background::<SearchWithinRange>(
20538            ranges,
20539            |colors| colors.colors().editor_document_highlight_read_background,
20540            cx,
20541        )
20542    }
20543
20544    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20545        self.breadcrumb_header = Some(new_header);
20546    }
20547
20548    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20549        self.clear_background_highlights::<SearchWithinRange>(cx);
20550    }
20551
20552    pub fn highlight_background<T: 'static>(
20553        &mut self,
20554        ranges: &[Range<Anchor>],
20555        color_fetcher: fn(&Theme) -> Hsla,
20556        cx: &mut Context<Self>,
20557    ) {
20558        self.background_highlights.insert(
20559            HighlightKey::Type(TypeId::of::<T>()),
20560            (color_fetcher, Arc::from(ranges)),
20561        );
20562        self.scrollbar_marker_state.dirty = true;
20563        cx.notify();
20564    }
20565
20566    pub fn highlight_background_key<T: 'static>(
20567        &mut self,
20568        key: usize,
20569        ranges: &[Range<Anchor>],
20570        color_fetcher: fn(&Theme) -> Hsla,
20571        cx: &mut Context<Self>,
20572    ) {
20573        self.background_highlights.insert(
20574            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20575            (color_fetcher, Arc::from(ranges)),
20576        );
20577        self.scrollbar_marker_state.dirty = true;
20578        cx.notify();
20579    }
20580
20581    pub fn clear_background_highlights<T: 'static>(
20582        &mut self,
20583        cx: &mut Context<Self>,
20584    ) -> Option<BackgroundHighlight> {
20585        let text_highlights = self
20586            .background_highlights
20587            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20588        if !text_highlights.1.is_empty() {
20589            self.scrollbar_marker_state.dirty = true;
20590            cx.notify();
20591        }
20592        Some(text_highlights)
20593    }
20594
20595    pub fn highlight_gutter<T: 'static>(
20596        &mut self,
20597        ranges: impl Into<Vec<Range<Anchor>>>,
20598        color_fetcher: fn(&App) -> Hsla,
20599        cx: &mut Context<Self>,
20600    ) {
20601        self.gutter_highlights
20602            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20603        cx.notify();
20604    }
20605
20606    pub fn clear_gutter_highlights<T: 'static>(
20607        &mut self,
20608        cx: &mut Context<Self>,
20609    ) -> Option<GutterHighlight> {
20610        cx.notify();
20611        self.gutter_highlights.remove(&TypeId::of::<T>())
20612    }
20613
20614    pub fn insert_gutter_highlight<T: 'static>(
20615        &mut self,
20616        range: Range<Anchor>,
20617        color_fetcher: fn(&App) -> Hsla,
20618        cx: &mut Context<Self>,
20619    ) {
20620        let snapshot = self.buffer().read(cx).snapshot(cx);
20621        let mut highlights = self
20622            .gutter_highlights
20623            .remove(&TypeId::of::<T>())
20624            .map(|(_, highlights)| highlights)
20625            .unwrap_or_default();
20626        let ix = highlights.binary_search_by(|highlight| {
20627            Ordering::Equal
20628                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20629                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20630        });
20631        if let Err(ix) = ix {
20632            highlights.insert(ix, range);
20633        }
20634        self.gutter_highlights
20635            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20636    }
20637
20638    pub fn remove_gutter_highlights<T: 'static>(
20639        &mut self,
20640        ranges_to_remove: Vec<Range<Anchor>>,
20641        cx: &mut Context<Self>,
20642    ) {
20643        let snapshot = self.buffer().read(cx).snapshot(cx);
20644        let Some((color_fetcher, mut gutter_highlights)) =
20645            self.gutter_highlights.remove(&TypeId::of::<T>())
20646        else {
20647            return;
20648        };
20649        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20650        gutter_highlights.retain(|highlight| {
20651            while let Some(range_to_remove) = ranges_to_remove.peek() {
20652                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20653                    Ordering::Less | Ordering::Equal => {
20654                        ranges_to_remove.next();
20655                    }
20656                    Ordering::Greater => {
20657                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20658                            Ordering::Less | Ordering::Equal => {
20659                                return false;
20660                            }
20661                            Ordering::Greater => break,
20662                        }
20663                    }
20664                }
20665            }
20666
20667            true
20668        });
20669        self.gutter_highlights
20670            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20671    }
20672
20673    #[cfg(feature = "test-support")]
20674    pub fn all_text_highlights(
20675        &self,
20676        window: &mut Window,
20677        cx: &mut Context<Self>,
20678    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20679        let snapshot = self.snapshot(window, cx);
20680        self.display_map.update(cx, |display_map, _| {
20681            display_map
20682                .all_text_highlights()
20683                .map(|highlight| {
20684                    let (style, ranges) = highlight.as_ref();
20685                    (
20686                        *style,
20687                        ranges
20688                            .iter()
20689                            .map(|range| range.clone().to_display_points(&snapshot))
20690                            .collect(),
20691                    )
20692                })
20693                .collect()
20694        })
20695    }
20696
20697    #[cfg(feature = "test-support")]
20698    pub fn all_text_background_highlights(
20699        &self,
20700        window: &mut Window,
20701        cx: &mut Context<Self>,
20702    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20703        let snapshot = self.snapshot(window, cx);
20704        let buffer = &snapshot.buffer_snapshot();
20705        let start = buffer.anchor_before(0);
20706        let end = buffer.anchor_after(buffer.len());
20707        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20708    }
20709
20710    #[cfg(any(test, feature = "test-support"))]
20711    pub fn sorted_background_highlights_in_range(
20712        &self,
20713        search_range: Range<Anchor>,
20714        display_snapshot: &DisplaySnapshot,
20715        theme: &Theme,
20716    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20717        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20718        res.sort_by(|a, b| {
20719            a.0.start
20720                .cmp(&b.0.start)
20721                .then_with(|| a.0.end.cmp(&b.0.end))
20722                .then_with(|| a.1.cmp(&b.1))
20723        });
20724        res
20725    }
20726
20727    #[cfg(feature = "test-support")]
20728    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20729        let snapshot = self.buffer().read(cx).snapshot(cx);
20730
20731        let highlights = self
20732            .background_highlights
20733            .get(&HighlightKey::Type(TypeId::of::<
20734                items::BufferSearchHighlights,
20735            >()));
20736
20737        if let Some((_color, ranges)) = highlights {
20738            ranges
20739                .iter()
20740                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20741                .collect_vec()
20742        } else {
20743            vec![]
20744        }
20745    }
20746
20747    fn document_highlights_for_position<'a>(
20748        &'a self,
20749        position: Anchor,
20750        buffer: &'a MultiBufferSnapshot,
20751    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20752        let read_highlights = self
20753            .background_highlights
20754            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20755            .map(|h| &h.1);
20756        let write_highlights = self
20757            .background_highlights
20758            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20759            .map(|h| &h.1);
20760        let left_position = position.bias_left(buffer);
20761        let right_position = position.bias_right(buffer);
20762        read_highlights
20763            .into_iter()
20764            .chain(write_highlights)
20765            .flat_map(move |ranges| {
20766                let start_ix = match ranges.binary_search_by(|probe| {
20767                    let cmp = probe.end.cmp(&left_position, buffer);
20768                    if cmp.is_ge() {
20769                        Ordering::Greater
20770                    } else {
20771                        Ordering::Less
20772                    }
20773                }) {
20774                    Ok(i) | Err(i) => i,
20775                };
20776
20777                ranges[start_ix..]
20778                    .iter()
20779                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20780            })
20781    }
20782
20783    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20784        self.background_highlights
20785            .get(&HighlightKey::Type(TypeId::of::<T>()))
20786            .is_some_and(|(_, highlights)| !highlights.is_empty())
20787    }
20788
20789    /// Returns all background highlights for a given range.
20790    ///
20791    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20792    pub fn background_highlights_in_range(
20793        &self,
20794        search_range: Range<Anchor>,
20795        display_snapshot: &DisplaySnapshot,
20796        theme: &Theme,
20797    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20798        let mut results = Vec::new();
20799        for (color_fetcher, ranges) in self.background_highlights.values() {
20800            let color = color_fetcher(theme);
20801            let start_ix = match ranges.binary_search_by(|probe| {
20802                let cmp = probe
20803                    .end
20804                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20805                if cmp.is_gt() {
20806                    Ordering::Greater
20807                } else {
20808                    Ordering::Less
20809                }
20810            }) {
20811                Ok(i) | Err(i) => i,
20812            };
20813            for range in &ranges[start_ix..] {
20814                if range
20815                    .start
20816                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20817                    .is_ge()
20818                {
20819                    break;
20820                }
20821
20822                let start = range.start.to_display_point(display_snapshot);
20823                let end = range.end.to_display_point(display_snapshot);
20824                results.push((start..end, color))
20825            }
20826        }
20827        results
20828    }
20829
20830    pub fn gutter_highlights_in_range(
20831        &self,
20832        search_range: Range<Anchor>,
20833        display_snapshot: &DisplaySnapshot,
20834        cx: &App,
20835    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20836        let mut results = Vec::new();
20837        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20838            let color = color_fetcher(cx);
20839            let start_ix = match ranges.binary_search_by(|probe| {
20840                let cmp = probe
20841                    .end
20842                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20843                if cmp.is_gt() {
20844                    Ordering::Greater
20845                } else {
20846                    Ordering::Less
20847                }
20848            }) {
20849                Ok(i) | Err(i) => i,
20850            };
20851            for range in &ranges[start_ix..] {
20852                if range
20853                    .start
20854                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20855                    .is_ge()
20856                {
20857                    break;
20858                }
20859
20860                let start = range.start.to_display_point(display_snapshot);
20861                let end = range.end.to_display_point(display_snapshot);
20862                results.push((start..end, color))
20863            }
20864        }
20865        results
20866    }
20867
20868    /// Get the text ranges corresponding to the redaction query
20869    pub fn redacted_ranges(
20870        &self,
20871        search_range: Range<Anchor>,
20872        display_snapshot: &DisplaySnapshot,
20873        cx: &App,
20874    ) -> Vec<Range<DisplayPoint>> {
20875        display_snapshot
20876            .buffer_snapshot()
20877            .redacted_ranges(search_range, |file| {
20878                if let Some(file) = file {
20879                    file.is_private()
20880                        && EditorSettings::get(
20881                            Some(SettingsLocation {
20882                                worktree_id: file.worktree_id(cx),
20883                                path: file.path().as_ref(),
20884                            }),
20885                            cx,
20886                        )
20887                        .redact_private_values
20888                } else {
20889                    false
20890                }
20891            })
20892            .map(|range| {
20893                range.start.to_display_point(display_snapshot)
20894                    ..range.end.to_display_point(display_snapshot)
20895            })
20896            .collect()
20897    }
20898
20899    pub fn highlight_text_key<T: 'static>(
20900        &mut self,
20901        key: usize,
20902        ranges: Vec<Range<Anchor>>,
20903        style: HighlightStyle,
20904        cx: &mut Context<Self>,
20905    ) {
20906        self.display_map.update(cx, |map, _| {
20907            map.highlight_text(
20908                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20909                ranges,
20910                style,
20911            );
20912        });
20913        cx.notify();
20914    }
20915
20916    pub fn highlight_text<T: 'static>(
20917        &mut self,
20918        ranges: Vec<Range<Anchor>>,
20919        style: HighlightStyle,
20920        cx: &mut Context<Self>,
20921    ) {
20922        self.display_map.update(cx, |map, _| {
20923            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20924        });
20925        cx.notify();
20926    }
20927
20928    pub fn text_highlights<'a, T: 'static>(
20929        &'a self,
20930        cx: &'a App,
20931    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20932        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20933    }
20934
20935    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20936        let cleared = self
20937            .display_map
20938            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20939        if cleared {
20940            cx.notify();
20941        }
20942    }
20943
20944    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20945        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20946            && self.focus_handle.is_focused(window)
20947    }
20948
20949    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20950        self.show_cursor_when_unfocused = is_enabled;
20951        cx.notify();
20952    }
20953
20954    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20955        cx.notify();
20956    }
20957
20958    fn on_debug_session_event(
20959        &mut self,
20960        _session: Entity<Session>,
20961        event: &SessionEvent,
20962        cx: &mut Context<Self>,
20963    ) {
20964        if let SessionEvent::InvalidateInlineValue = event {
20965            self.refresh_inline_values(cx);
20966        }
20967    }
20968
20969    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20970        let Some(project) = self.project.clone() else {
20971            return;
20972        };
20973
20974        if !self.inline_value_cache.enabled {
20975            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20976            self.splice_inlays(&inlays, Vec::new(), cx);
20977            return;
20978        }
20979
20980        let current_execution_position = self
20981            .highlighted_rows
20982            .get(&TypeId::of::<ActiveDebugLine>())
20983            .and_then(|lines| lines.last().map(|line| line.range.end));
20984
20985        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20986            let inline_values = editor
20987                .update(cx, |editor, cx| {
20988                    let Some(current_execution_position) = current_execution_position else {
20989                        return Some(Task::ready(Ok(Vec::new())));
20990                    };
20991
20992                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20993                        let snapshot = buffer.snapshot(cx);
20994
20995                        let excerpt = snapshot.excerpt_containing(
20996                            current_execution_position..current_execution_position,
20997                        )?;
20998
20999                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
21000                    })?;
21001
21002                    let range =
21003                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
21004
21005                    project.inline_values(buffer, range, cx)
21006                })
21007                .ok()
21008                .flatten()?
21009                .await
21010                .context("refreshing debugger inlays")
21011                .log_err()?;
21012
21013            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
21014
21015            for (buffer_id, inline_value) in inline_values
21016                .into_iter()
21017                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
21018            {
21019                buffer_inline_values
21020                    .entry(buffer_id)
21021                    .or_default()
21022                    .push(inline_value);
21023            }
21024
21025            editor
21026                .update(cx, |editor, cx| {
21027                    let snapshot = editor.buffer.read(cx).snapshot(cx);
21028                    let mut new_inlays = Vec::default();
21029
21030                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
21031                        let buffer_id = buffer_snapshot.remote_id();
21032                        buffer_inline_values
21033                            .get(&buffer_id)
21034                            .into_iter()
21035                            .flatten()
21036                            .for_each(|hint| {
21037                                let inlay = Inlay::debugger(
21038                                    post_inc(&mut editor.next_inlay_id),
21039                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
21040                                    hint.text(),
21041                                );
21042                                if !inlay.text().chars().contains(&'\n') {
21043                                    new_inlays.push(inlay);
21044                                }
21045                            });
21046                    }
21047
21048                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
21049                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
21050
21051                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
21052                })
21053                .ok()?;
21054            Some(())
21055        });
21056    }
21057
21058    fn on_buffer_event(
21059        &mut self,
21060        multibuffer: &Entity<MultiBuffer>,
21061        event: &multi_buffer::Event,
21062        window: &mut Window,
21063        cx: &mut Context<Self>,
21064    ) {
21065        match event {
21066            multi_buffer::Event::Edited { edited_buffer } => {
21067                self.scrollbar_marker_state.dirty = true;
21068                self.active_indent_guides_state.dirty = true;
21069                self.refresh_active_diagnostics(cx);
21070                self.refresh_code_actions(window, cx);
21071                self.refresh_selected_text_highlights(true, window, cx);
21072                self.refresh_single_line_folds(window, cx);
21073                self.refresh_matching_bracket_highlights(window, cx);
21074                if self.has_active_edit_prediction() {
21075                    self.update_visible_edit_prediction(window, cx);
21076                }
21077
21078                if let Some(buffer) = edited_buffer {
21079                    if buffer.read(cx).file().is_none() {
21080                        cx.emit(EditorEvent::TitleChanged);
21081                    }
21082
21083                    if self.project.is_some() {
21084                        let buffer_id = buffer.read(cx).remote_id();
21085                        self.register_buffer(buffer_id, cx);
21086                        self.update_lsp_data(Some(buffer_id), window, cx);
21087                        self.refresh_inlay_hints(
21088                            InlayHintRefreshReason::BufferEdited(buffer_id),
21089                            cx,
21090                        );
21091                    }
21092                }
21093
21094                cx.emit(EditorEvent::BufferEdited);
21095                cx.emit(SearchEvent::MatchesInvalidated);
21096
21097                let Some(project) = &self.project else { return };
21098                let (telemetry, is_via_ssh) = {
21099                    let project = project.read(cx);
21100                    let telemetry = project.client().telemetry().clone();
21101                    let is_via_ssh = project.is_via_remote_server();
21102                    (telemetry, is_via_ssh)
21103                };
21104                telemetry.log_edit_event("editor", is_via_ssh);
21105            }
21106            multi_buffer::Event::ExcerptsAdded {
21107                buffer,
21108                predecessor,
21109                excerpts,
21110            } => {
21111                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21112                let buffer_id = buffer.read(cx).remote_id();
21113                if self.buffer.read(cx).diff_for(buffer_id).is_none()
21114                    && let Some(project) = &self.project
21115                {
21116                    update_uncommitted_diff_for_buffer(
21117                        cx.entity(),
21118                        project,
21119                        [buffer.clone()],
21120                        self.buffer.clone(),
21121                        cx,
21122                    )
21123                    .detach();
21124                }
21125                self.update_lsp_data(Some(buffer_id), window, cx);
21126                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21127                cx.emit(EditorEvent::ExcerptsAdded {
21128                    buffer: buffer.clone(),
21129                    predecessor: *predecessor,
21130                    excerpts: excerpts.clone(),
21131                });
21132            }
21133            multi_buffer::Event::ExcerptsRemoved {
21134                ids,
21135                removed_buffer_ids,
21136            } => {
21137                if let Some(inlay_hints) = &mut self.inlay_hints {
21138                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
21139                }
21140                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
21141                for buffer_id in removed_buffer_ids {
21142                    self.registered_buffers.remove(buffer_id);
21143                }
21144                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21145                cx.emit(EditorEvent::ExcerptsRemoved {
21146                    ids: ids.clone(),
21147                    removed_buffer_ids: removed_buffer_ids.clone(),
21148                });
21149            }
21150            multi_buffer::Event::ExcerptsEdited {
21151                excerpt_ids,
21152                buffer_ids,
21153            } => {
21154                self.display_map.update(cx, |map, cx| {
21155                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
21156                });
21157                cx.emit(EditorEvent::ExcerptsEdited {
21158                    ids: excerpt_ids.clone(),
21159                });
21160            }
21161            multi_buffer::Event::ExcerptsExpanded { ids } => {
21162                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21163                self.refresh_document_highlights(cx);
21164                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
21165            }
21166            multi_buffer::Event::Reparsed(buffer_id) => {
21167                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21168                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21169
21170                cx.emit(EditorEvent::Reparsed(*buffer_id));
21171            }
21172            multi_buffer::Event::DiffHunksToggled => {
21173                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21174            }
21175            multi_buffer::Event::LanguageChanged(buffer_id) => {
21176                self.registered_buffers.remove(&buffer_id);
21177                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21178                cx.emit(EditorEvent::Reparsed(*buffer_id));
21179                cx.notify();
21180            }
21181            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
21182            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21183            multi_buffer::Event::FileHandleChanged
21184            | multi_buffer::Event::Reloaded
21185            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21186            multi_buffer::Event::DiagnosticsUpdated => {
21187                self.update_diagnostics_state(window, cx);
21188            }
21189            _ => {}
21190        };
21191    }
21192
21193    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21194        if !self.diagnostics_enabled() {
21195            return;
21196        }
21197        self.refresh_active_diagnostics(cx);
21198        self.refresh_inline_diagnostics(true, window, cx);
21199        self.scrollbar_marker_state.dirty = true;
21200        cx.notify();
21201    }
21202
21203    pub fn start_temporary_diff_override(&mut self) {
21204        self.load_diff_task.take();
21205        self.temporary_diff_override = true;
21206    }
21207
21208    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21209        self.temporary_diff_override = false;
21210        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21211        self.buffer.update(cx, |buffer, cx| {
21212            buffer.set_all_diff_hunks_collapsed(cx);
21213        });
21214
21215        if let Some(project) = self.project.clone() {
21216            self.load_diff_task = Some(
21217                update_uncommitted_diff_for_buffer(
21218                    cx.entity(),
21219                    &project,
21220                    self.buffer.read(cx).all_buffers(),
21221                    self.buffer.clone(),
21222                    cx,
21223                )
21224                .shared(),
21225            );
21226        }
21227    }
21228
21229    fn on_display_map_changed(
21230        &mut self,
21231        _: Entity<DisplayMap>,
21232        _: &mut Window,
21233        cx: &mut Context<Self>,
21234    ) {
21235        cx.notify();
21236    }
21237
21238    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21239        if self.diagnostics_enabled() {
21240            let new_severity = EditorSettings::get_global(cx)
21241                .diagnostics_max_severity
21242                .unwrap_or(DiagnosticSeverity::Hint);
21243            self.set_max_diagnostics_severity(new_severity, cx);
21244        }
21245        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21246        self.update_edit_prediction_settings(cx);
21247        self.refresh_edit_prediction(true, false, window, cx);
21248        self.refresh_inline_values(cx);
21249        self.refresh_inlay_hints(
21250            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21251                self.selections.newest_anchor().head(),
21252                &self.buffer.read(cx).snapshot(cx),
21253                cx,
21254            )),
21255            cx,
21256        );
21257
21258        let old_cursor_shape = self.cursor_shape;
21259        let old_show_breadcrumbs = self.show_breadcrumbs;
21260
21261        {
21262            let editor_settings = EditorSettings::get_global(cx);
21263            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21264            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21265            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21266            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21267        }
21268
21269        if old_cursor_shape != self.cursor_shape {
21270            cx.emit(EditorEvent::CursorShapeChanged);
21271        }
21272
21273        if old_show_breadcrumbs != self.show_breadcrumbs {
21274            cx.emit(EditorEvent::BreadcrumbsChanged);
21275        }
21276
21277        let project_settings = ProjectSettings::get_global(cx);
21278        self.buffer_serialization = self
21279            .should_serialize_buffer()
21280            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
21281
21282        if self.mode.is_full() {
21283            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21284            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21285            if self.show_inline_diagnostics != show_inline_diagnostics {
21286                self.show_inline_diagnostics = show_inline_diagnostics;
21287                self.refresh_inline_diagnostics(false, window, cx);
21288            }
21289
21290            if self.git_blame_inline_enabled != inline_blame_enabled {
21291                self.toggle_git_blame_inline_internal(false, window, cx);
21292            }
21293
21294            let minimap_settings = EditorSettings::get_global(cx).minimap;
21295            if self.minimap_visibility != MinimapVisibility::Disabled {
21296                if self.minimap_visibility.settings_visibility()
21297                    != minimap_settings.minimap_enabled()
21298                {
21299                    self.set_minimap_visibility(
21300                        MinimapVisibility::for_mode(self.mode(), cx),
21301                        window,
21302                        cx,
21303                    );
21304                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21305                    minimap_entity.update(cx, |minimap_editor, cx| {
21306                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21307                    })
21308                }
21309            }
21310        }
21311
21312        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21313            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21314        }) {
21315            if !inlay_splice.is_empty() {
21316                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21317            }
21318            self.refresh_colors_for_visible_range(None, window, cx);
21319        }
21320
21321        cx.notify();
21322    }
21323
21324    pub fn set_searchable(&mut self, searchable: bool) {
21325        self.searchable = searchable;
21326    }
21327
21328    pub fn searchable(&self) -> bool {
21329        self.searchable
21330    }
21331
21332    pub fn open_excerpts_in_split(
21333        &mut self,
21334        _: &OpenExcerptsSplit,
21335        window: &mut Window,
21336        cx: &mut Context<Self>,
21337    ) {
21338        self.open_excerpts_common(None, true, window, cx)
21339    }
21340
21341    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21342        self.open_excerpts_common(None, false, window, cx)
21343    }
21344
21345    fn open_excerpts_common(
21346        &mut self,
21347        jump_data: Option<JumpData>,
21348        split: bool,
21349        window: &mut Window,
21350        cx: &mut Context<Self>,
21351    ) {
21352        let Some(workspace) = self.workspace() else {
21353            cx.propagate();
21354            return;
21355        };
21356
21357        if self.buffer.read(cx).is_singleton() {
21358            cx.propagate();
21359            return;
21360        }
21361
21362        let mut new_selections_by_buffer = HashMap::default();
21363        match &jump_data {
21364            Some(JumpData::MultiBufferPoint {
21365                excerpt_id,
21366                position,
21367                anchor,
21368                line_offset_from_top,
21369            }) => {
21370                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21371                if let Some(buffer) = multi_buffer_snapshot
21372                    .buffer_id_for_excerpt(*excerpt_id)
21373                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21374                {
21375                    let buffer_snapshot = buffer.read(cx).snapshot();
21376                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21377                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21378                    } else {
21379                        buffer_snapshot.clip_point(*position, Bias::Left)
21380                    };
21381                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21382                    new_selections_by_buffer.insert(
21383                        buffer,
21384                        (
21385                            vec![jump_to_offset..jump_to_offset],
21386                            Some(*line_offset_from_top),
21387                        ),
21388                    );
21389                }
21390            }
21391            Some(JumpData::MultiBufferRow {
21392                row,
21393                line_offset_from_top,
21394            }) => {
21395                let point = MultiBufferPoint::new(row.0, 0);
21396                if let Some((buffer, buffer_point, _)) =
21397                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21398                {
21399                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21400                    new_selections_by_buffer
21401                        .entry(buffer)
21402                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21403                        .0
21404                        .push(buffer_offset..buffer_offset)
21405                }
21406            }
21407            None => {
21408                let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
21409                let multi_buffer = self.buffer.read(cx);
21410                for selection in selections {
21411                    for (snapshot, range, _, anchor) in multi_buffer
21412                        .snapshot(cx)
21413                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21414                    {
21415                        if let Some(anchor) = anchor {
21416                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21417                            else {
21418                                continue;
21419                            };
21420                            let offset = text::ToOffset::to_offset(
21421                                &anchor.text_anchor,
21422                                &buffer_handle.read(cx).snapshot(),
21423                            );
21424                            let range = offset..offset;
21425                            new_selections_by_buffer
21426                                .entry(buffer_handle)
21427                                .or_insert((Vec::new(), None))
21428                                .0
21429                                .push(range)
21430                        } else {
21431                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21432                            else {
21433                                continue;
21434                            };
21435                            new_selections_by_buffer
21436                                .entry(buffer_handle)
21437                                .or_insert((Vec::new(), None))
21438                                .0
21439                                .push(range)
21440                        }
21441                    }
21442                }
21443            }
21444        }
21445
21446        new_selections_by_buffer
21447            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21448
21449        if new_selections_by_buffer.is_empty() {
21450            return;
21451        }
21452
21453        // We defer the pane interaction because we ourselves are a workspace item
21454        // and activating a new item causes the pane to call a method on us reentrantly,
21455        // which panics if we're on the stack.
21456        window.defer(cx, move |window, cx| {
21457            workspace.update(cx, |workspace, cx| {
21458                let pane = if split {
21459                    workspace.adjacent_pane(window, cx)
21460                } else {
21461                    workspace.active_pane().clone()
21462                };
21463
21464                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21465                    let editor = buffer
21466                        .read(cx)
21467                        .file()
21468                        .is_none()
21469                        .then(|| {
21470                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21471                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21472                            // Instead, we try to activate the existing editor in the pane first.
21473                            let (editor, pane_item_index) =
21474                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21475                                    let editor = item.downcast::<Editor>()?;
21476                                    let singleton_buffer =
21477                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21478                                    if singleton_buffer == buffer {
21479                                        Some((editor, i))
21480                                    } else {
21481                                        None
21482                                    }
21483                                })?;
21484                            pane.update(cx, |pane, cx| {
21485                                pane.activate_item(pane_item_index, true, true, window, cx)
21486                            });
21487                            Some(editor)
21488                        })
21489                        .flatten()
21490                        .unwrap_or_else(|| {
21491                            workspace.open_project_item::<Self>(
21492                                pane.clone(),
21493                                buffer,
21494                                true,
21495                                true,
21496                                window,
21497                                cx,
21498                            )
21499                        });
21500
21501                    editor.update(cx, |editor, cx| {
21502                        let autoscroll = match scroll_offset {
21503                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21504                            None => Autoscroll::newest(),
21505                        };
21506                        let nav_history = editor.nav_history.take();
21507                        editor.change_selections(
21508                            SelectionEffects::scroll(autoscroll),
21509                            window,
21510                            cx,
21511                            |s| {
21512                                s.select_ranges(ranges);
21513                            },
21514                        );
21515                        editor.nav_history = nav_history;
21516                    });
21517                }
21518            })
21519        });
21520    }
21521
21522    // For now, don't allow opening excerpts in buffers that aren't backed by
21523    // regular project files.
21524    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21525        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21526    }
21527
21528    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21529        let snapshot = self.buffer.read(cx).read(cx);
21530        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21531        Some(
21532            ranges
21533                .iter()
21534                .map(move |range| {
21535                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21536                })
21537                .collect(),
21538        )
21539    }
21540
21541    fn selection_replacement_ranges(
21542        &self,
21543        range: Range<OffsetUtf16>,
21544        cx: &mut App,
21545    ) -> Vec<Range<OffsetUtf16>> {
21546        let selections = self
21547            .selections
21548            .all::<OffsetUtf16>(&self.display_snapshot(cx));
21549        let newest_selection = selections
21550            .iter()
21551            .max_by_key(|selection| selection.id)
21552            .unwrap();
21553        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21554        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21555        let snapshot = self.buffer.read(cx).read(cx);
21556        selections
21557            .into_iter()
21558            .map(|mut selection| {
21559                selection.start.0 =
21560                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21561                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21562                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21563                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21564            })
21565            .collect()
21566    }
21567
21568    fn report_editor_event(
21569        &self,
21570        reported_event: ReportEditorEvent,
21571        file_extension: Option<String>,
21572        cx: &App,
21573    ) {
21574        if cfg!(any(test, feature = "test-support")) {
21575            return;
21576        }
21577
21578        let Some(project) = &self.project else { return };
21579
21580        // If None, we are in a file without an extension
21581        let file = self
21582            .buffer
21583            .read(cx)
21584            .as_singleton()
21585            .and_then(|b| b.read(cx).file());
21586        let file_extension = file_extension.or(file
21587            .as_ref()
21588            .and_then(|file| Path::new(file.file_name(cx)).extension())
21589            .and_then(|e| e.to_str())
21590            .map(|a| a.to_string()));
21591
21592        let vim_mode = vim_flavor(cx).is_some();
21593
21594        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21595        let copilot_enabled = edit_predictions_provider
21596            == language::language_settings::EditPredictionProvider::Copilot;
21597        let copilot_enabled_for_language = self
21598            .buffer
21599            .read(cx)
21600            .language_settings(cx)
21601            .show_edit_predictions;
21602
21603        let project = project.read(cx);
21604        let event_type = reported_event.event_type();
21605
21606        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21607            telemetry::event!(
21608                event_type,
21609                type = if auto_saved {"autosave"} else {"manual"},
21610                file_extension,
21611                vim_mode,
21612                copilot_enabled,
21613                copilot_enabled_for_language,
21614                edit_predictions_provider,
21615                is_via_ssh = project.is_via_remote_server(),
21616            );
21617        } else {
21618            telemetry::event!(
21619                event_type,
21620                file_extension,
21621                vim_mode,
21622                copilot_enabled,
21623                copilot_enabled_for_language,
21624                edit_predictions_provider,
21625                is_via_ssh = project.is_via_remote_server(),
21626            );
21627        };
21628    }
21629
21630    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21631    /// with each line being an array of {text, highlight} objects.
21632    fn copy_highlight_json(
21633        &mut self,
21634        _: &CopyHighlightJson,
21635        window: &mut Window,
21636        cx: &mut Context<Self>,
21637    ) {
21638        #[derive(Serialize)]
21639        struct Chunk<'a> {
21640            text: String,
21641            highlight: Option<&'a str>,
21642        }
21643
21644        let snapshot = self.buffer.read(cx).snapshot(cx);
21645        let range = self
21646            .selected_text_range(false, window, cx)
21647            .and_then(|selection| {
21648                if selection.range.is_empty() {
21649                    None
21650                } else {
21651                    Some(
21652                        snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.start))
21653                            ..snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.end)),
21654                    )
21655                }
21656            })
21657            .unwrap_or_else(|| 0..snapshot.len());
21658
21659        let chunks = snapshot.chunks(range, true);
21660        let mut lines = Vec::new();
21661        let mut line: VecDeque<Chunk> = VecDeque::new();
21662
21663        let Some(style) = self.style.as_ref() else {
21664            return;
21665        };
21666
21667        for chunk in chunks {
21668            let highlight = chunk
21669                .syntax_highlight_id
21670                .and_then(|id| id.name(&style.syntax));
21671            let mut chunk_lines = chunk.text.split('\n').peekable();
21672            while let Some(text) = chunk_lines.next() {
21673                let mut merged_with_last_token = false;
21674                if let Some(last_token) = line.back_mut()
21675                    && last_token.highlight == highlight
21676                {
21677                    last_token.text.push_str(text);
21678                    merged_with_last_token = true;
21679                }
21680
21681                if !merged_with_last_token {
21682                    line.push_back(Chunk {
21683                        text: text.into(),
21684                        highlight,
21685                    });
21686                }
21687
21688                if chunk_lines.peek().is_some() {
21689                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21690                        line.pop_front();
21691                    }
21692                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21693                        line.pop_back();
21694                    }
21695
21696                    lines.push(mem::take(&mut line));
21697                }
21698            }
21699        }
21700
21701        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21702            return;
21703        };
21704        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21705    }
21706
21707    pub fn open_context_menu(
21708        &mut self,
21709        _: &OpenContextMenu,
21710        window: &mut Window,
21711        cx: &mut Context<Self>,
21712    ) {
21713        self.request_autoscroll(Autoscroll::newest(), cx);
21714        let position = self
21715            .selections
21716            .newest_display(&self.display_snapshot(cx))
21717            .start;
21718        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21719    }
21720
21721    pub fn replay_insert_event(
21722        &mut self,
21723        text: &str,
21724        relative_utf16_range: Option<Range<isize>>,
21725        window: &mut Window,
21726        cx: &mut Context<Self>,
21727    ) {
21728        if !self.input_enabled {
21729            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21730            return;
21731        }
21732        if let Some(relative_utf16_range) = relative_utf16_range {
21733            let selections = self
21734                .selections
21735                .all::<OffsetUtf16>(&self.display_snapshot(cx));
21736            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21737                let new_ranges = selections.into_iter().map(|range| {
21738                    let start = OffsetUtf16(
21739                        range
21740                            .head()
21741                            .0
21742                            .saturating_add_signed(relative_utf16_range.start),
21743                    );
21744                    let end = OffsetUtf16(
21745                        range
21746                            .head()
21747                            .0
21748                            .saturating_add_signed(relative_utf16_range.end),
21749                    );
21750                    start..end
21751                });
21752                s.select_ranges(new_ranges);
21753            });
21754        }
21755
21756        self.handle_input(text, window, cx);
21757    }
21758
21759    pub fn is_focused(&self, window: &Window) -> bool {
21760        self.focus_handle.is_focused(window)
21761    }
21762
21763    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21764        cx.emit(EditorEvent::Focused);
21765
21766        if let Some(descendant) = self
21767            .last_focused_descendant
21768            .take()
21769            .and_then(|descendant| descendant.upgrade())
21770        {
21771            window.focus(&descendant);
21772        } else {
21773            if let Some(blame) = self.blame.as_ref() {
21774                blame.update(cx, GitBlame::focus)
21775            }
21776
21777            self.blink_manager.update(cx, BlinkManager::enable);
21778            self.show_cursor_names(window, cx);
21779            self.buffer.update(cx, |buffer, cx| {
21780                buffer.finalize_last_transaction(cx);
21781                if self.leader_id.is_none() {
21782                    buffer.set_active_selections(
21783                        &self.selections.disjoint_anchors_arc(),
21784                        self.selections.line_mode(),
21785                        self.cursor_shape,
21786                        cx,
21787                    );
21788                }
21789            });
21790        }
21791    }
21792
21793    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21794        cx.emit(EditorEvent::FocusedIn)
21795    }
21796
21797    fn handle_focus_out(
21798        &mut self,
21799        event: FocusOutEvent,
21800        _window: &mut Window,
21801        cx: &mut Context<Self>,
21802    ) {
21803        if event.blurred != self.focus_handle {
21804            self.last_focused_descendant = Some(event.blurred);
21805        }
21806        self.selection_drag_state = SelectionDragState::None;
21807        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21808    }
21809
21810    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21811        self.blink_manager.update(cx, BlinkManager::disable);
21812        self.buffer
21813            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21814
21815        if let Some(blame) = self.blame.as_ref() {
21816            blame.update(cx, GitBlame::blur)
21817        }
21818        if !self.hover_state.focused(window, cx) {
21819            hide_hover(self, cx);
21820        }
21821        if !self
21822            .context_menu
21823            .borrow()
21824            .as_ref()
21825            .is_some_and(|context_menu| context_menu.focused(window, cx))
21826        {
21827            self.hide_context_menu(window, cx);
21828        }
21829        self.take_active_edit_prediction(cx);
21830        cx.emit(EditorEvent::Blurred);
21831        cx.notify();
21832    }
21833
21834    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21835        let mut pending: String = window
21836            .pending_input_keystrokes()
21837            .into_iter()
21838            .flatten()
21839            .filter_map(|keystroke| {
21840                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21841                    keystroke.key_char.clone()
21842                } else {
21843                    None
21844                }
21845            })
21846            .collect();
21847
21848        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21849            pending = "".to_string();
21850        }
21851
21852        let existing_pending = self
21853            .text_highlights::<PendingInput>(cx)
21854            .map(|(_, ranges)| ranges.to_vec());
21855        if existing_pending.is_none() && pending.is_empty() {
21856            return;
21857        }
21858        let transaction =
21859            self.transact(window, cx, |this, window, cx| {
21860                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
21861                let edits = selections
21862                    .iter()
21863                    .map(|selection| (selection.end..selection.end, pending.clone()));
21864                this.edit(edits, cx);
21865                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21866                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21867                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21868                    }));
21869                });
21870                if let Some(existing_ranges) = existing_pending {
21871                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21872                    this.edit(edits, cx);
21873                }
21874            });
21875
21876        let snapshot = self.snapshot(window, cx);
21877        let ranges = self
21878            .selections
21879            .all::<usize>(&snapshot.display_snapshot)
21880            .into_iter()
21881            .map(|selection| {
21882                snapshot.buffer_snapshot().anchor_after(selection.end)
21883                    ..snapshot
21884                        .buffer_snapshot()
21885                        .anchor_before(selection.end + pending.len())
21886            })
21887            .collect();
21888
21889        if pending.is_empty() {
21890            self.clear_highlights::<PendingInput>(cx);
21891        } else {
21892            self.highlight_text::<PendingInput>(
21893                ranges,
21894                HighlightStyle {
21895                    underline: Some(UnderlineStyle {
21896                        thickness: px(1.),
21897                        color: None,
21898                        wavy: false,
21899                    }),
21900                    ..Default::default()
21901                },
21902                cx,
21903            );
21904        }
21905
21906        self.ime_transaction = self.ime_transaction.or(transaction);
21907        if let Some(transaction) = self.ime_transaction {
21908            self.buffer.update(cx, |buffer, cx| {
21909                buffer.group_until_transaction(transaction, cx);
21910            });
21911        }
21912
21913        if self.text_highlights::<PendingInput>(cx).is_none() {
21914            self.ime_transaction.take();
21915        }
21916    }
21917
21918    pub fn register_action_renderer(
21919        &mut self,
21920        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21921    ) -> Subscription {
21922        let id = self.next_editor_action_id.post_inc();
21923        self.editor_actions
21924            .borrow_mut()
21925            .insert(id, Box::new(listener));
21926
21927        let editor_actions = self.editor_actions.clone();
21928        Subscription::new(move || {
21929            editor_actions.borrow_mut().remove(&id);
21930        })
21931    }
21932
21933    pub fn register_action<A: Action>(
21934        &mut self,
21935        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21936    ) -> Subscription {
21937        let id = self.next_editor_action_id.post_inc();
21938        let listener = Arc::new(listener);
21939        self.editor_actions.borrow_mut().insert(
21940            id,
21941            Box::new(move |_, window, _| {
21942                let listener = listener.clone();
21943                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21944                    let action = action.downcast_ref().unwrap();
21945                    if phase == DispatchPhase::Bubble {
21946                        listener(action, window, cx)
21947                    }
21948                })
21949            }),
21950        );
21951
21952        let editor_actions = self.editor_actions.clone();
21953        Subscription::new(move || {
21954            editor_actions.borrow_mut().remove(&id);
21955        })
21956    }
21957
21958    pub fn file_header_size(&self) -> u32 {
21959        FILE_HEADER_HEIGHT
21960    }
21961
21962    pub fn restore(
21963        &mut self,
21964        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21965        window: &mut Window,
21966        cx: &mut Context<Self>,
21967    ) {
21968        let workspace = self.workspace();
21969        let project = self.project();
21970        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21971            let mut tasks = Vec::new();
21972            for (buffer_id, changes) in revert_changes {
21973                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21974                    buffer.update(cx, |buffer, cx| {
21975                        buffer.edit(
21976                            changes
21977                                .into_iter()
21978                                .map(|(range, text)| (range, text.to_string())),
21979                            None,
21980                            cx,
21981                        );
21982                    });
21983
21984                    if let Some(project) =
21985                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21986                    {
21987                        project.update(cx, |project, cx| {
21988                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21989                        })
21990                    }
21991                }
21992            }
21993            tasks
21994        });
21995        cx.spawn_in(window, async move |_, cx| {
21996            for (buffer, task) in save_tasks {
21997                let result = task.await;
21998                if result.is_err() {
21999                    let Some(path) = buffer
22000                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
22001                        .ok()
22002                    else {
22003                        continue;
22004                    };
22005                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
22006                        let Some(task) = cx
22007                            .update_window_entity(workspace, |workspace, window, cx| {
22008                                workspace
22009                                    .open_path_preview(path, None, false, false, false, window, cx)
22010                            })
22011                            .ok()
22012                        else {
22013                            continue;
22014                        };
22015                        task.await.log_err();
22016                    }
22017                }
22018            }
22019        })
22020        .detach();
22021        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22022            selections.refresh()
22023        });
22024    }
22025
22026    pub fn to_pixel_point(
22027        &self,
22028        source: multi_buffer::Anchor,
22029        editor_snapshot: &EditorSnapshot,
22030        window: &mut Window,
22031    ) -> Option<gpui::Point<Pixels>> {
22032        let source_point = source.to_display_point(editor_snapshot);
22033        self.display_to_pixel_point(source_point, editor_snapshot, window)
22034    }
22035
22036    pub fn display_to_pixel_point(
22037        &self,
22038        source: DisplayPoint,
22039        editor_snapshot: &EditorSnapshot,
22040        window: &mut Window,
22041    ) -> Option<gpui::Point<Pixels>> {
22042        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
22043        let text_layout_details = self.text_layout_details(window);
22044        let scroll_top = text_layout_details
22045            .scroll_anchor
22046            .scroll_position(editor_snapshot)
22047            .y;
22048
22049        if source.row().as_f64() < scroll_top.floor() {
22050            return None;
22051        }
22052        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
22053        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
22054        Some(gpui::Point::new(source_x, source_y))
22055    }
22056
22057    pub fn has_visible_completions_menu(&self) -> bool {
22058        !self.edit_prediction_preview_is_active()
22059            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
22060                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
22061            })
22062    }
22063
22064    pub fn register_addon<T: Addon>(&mut self, instance: T) {
22065        if self.mode.is_minimap() {
22066            return;
22067        }
22068        self.addons
22069            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
22070    }
22071
22072    pub fn unregister_addon<T: Addon>(&mut self) {
22073        self.addons.remove(&std::any::TypeId::of::<T>());
22074    }
22075
22076    pub fn addon<T: Addon>(&self) -> Option<&T> {
22077        let type_id = std::any::TypeId::of::<T>();
22078        self.addons
22079            .get(&type_id)
22080            .and_then(|item| item.to_any().downcast_ref::<T>())
22081    }
22082
22083    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
22084        let type_id = std::any::TypeId::of::<T>();
22085        self.addons
22086            .get_mut(&type_id)
22087            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
22088    }
22089
22090    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
22091        let text_layout_details = self.text_layout_details(window);
22092        let style = &text_layout_details.editor_style;
22093        let font_id = window.text_system().resolve_font(&style.text.font());
22094        let font_size = style.text.font_size.to_pixels(window.rem_size());
22095        let line_height = style.text.line_height_in_pixels(window.rem_size());
22096        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
22097        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
22098
22099        CharacterDimensions {
22100            em_width,
22101            em_advance,
22102            line_height,
22103        }
22104    }
22105
22106    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
22107        self.load_diff_task.clone()
22108    }
22109
22110    fn read_metadata_from_db(
22111        &mut self,
22112        item_id: u64,
22113        workspace_id: WorkspaceId,
22114        window: &mut Window,
22115        cx: &mut Context<Editor>,
22116    ) {
22117        if self.buffer_kind(cx) == ItemBufferKind::Singleton
22118            && !self.mode.is_minimap()
22119            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
22120        {
22121            let buffer_snapshot = OnceCell::new();
22122
22123            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
22124                && !folds.is_empty()
22125            {
22126                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22127                self.fold_ranges(
22128                    folds
22129                        .into_iter()
22130                        .map(|(start, end)| {
22131                            snapshot.clip_offset(start, Bias::Left)
22132                                ..snapshot.clip_offset(end, Bias::Right)
22133                        })
22134                        .collect(),
22135                    false,
22136                    window,
22137                    cx,
22138                );
22139            }
22140
22141            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
22142                && !selections.is_empty()
22143            {
22144                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22145                // skip adding the initial selection to selection history
22146                self.selection_history.mode = SelectionHistoryMode::Skipping;
22147                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22148                    s.select_ranges(selections.into_iter().map(|(start, end)| {
22149                        snapshot.clip_offset(start, Bias::Left)
22150                            ..snapshot.clip_offset(end, Bias::Right)
22151                    }));
22152                });
22153                self.selection_history.mode = SelectionHistoryMode::Normal;
22154            };
22155        }
22156
22157        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22158    }
22159
22160    fn update_lsp_data(
22161        &mut self,
22162        for_buffer: Option<BufferId>,
22163        window: &mut Window,
22164        cx: &mut Context<'_, Self>,
22165    ) {
22166        self.pull_diagnostics(for_buffer, window, cx);
22167        self.refresh_colors_for_visible_range(for_buffer, window, cx);
22168    }
22169
22170    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
22171        if self.ignore_lsp_data() {
22172            return;
22173        }
22174        for (_, (visible_buffer, _, _)) in self.visible_excerpts(cx) {
22175            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
22176        }
22177    }
22178
22179    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
22180        if self.ignore_lsp_data() {
22181            return;
22182        }
22183
22184        if !self.registered_buffers.contains_key(&buffer_id)
22185            && let Some(project) = self.project.as_ref()
22186        {
22187            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
22188                project.update(cx, |project, cx| {
22189                    self.registered_buffers.insert(
22190                        buffer_id,
22191                        project.register_buffer_with_language_servers(&buffer, cx),
22192                    );
22193                });
22194            } else {
22195                self.registered_buffers.remove(&buffer_id);
22196            }
22197        }
22198    }
22199
22200    fn ignore_lsp_data(&self) -> bool {
22201        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
22202        // skip any LSP updates for it.
22203        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
22204    }
22205}
22206
22207fn edit_for_markdown_paste<'a>(
22208    buffer: &MultiBufferSnapshot,
22209    range: Range<usize>,
22210    to_insert: &'a str,
22211    url: Option<url::Url>,
22212) -> (Range<usize>, Cow<'a, str>) {
22213    if url.is_none() {
22214        return (range, Cow::Borrowed(to_insert));
22215    };
22216
22217    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22218
22219    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22220        Cow::Borrowed(to_insert)
22221    } else {
22222        Cow::Owned(format!("[{old_text}]({to_insert})"))
22223    };
22224    (range, new_text)
22225}
22226
22227#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
22228pub enum VimFlavor {
22229    Vim,
22230    Helix,
22231}
22232
22233pub fn vim_flavor(cx: &App) -> Option<VimFlavor> {
22234    if vim_mode_setting::HelixModeSetting::try_get(cx)
22235        .map(|helix_mode| helix_mode.0)
22236        .unwrap_or(false)
22237    {
22238        Some(VimFlavor::Helix)
22239    } else if vim_mode_setting::VimModeSetting::try_get(cx)
22240        .map(|vim_mode| vim_mode.0)
22241        .unwrap_or(false)
22242    {
22243        Some(VimFlavor::Vim)
22244    } else {
22245        None // neither vim nor helix mode
22246    }
22247}
22248
22249fn process_completion_for_edit(
22250    completion: &Completion,
22251    intent: CompletionIntent,
22252    buffer: &Entity<Buffer>,
22253    cursor_position: &text::Anchor,
22254    cx: &mut Context<Editor>,
22255) -> CompletionEdit {
22256    let buffer = buffer.read(cx);
22257    let buffer_snapshot = buffer.snapshot();
22258    let (snippet, new_text) = if completion.is_snippet() {
22259        let mut snippet_source = completion.new_text.clone();
22260        // Workaround for typescript language server issues so that methods don't expand within
22261        // strings and functions with type expressions. The previous point is used because the query
22262        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22263        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22264        let previous_point = if previous_point.column > 0 {
22265            cursor_position.to_previous_offset(&buffer_snapshot)
22266        } else {
22267            cursor_position.to_offset(&buffer_snapshot)
22268        };
22269        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22270            && scope.prefers_label_for_snippet_in_completion()
22271            && let Some(label) = completion.label()
22272            && matches!(
22273                completion.kind(),
22274                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22275            )
22276        {
22277            snippet_source = label;
22278        }
22279        match Snippet::parse(&snippet_source).log_err() {
22280            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22281            None => (None, completion.new_text.clone()),
22282        }
22283    } else {
22284        (None, completion.new_text.clone())
22285    };
22286
22287    let mut range_to_replace = {
22288        let replace_range = &completion.replace_range;
22289        if let CompletionSource::Lsp {
22290            insert_range: Some(insert_range),
22291            ..
22292        } = &completion.source
22293        {
22294            debug_assert_eq!(
22295                insert_range.start, replace_range.start,
22296                "insert_range and replace_range should start at the same position"
22297            );
22298            debug_assert!(
22299                insert_range
22300                    .start
22301                    .cmp(cursor_position, &buffer_snapshot)
22302                    .is_le(),
22303                "insert_range should start before or at cursor position"
22304            );
22305            debug_assert!(
22306                replace_range
22307                    .start
22308                    .cmp(cursor_position, &buffer_snapshot)
22309                    .is_le(),
22310                "replace_range should start before or at cursor position"
22311            );
22312
22313            let should_replace = match intent {
22314                CompletionIntent::CompleteWithInsert => false,
22315                CompletionIntent::CompleteWithReplace => true,
22316                CompletionIntent::Complete | CompletionIntent::Compose => {
22317                    let insert_mode =
22318                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22319                            .completions
22320                            .lsp_insert_mode;
22321                    match insert_mode {
22322                        LspInsertMode::Insert => false,
22323                        LspInsertMode::Replace => true,
22324                        LspInsertMode::ReplaceSubsequence => {
22325                            let mut text_to_replace = buffer.chars_for_range(
22326                                buffer.anchor_before(replace_range.start)
22327                                    ..buffer.anchor_after(replace_range.end),
22328                            );
22329                            let mut current_needle = text_to_replace.next();
22330                            for haystack_ch in completion.label.text.chars() {
22331                                if let Some(needle_ch) = current_needle
22332                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22333                                {
22334                                    current_needle = text_to_replace.next();
22335                                }
22336                            }
22337                            current_needle.is_none()
22338                        }
22339                        LspInsertMode::ReplaceSuffix => {
22340                            if replace_range
22341                                .end
22342                                .cmp(cursor_position, &buffer_snapshot)
22343                                .is_gt()
22344                            {
22345                                let range_after_cursor = *cursor_position..replace_range.end;
22346                                let text_after_cursor = buffer
22347                                    .text_for_range(
22348                                        buffer.anchor_before(range_after_cursor.start)
22349                                            ..buffer.anchor_after(range_after_cursor.end),
22350                                    )
22351                                    .collect::<String>()
22352                                    .to_ascii_lowercase();
22353                                completion
22354                                    .label
22355                                    .text
22356                                    .to_ascii_lowercase()
22357                                    .ends_with(&text_after_cursor)
22358                            } else {
22359                                true
22360                            }
22361                        }
22362                    }
22363                }
22364            };
22365
22366            if should_replace {
22367                replace_range.clone()
22368            } else {
22369                insert_range.clone()
22370            }
22371        } else {
22372            replace_range.clone()
22373        }
22374    };
22375
22376    if range_to_replace
22377        .end
22378        .cmp(cursor_position, &buffer_snapshot)
22379        .is_lt()
22380    {
22381        range_to_replace.end = *cursor_position;
22382    }
22383
22384    CompletionEdit {
22385        new_text,
22386        replace_range: range_to_replace.to_offset(buffer),
22387        snippet,
22388    }
22389}
22390
22391struct CompletionEdit {
22392    new_text: String,
22393    replace_range: Range<usize>,
22394    snippet: Option<Snippet>,
22395}
22396
22397fn insert_extra_newline_brackets(
22398    buffer: &MultiBufferSnapshot,
22399    range: Range<usize>,
22400    language: &language::LanguageScope,
22401) -> bool {
22402    let leading_whitespace_len = buffer
22403        .reversed_chars_at(range.start)
22404        .take_while(|c| c.is_whitespace() && *c != '\n')
22405        .map(|c| c.len_utf8())
22406        .sum::<usize>();
22407    let trailing_whitespace_len = buffer
22408        .chars_at(range.end)
22409        .take_while(|c| c.is_whitespace() && *c != '\n')
22410        .map(|c| c.len_utf8())
22411        .sum::<usize>();
22412    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22413
22414    language.brackets().any(|(pair, enabled)| {
22415        let pair_start = pair.start.trim_end();
22416        let pair_end = pair.end.trim_start();
22417
22418        enabled
22419            && pair.newline
22420            && buffer.contains_str_at(range.end, pair_end)
22421            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22422    })
22423}
22424
22425fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22426    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22427        [(buffer, range, _)] => (*buffer, range.clone()),
22428        _ => return false,
22429    };
22430    let pair = {
22431        let mut result: Option<BracketMatch> = None;
22432
22433        for pair in buffer
22434            .all_bracket_ranges(range.clone())
22435            .filter(move |pair| {
22436                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22437            })
22438        {
22439            let len = pair.close_range.end - pair.open_range.start;
22440
22441            if let Some(existing) = &result {
22442                let existing_len = existing.close_range.end - existing.open_range.start;
22443                if len > existing_len {
22444                    continue;
22445                }
22446            }
22447
22448            result = Some(pair);
22449        }
22450
22451        result
22452    };
22453    let Some(pair) = pair else {
22454        return false;
22455    };
22456    pair.newline_only
22457        && buffer
22458            .chars_for_range(pair.open_range.end..range.start)
22459            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22460            .all(|c| c.is_whitespace() && c != '\n')
22461}
22462
22463fn update_uncommitted_diff_for_buffer(
22464    editor: Entity<Editor>,
22465    project: &Entity<Project>,
22466    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22467    buffer: Entity<MultiBuffer>,
22468    cx: &mut App,
22469) -> Task<()> {
22470    let mut tasks = Vec::new();
22471    project.update(cx, |project, cx| {
22472        for buffer in buffers {
22473            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22474                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22475            }
22476        }
22477    });
22478    cx.spawn(async move |cx| {
22479        let diffs = future::join_all(tasks).await;
22480        if editor
22481            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22482            .unwrap_or(false)
22483        {
22484            return;
22485        }
22486
22487        buffer
22488            .update(cx, |buffer, cx| {
22489                for diff in diffs.into_iter().flatten() {
22490                    buffer.add_diff(diff, cx);
22491                }
22492            })
22493            .ok();
22494    })
22495}
22496
22497fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22498    let tab_size = tab_size.get() as usize;
22499    let mut width = offset;
22500
22501    for ch in text.chars() {
22502        width += if ch == '\t' {
22503            tab_size - (width % tab_size)
22504        } else {
22505            1
22506        };
22507    }
22508
22509    width - offset
22510}
22511
22512#[cfg(test)]
22513mod tests {
22514    use super::*;
22515
22516    #[test]
22517    fn test_string_size_with_expanded_tabs() {
22518        let nz = |val| NonZeroU32::new(val).unwrap();
22519        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22520        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22521        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22522        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22523        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22524        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22525        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22526        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22527    }
22528}
22529
22530/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22531struct WordBreakingTokenizer<'a> {
22532    input: &'a str,
22533}
22534
22535impl<'a> WordBreakingTokenizer<'a> {
22536    fn new(input: &'a str) -> Self {
22537        Self { input }
22538    }
22539}
22540
22541fn is_char_ideographic(ch: char) -> bool {
22542    use unicode_script::Script::*;
22543    use unicode_script::UnicodeScript;
22544    matches!(ch.script(), Han | Tangut | Yi)
22545}
22546
22547fn is_grapheme_ideographic(text: &str) -> bool {
22548    text.chars().any(is_char_ideographic)
22549}
22550
22551fn is_grapheme_whitespace(text: &str) -> bool {
22552    text.chars().any(|x| x.is_whitespace())
22553}
22554
22555fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22556    text.chars()
22557        .next()
22558        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22559}
22560
22561#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22562enum WordBreakToken<'a> {
22563    Word { token: &'a str, grapheme_len: usize },
22564    InlineWhitespace { token: &'a str, grapheme_len: usize },
22565    Newline,
22566}
22567
22568impl<'a> Iterator for WordBreakingTokenizer<'a> {
22569    /// Yields a span, the count of graphemes in the token, and whether it was
22570    /// whitespace. Note that it also breaks at word boundaries.
22571    type Item = WordBreakToken<'a>;
22572
22573    fn next(&mut self) -> Option<Self::Item> {
22574        use unicode_segmentation::UnicodeSegmentation;
22575        if self.input.is_empty() {
22576            return None;
22577        }
22578
22579        let mut iter = self.input.graphemes(true).peekable();
22580        let mut offset = 0;
22581        let mut grapheme_len = 0;
22582        if let Some(first_grapheme) = iter.next() {
22583            let is_newline = first_grapheme == "\n";
22584            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22585            offset += first_grapheme.len();
22586            grapheme_len += 1;
22587            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22588                if let Some(grapheme) = iter.peek().copied()
22589                    && should_stay_with_preceding_ideograph(grapheme)
22590                {
22591                    offset += grapheme.len();
22592                    grapheme_len += 1;
22593                }
22594            } else {
22595                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22596                let mut next_word_bound = words.peek().copied();
22597                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22598                    next_word_bound = words.next();
22599                }
22600                while let Some(grapheme) = iter.peek().copied() {
22601                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22602                        break;
22603                    };
22604                    if is_grapheme_whitespace(grapheme) != is_whitespace
22605                        || (grapheme == "\n") != is_newline
22606                    {
22607                        break;
22608                    };
22609                    offset += grapheme.len();
22610                    grapheme_len += 1;
22611                    iter.next();
22612                }
22613            }
22614            let token = &self.input[..offset];
22615            self.input = &self.input[offset..];
22616            if token == "\n" {
22617                Some(WordBreakToken::Newline)
22618            } else if is_whitespace {
22619                Some(WordBreakToken::InlineWhitespace {
22620                    token,
22621                    grapheme_len,
22622                })
22623            } else {
22624                Some(WordBreakToken::Word {
22625                    token,
22626                    grapheme_len,
22627                })
22628            }
22629        } else {
22630            None
22631        }
22632    }
22633}
22634
22635#[test]
22636fn test_word_breaking_tokenizer() {
22637    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22638        ("", &[]),
22639        ("  ", &[whitespace("  ", 2)]),
22640        ("Ʒ", &[word("Ʒ", 1)]),
22641        ("Ǽ", &[word("Ǽ", 1)]),
22642        ("", &[word("", 1)]),
22643        ("⋑⋑", &[word("⋑⋑", 2)]),
22644        (
22645            "原理,进而",
22646            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22647        ),
22648        (
22649            "hello world",
22650            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22651        ),
22652        (
22653            "hello, world",
22654            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22655        ),
22656        (
22657            "  hello world",
22658            &[
22659                whitespace("  ", 2),
22660                word("hello", 5),
22661                whitespace(" ", 1),
22662                word("world", 5),
22663            ],
22664        ),
22665        (
22666            "这是什么 \n 钢笔",
22667            &[
22668                word("", 1),
22669                word("", 1),
22670                word("", 1),
22671                word("", 1),
22672                whitespace(" ", 1),
22673                newline(),
22674                whitespace(" ", 1),
22675                word("", 1),
22676                word("", 1),
22677            ],
22678        ),
22679        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22680    ];
22681
22682    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22683        WordBreakToken::Word {
22684            token,
22685            grapheme_len,
22686        }
22687    }
22688
22689    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22690        WordBreakToken::InlineWhitespace {
22691            token,
22692            grapheme_len,
22693        }
22694    }
22695
22696    fn newline() -> WordBreakToken<'static> {
22697        WordBreakToken::Newline
22698    }
22699
22700    for (input, result) in tests {
22701        assert_eq!(
22702            WordBreakingTokenizer::new(input)
22703                .collect::<Vec<_>>()
22704                .as_slice(),
22705            *result,
22706        );
22707    }
22708}
22709
22710fn wrap_with_prefix(
22711    first_line_prefix: String,
22712    subsequent_lines_prefix: String,
22713    unwrapped_text: String,
22714    wrap_column: usize,
22715    tab_size: NonZeroU32,
22716    preserve_existing_whitespace: bool,
22717) -> String {
22718    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22719    let subsequent_lines_prefix_len =
22720        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22721    let mut wrapped_text = String::new();
22722    let mut current_line = first_line_prefix;
22723    let mut is_first_line = true;
22724
22725    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22726    let mut current_line_len = first_line_prefix_len;
22727    let mut in_whitespace = false;
22728    for token in tokenizer {
22729        let have_preceding_whitespace = in_whitespace;
22730        match token {
22731            WordBreakToken::Word {
22732                token,
22733                grapheme_len,
22734            } => {
22735                in_whitespace = false;
22736                let current_prefix_len = if is_first_line {
22737                    first_line_prefix_len
22738                } else {
22739                    subsequent_lines_prefix_len
22740                };
22741                if current_line_len + grapheme_len > wrap_column
22742                    && current_line_len != current_prefix_len
22743                {
22744                    wrapped_text.push_str(current_line.trim_end());
22745                    wrapped_text.push('\n');
22746                    is_first_line = false;
22747                    current_line = subsequent_lines_prefix.clone();
22748                    current_line_len = subsequent_lines_prefix_len;
22749                }
22750                current_line.push_str(token);
22751                current_line_len += grapheme_len;
22752            }
22753            WordBreakToken::InlineWhitespace {
22754                mut token,
22755                mut grapheme_len,
22756            } => {
22757                in_whitespace = true;
22758                if have_preceding_whitespace && !preserve_existing_whitespace {
22759                    continue;
22760                }
22761                if !preserve_existing_whitespace {
22762                    // Keep a single whitespace grapheme as-is
22763                    if let Some(first) =
22764                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
22765                    {
22766                        token = first;
22767                    } else {
22768                        token = " ";
22769                    }
22770                    grapheme_len = 1;
22771                }
22772                let current_prefix_len = if is_first_line {
22773                    first_line_prefix_len
22774                } else {
22775                    subsequent_lines_prefix_len
22776                };
22777                if current_line_len + grapheme_len > wrap_column {
22778                    wrapped_text.push_str(current_line.trim_end());
22779                    wrapped_text.push('\n');
22780                    is_first_line = false;
22781                    current_line = subsequent_lines_prefix.clone();
22782                    current_line_len = subsequent_lines_prefix_len;
22783                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22784                    current_line.push_str(token);
22785                    current_line_len += grapheme_len;
22786                }
22787            }
22788            WordBreakToken::Newline => {
22789                in_whitespace = true;
22790                let current_prefix_len = if is_first_line {
22791                    first_line_prefix_len
22792                } else {
22793                    subsequent_lines_prefix_len
22794                };
22795                if preserve_existing_whitespace {
22796                    wrapped_text.push_str(current_line.trim_end());
22797                    wrapped_text.push('\n');
22798                    is_first_line = false;
22799                    current_line = subsequent_lines_prefix.clone();
22800                    current_line_len = subsequent_lines_prefix_len;
22801                } else if have_preceding_whitespace {
22802                    continue;
22803                } else if current_line_len + 1 > wrap_column
22804                    && current_line_len != current_prefix_len
22805                {
22806                    wrapped_text.push_str(current_line.trim_end());
22807                    wrapped_text.push('\n');
22808                    is_first_line = false;
22809                    current_line = subsequent_lines_prefix.clone();
22810                    current_line_len = subsequent_lines_prefix_len;
22811                } else if current_line_len != current_prefix_len {
22812                    current_line.push(' ');
22813                    current_line_len += 1;
22814                }
22815            }
22816        }
22817    }
22818
22819    if !current_line.is_empty() {
22820        wrapped_text.push_str(&current_line);
22821    }
22822    wrapped_text
22823}
22824
22825#[test]
22826fn test_wrap_with_prefix() {
22827    assert_eq!(
22828        wrap_with_prefix(
22829            "# ".to_string(),
22830            "# ".to_string(),
22831            "abcdefg".to_string(),
22832            4,
22833            NonZeroU32::new(4).unwrap(),
22834            false,
22835        ),
22836        "# abcdefg"
22837    );
22838    assert_eq!(
22839        wrap_with_prefix(
22840            "".to_string(),
22841            "".to_string(),
22842            "\thello world".to_string(),
22843            8,
22844            NonZeroU32::new(4).unwrap(),
22845            false,
22846        ),
22847        "hello\nworld"
22848    );
22849    assert_eq!(
22850        wrap_with_prefix(
22851            "// ".to_string(),
22852            "// ".to_string(),
22853            "xx \nyy zz aa bb cc".to_string(),
22854            12,
22855            NonZeroU32::new(4).unwrap(),
22856            false,
22857        ),
22858        "// xx yy zz\n// aa bb cc"
22859    );
22860    assert_eq!(
22861        wrap_with_prefix(
22862            String::new(),
22863            String::new(),
22864            "这是什么 \n 钢笔".to_string(),
22865            3,
22866            NonZeroU32::new(4).unwrap(),
22867            false,
22868        ),
22869        "这是什\n么 钢\n"
22870    );
22871    assert_eq!(
22872        wrap_with_prefix(
22873            String::new(),
22874            String::new(),
22875            format!("foo{}bar", '\u{2009}'), // thin space
22876            80,
22877            NonZeroU32::new(4).unwrap(),
22878            false,
22879        ),
22880        format!("foo{}bar", '\u{2009}')
22881    );
22882}
22883
22884pub trait CollaborationHub {
22885    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22886    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22887    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22888}
22889
22890impl CollaborationHub for Entity<Project> {
22891    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22892        self.read(cx).collaborators()
22893    }
22894
22895    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22896        self.read(cx).user_store().read(cx).participant_indices()
22897    }
22898
22899    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22900        let this = self.read(cx);
22901        let user_ids = this.collaborators().values().map(|c| c.user_id);
22902        this.user_store().read(cx).participant_names(user_ids, cx)
22903    }
22904}
22905
22906pub trait SemanticsProvider {
22907    fn hover(
22908        &self,
22909        buffer: &Entity<Buffer>,
22910        position: text::Anchor,
22911        cx: &mut App,
22912    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22913
22914    fn inline_values(
22915        &self,
22916        buffer_handle: Entity<Buffer>,
22917        range: Range<text::Anchor>,
22918        cx: &mut App,
22919    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22920
22921    fn applicable_inlay_chunks(
22922        &self,
22923        buffer: &Entity<Buffer>,
22924        ranges: &[Range<text::Anchor>],
22925        cx: &mut App,
22926    ) -> Vec<Range<BufferRow>>;
22927
22928    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
22929
22930    fn inlay_hints(
22931        &self,
22932        invalidate: InvalidationStrategy,
22933        buffer: Entity<Buffer>,
22934        ranges: Vec<Range<text::Anchor>>,
22935        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
22936        cx: &mut App,
22937    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
22938
22939    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22940
22941    fn document_highlights(
22942        &self,
22943        buffer: &Entity<Buffer>,
22944        position: text::Anchor,
22945        cx: &mut App,
22946    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22947
22948    fn definitions(
22949        &self,
22950        buffer: &Entity<Buffer>,
22951        position: text::Anchor,
22952        kind: GotoDefinitionKind,
22953        cx: &mut App,
22954    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22955
22956    fn range_for_rename(
22957        &self,
22958        buffer: &Entity<Buffer>,
22959        position: text::Anchor,
22960        cx: &mut App,
22961    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22962
22963    fn perform_rename(
22964        &self,
22965        buffer: &Entity<Buffer>,
22966        position: text::Anchor,
22967        new_name: String,
22968        cx: &mut App,
22969    ) -> Option<Task<Result<ProjectTransaction>>>;
22970}
22971
22972pub trait CompletionProvider {
22973    fn completions(
22974        &self,
22975        excerpt_id: ExcerptId,
22976        buffer: &Entity<Buffer>,
22977        buffer_position: text::Anchor,
22978        trigger: CompletionContext,
22979        window: &mut Window,
22980        cx: &mut Context<Editor>,
22981    ) -> Task<Result<Vec<CompletionResponse>>>;
22982
22983    fn resolve_completions(
22984        &self,
22985        _buffer: Entity<Buffer>,
22986        _completion_indices: Vec<usize>,
22987        _completions: Rc<RefCell<Box<[Completion]>>>,
22988        _cx: &mut Context<Editor>,
22989    ) -> Task<Result<bool>> {
22990        Task::ready(Ok(false))
22991    }
22992
22993    fn apply_additional_edits_for_completion(
22994        &self,
22995        _buffer: Entity<Buffer>,
22996        _completions: Rc<RefCell<Box<[Completion]>>>,
22997        _completion_index: usize,
22998        _push_to_history: bool,
22999        _cx: &mut Context<Editor>,
23000    ) -> Task<Result<Option<language::Transaction>>> {
23001        Task::ready(Ok(None))
23002    }
23003
23004    fn is_completion_trigger(
23005        &self,
23006        buffer: &Entity<Buffer>,
23007        position: language::Anchor,
23008        text: &str,
23009        trigger_in_words: bool,
23010        menu_is_open: bool,
23011        cx: &mut Context<Editor>,
23012    ) -> bool;
23013
23014    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
23015
23016    fn sort_completions(&self) -> bool {
23017        true
23018    }
23019
23020    fn filter_completions(&self) -> bool {
23021        true
23022    }
23023}
23024
23025pub trait CodeActionProvider {
23026    fn id(&self) -> Arc<str>;
23027
23028    fn code_actions(
23029        &self,
23030        buffer: &Entity<Buffer>,
23031        range: Range<text::Anchor>,
23032        window: &mut Window,
23033        cx: &mut App,
23034    ) -> Task<Result<Vec<CodeAction>>>;
23035
23036    fn apply_code_action(
23037        &self,
23038        buffer_handle: Entity<Buffer>,
23039        action: CodeAction,
23040        excerpt_id: ExcerptId,
23041        push_to_history: bool,
23042        window: &mut Window,
23043        cx: &mut App,
23044    ) -> Task<Result<ProjectTransaction>>;
23045}
23046
23047impl CodeActionProvider for Entity<Project> {
23048    fn id(&self) -> Arc<str> {
23049        "project".into()
23050    }
23051
23052    fn code_actions(
23053        &self,
23054        buffer: &Entity<Buffer>,
23055        range: Range<text::Anchor>,
23056        _window: &mut Window,
23057        cx: &mut App,
23058    ) -> Task<Result<Vec<CodeAction>>> {
23059        self.update(cx, |project, cx| {
23060            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
23061            let code_actions = project.code_actions(buffer, range, None, cx);
23062            cx.background_spawn(async move {
23063                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
23064                Ok(code_lens_actions
23065                    .context("code lens fetch")?
23066                    .into_iter()
23067                    .flatten()
23068                    .chain(
23069                        code_actions
23070                            .context("code action fetch")?
23071                            .into_iter()
23072                            .flatten(),
23073                    )
23074                    .collect())
23075            })
23076        })
23077    }
23078
23079    fn apply_code_action(
23080        &self,
23081        buffer_handle: Entity<Buffer>,
23082        action: CodeAction,
23083        _excerpt_id: ExcerptId,
23084        push_to_history: bool,
23085        _window: &mut Window,
23086        cx: &mut App,
23087    ) -> Task<Result<ProjectTransaction>> {
23088        self.update(cx, |project, cx| {
23089            project.apply_code_action(buffer_handle, action, push_to_history, cx)
23090        })
23091    }
23092}
23093
23094fn snippet_completions(
23095    project: &Project,
23096    buffer: &Entity<Buffer>,
23097    buffer_position: text::Anchor,
23098    cx: &mut App,
23099) -> Task<Result<CompletionResponse>> {
23100    let languages = buffer.read(cx).languages_at(buffer_position);
23101    let snippet_store = project.snippets().read(cx);
23102
23103    let scopes: Vec<_> = languages
23104        .iter()
23105        .filter_map(|language| {
23106            let language_name = language.lsp_id();
23107            let snippets = snippet_store.snippets_for(Some(language_name), cx);
23108
23109            if snippets.is_empty() {
23110                None
23111            } else {
23112                Some((language.default_scope(), snippets))
23113            }
23114        })
23115        .collect();
23116
23117    if scopes.is_empty() {
23118        return Task::ready(Ok(CompletionResponse {
23119            completions: vec![],
23120            display_options: CompletionDisplayOptions::default(),
23121            is_incomplete: false,
23122        }));
23123    }
23124
23125    let snapshot = buffer.read(cx).text_snapshot();
23126    let executor = cx.background_executor().clone();
23127
23128    cx.background_spawn(async move {
23129        let mut is_incomplete = false;
23130        let mut completions: Vec<Completion> = Vec::new();
23131        for (scope, snippets) in scopes.into_iter() {
23132            let classifier =
23133                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
23134
23135            const MAX_WORD_PREFIX_LEN: usize = 128;
23136            let last_word: String = snapshot
23137                .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
23138                .take(MAX_WORD_PREFIX_LEN)
23139                .take_while(|c| classifier.is_word(*c))
23140                .collect::<String>()
23141                .chars()
23142                .rev()
23143                .collect();
23144
23145            if last_word.is_empty() {
23146                return Ok(CompletionResponse {
23147                    completions: vec![],
23148                    display_options: CompletionDisplayOptions::default(),
23149                    is_incomplete: true,
23150                });
23151            }
23152
23153            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
23154            let to_lsp = |point: &text::Anchor| {
23155                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
23156                point_to_lsp(end)
23157            };
23158            let lsp_end = to_lsp(&buffer_position);
23159
23160            let candidates = snippets
23161                .iter()
23162                .enumerate()
23163                .flat_map(|(ix, snippet)| {
23164                    snippet
23165                        .prefix
23166                        .iter()
23167                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
23168                })
23169                .collect::<Vec<StringMatchCandidate>>();
23170
23171            const MAX_RESULTS: usize = 100;
23172            let mut matches = fuzzy::match_strings(
23173                &candidates,
23174                &last_word,
23175                last_word.chars().any(|c| c.is_uppercase()),
23176                true,
23177                MAX_RESULTS,
23178                &Default::default(),
23179                executor.clone(),
23180            )
23181            .await;
23182
23183            if matches.len() >= MAX_RESULTS {
23184                is_incomplete = true;
23185            }
23186
23187            // Remove all candidates where the query's start does not match the start of any word in the candidate
23188            if let Some(query_start) = last_word.chars().next() {
23189                matches.retain(|string_match| {
23190                    split_words(&string_match.string).any(|word| {
23191                        // Check that the first codepoint of the word as lowercase matches the first
23192                        // codepoint of the query as lowercase
23193                        word.chars()
23194                            .flat_map(|codepoint| codepoint.to_lowercase())
23195                            .zip(query_start.to_lowercase())
23196                            .all(|(word_cp, query_cp)| word_cp == query_cp)
23197                    })
23198                });
23199            }
23200
23201            let matched_strings = matches
23202                .into_iter()
23203                .map(|m| m.string)
23204                .collect::<HashSet<_>>();
23205
23206            completions.extend(snippets.iter().filter_map(|snippet| {
23207                let matching_prefix = snippet
23208                    .prefix
23209                    .iter()
23210                    .find(|prefix| matched_strings.contains(*prefix))?;
23211                let start = as_offset - last_word.len();
23212                let start = snapshot.anchor_before(start);
23213                let range = start..buffer_position;
23214                let lsp_start = to_lsp(&start);
23215                let lsp_range = lsp::Range {
23216                    start: lsp_start,
23217                    end: lsp_end,
23218                };
23219                Some(Completion {
23220                    replace_range: range,
23221                    new_text: snippet.body.clone(),
23222                    source: CompletionSource::Lsp {
23223                        insert_range: None,
23224                        server_id: LanguageServerId(usize::MAX),
23225                        resolved: true,
23226                        lsp_completion: Box::new(lsp::CompletionItem {
23227                            label: snippet.prefix.first().unwrap().clone(),
23228                            kind: Some(CompletionItemKind::SNIPPET),
23229                            label_details: snippet.description.as_ref().map(|description| {
23230                                lsp::CompletionItemLabelDetails {
23231                                    detail: Some(description.clone()),
23232                                    description: None,
23233                                }
23234                            }),
23235                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23236                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23237                                lsp::InsertReplaceEdit {
23238                                    new_text: snippet.body.clone(),
23239                                    insert: lsp_range,
23240                                    replace: lsp_range,
23241                                },
23242                            )),
23243                            filter_text: Some(snippet.body.clone()),
23244                            sort_text: Some(char::MAX.to_string()),
23245                            ..lsp::CompletionItem::default()
23246                        }),
23247                        lsp_defaults: None,
23248                    },
23249                    label: CodeLabel::plain(matching_prefix.clone(), None),
23250                    icon_path: None,
23251                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23252                        single_line: snippet.name.clone().into(),
23253                        plain_text: snippet
23254                            .description
23255                            .clone()
23256                            .map(|description| description.into()),
23257                    }),
23258                    insert_text_mode: None,
23259                    confirm: None,
23260                })
23261            }))
23262        }
23263
23264        Ok(CompletionResponse {
23265            completions,
23266            display_options: CompletionDisplayOptions::default(),
23267            is_incomplete,
23268        })
23269    })
23270}
23271
23272impl CompletionProvider for Entity<Project> {
23273    fn completions(
23274        &self,
23275        _excerpt_id: ExcerptId,
23276        buffer: &Entity<Buffer>,
23277        buffer_position: text::Anchor,
23278        options: CompletionContext,
23279        _window: &mut Window,
23280        cx: &mut Context<Editor>,
23281    ) -> Task<Result<Vec<CompletionResponse>>> {
23282        self.update(cx, |project, cx| {
23283            let snippets = snippet_completions(project, buffer, buffer_position, cx);
23284            let project_completions = project.completions(buffer, buffer_position, options, cx);
23285            cx.background_spawn(async move {
23286                let mut responses = project_completions.await?;
23287                let snippets = snippets.await?;
23288                if !snippets.completions.is_empty() {
23289                    responses.push(snippets);
23290                }
23291                Ok(responses)
23292            })
23293        })
23294    }
23295
23296    fn resolve_completions(
23297        &self,
23298        buffer: Entity<Buffer>,
23299        completion_indices: Vec<usize>,
23300        completions: Rc<RefCell<Box<[Completion]>>>,
23301        cx: &mut Context<Editor>,
23302    ) -> Task<Result<bool>> {
23303        self.update(cx, |project, cx| {
23304            project.lsp_store().update(cx, |lsp_store, cx| {
23305                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23306            })
23307        })
23308    }
23309
23310    fn apply_additional_edits_for_completion(
23311        &self,
23312        buffer: Entity<Buffer>,
23313        completions: Rc<RefCell<Box<[Completion]>>>,
23314        completion_index: usize,
23315        push_to_history: bool,
23316        cx: &mut Context<Editor>,
23317    ) -> Task<Result<Option<language::Transaction>>> {
23318        self.update(cx, |project, cx| {
23319            project.lsp_store().update(cx, |lsp_store, cx| {
23320                lsp_store.apply_additional_edits_for_completion(
23321                    buffer,
23322                    completions,
23323                    completion_index,
23324                    push_to_history,
23325                    cx,
23326                )
23327            })
23328        })
23329    }
23330
23331    fn is_completion_trigger(
23332        &self,
23333        buffer: &Entity<Buffer>,
23334        position: language::Anchor,
23335        text: &str,
23336        trigger_in_words: bool,
23337        menu_is_open: bool,
23338        cx: &mut Context<Editor>,
23339    ) -> bool {
23340        let mut chars = text.chars();
23341        let char = if let Some(char) = chars.next() {
23342            char
23343        } else {
23344            return false;
23345        };
23346        if chars.next().is_some() {
23347            return false;
23348        }
23349
23350        let buffer = buffer.read(cx);
23351        let snapshot = buffer.snapshot();
23352        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23353            return false;
23354        }
23355        let classifier = snapshot
23356            .char_classifier_at(position)
23357            .scope_context(Some(CharScopeContext::Completion));
23358        if trigger_in_words && classifier.is_word(char) {
23359            return true;
23360        }
23361
23362        buffer.completion_triggers().contains(text)
23363    }
23364}
23365
23366impl SemanticsProvider for Entity<Project> {
23367    fn hover(
23368        &self,
23369        buffer: &Entity<Buffer>,
23370        position: text::Anchor,
23371        cx: &mut App,
23372    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23373        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23374    }
23375
23376    fn document_highlights(
23377        &self,
23378        buffer: &Entity<Buffer>,
23379        position: text::Anchor,
23380        cx: &mut App,
23381    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23382        Some(self.update(cx, |project, cx| {
23383            project.document_highlights(buffer, position, cx)
23384        }))
23385    }
23386
23387    fn definitions(
23388        &self,
23389        buffer: &Entity<Buffer>,
23390        position: text::Anchor,
23391        kind: GotoDefinitionKind,
23392        cx: &mut App,
23393    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23394        Some(self.update(cx, |project, cx| match kind {
23395            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23396            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23397            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23398            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23399        }))
23400    }
23401
23402    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23403        self.update(cx, |project, cx| {
23404            if project
23405                .active_debug_session(cx)
23406                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23407            {
23408                return true;
23409            }
23410
23411            buffer.update(cx, |buffer, cx| {
23412                project.any_language_server_supports_inlay_hints(buffer, cx)
23413            })
23414        })
23415    }
23416
23417    fn inline_values(
23418        &self,
23419        buffer_handle: Entity<Buffer>,
23420        range: Range<text::Anchor>,
23421        cx: &mut App,
23422    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23423        self.update(cx, |project, cx| {
23424            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23425
23426            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23427        })
23428    }
23429
23430    fn applicable_inlay_chunks(
23431        &self,
23432        buffer: &Entity<Buffer>,
23433        ranges: &[Range<text::Anchor>],
23434        cx: &mut App,
23435    ) -> Vec<Range<BufferRow>> {
23436        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23437            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
23438        })
23439    }
23440
23441    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
23442        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
23443            lsp_store.invalidate_inlay_hints(for_buffers)
23444        });
23445    }
23446
23447    fn inlay_hints(
23448        &self,
23449        invalidate: InvalidationStrategy,
23450        buffer: Entity<Buffer>,
23451        ranges: Vec<Range<text::Anchor>>,
23452        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23453        cx: &mut App,
23454    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
23455        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23456            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
23457        }))
23458    }
23459
23460    fn range_for_rename(
23461        &self,
23462        buffer: &Entity<Buffer>,
23463        position: text::Anchor,
23464        cx: &mut App,
23465    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23466        Some(self.update(cx, |project, cx| {
23467            let buffer = buffer.clone();
23468            let task = project.prepare_rename(buffer.clone(), position, cx);
23469            cx.spawn(async move |_, cx| {
23470                Ok(match task.await? {
23471                    PrepareRenameResponse::Success(range) => Some(range),
23472                    PrepareRenameResponse::InvalidPosition => None,
23473                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23474                        // Fallback on using TreeSitter info to determine identifier range
23475                        buffer.read_with(cx, |buffer, _| {
23476                            let snapshot = buffer.snapshot();
23477                            let (range, kind) = snapshot.surrounding_word(position, None);
23478                            if kind != Some(CharKind::Word) {
23479                                return None;
23480                            }
23481                            Some(
23482                                snapshot.anchor_before(range.start)
23483                                    ..snapshot.anchor_after(range.end),
23484                            )
23485                        })?
23486                    }
23487                })
23488            })
23489        }))
23490    }
23491
23492    fn perform_rename(
23493        &self,
23494        buffer: &Entity<Buffer>,
23495        position: text::Anchor,
23496        new_name: String,
23497        cx: &mut App,
23498    ) -> Option<Task<Result<ProjectTransaction>>> {
23499        Some(self.update(cx, |project, cx| {
23500            project.perform_rename(buffer.clone(), position, new_name, cx)
23501        }))
23502    }
23503}
23504
23505fn consume_contiguous_rows(
23506    contiguous_row_selections: &mut Vec<Selection<Point>>,
23507    selection: &Selection<Point>,
23508    display_map: &DisplaySnapshot,
23509    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23510) -> (MultiBufferRow, MultiBufferRow) {
23511    contiguous_row_selections.push(selection.clone());
23512    let start_row = starting_row(selection, display_map);
23513    let mut end_row = ending_row(selection, display_map);
23514
23515    while let Some(next_selection) = selections.peek() {
23516        if next_selection.start.row <= end_row.0 {
23517            end_row = ending_row(next_selection, display_map);
23518            contiguous_row_selections.push(selections.next().unwrap().clone());
23519        } else {
23520            break;
23521        }
23522    }
23523    (start_row, end_row)
23524}
23525
23526fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23527    if selection.start.column > 0 {
23528        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23529    } else {
23530        MultiBufferRow(selection.start.row)
23531    }
23532}
23533
23534fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23535    if next_selection.end.column > 0 || next_selection.is_empty() {
23536        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23537    } else {
23538        MultiBufferRow(next_selection.end.row)
23539    }
23540}
23541
23542impl EditorSnapshot {
23543    pub fn remote_selections_in_range<'a>(
23544        &'a self,
23545        range: &'a Range<Anchor>,
23546        collaboration_hub: &dyn CollaborationHub,
23547        cx: &'a App,
23548    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23549        let participant_names = collaboration_hub.user_names(cx);
23550        let participant_indices = collaboration_hub.user_participant_indices(cx);
23551        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23552        let collaborators_by_replica_id = collaborators_by_peer_id
23553            .values()
23554            .map(|collaborator| (collaborator.replica_id, collaborator))
23555            .collect::<HashMap<_, _>>();
23556        self.buffer_snapshot()
23557            .selections_in_range(range, false)
23558            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23559                if replica_id == ReplicaId::AGENT {
23560                    Some(RemoteSelection {
23561                        replica_id,
23562                        selection,
23563                        cursor_shape,
23564                        line_mode,
23565                        collaborator_id: CollaboratorId::Agent,
23566                        user_name: Some("Agent".into()),
23567                        color: cx.theme().players().agent(),
23568                    })
23569                } else {
23570                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23571                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23572                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23573                    Some(RemoteSelection {
23574                        replica_id,
23575                        selection,
23576                        cursor_shape,
23577                        line_mode,
23578                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23579                        user_name,
23580                        color: if let Some(index) = participant_index {
23581                            cx.theme().players().color_for_participant(index.0)
23582                        } else {
23583                            cx.theme().players().absent()
23584                        },
23585                    })
23586                }
23587            })
23588    }
23589
23590    pub fn hunks_for_ranges(
23591        &self,
23592        ranges: impl IntoIterator<Item = Range<Point>>,
23593    ) -> Vec<MultiBufferDiffHunk> {
23594        let mut hunks = Vec::new();
23595        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23596            HashMap::default();
23597        for query_range in ranges {
23598            let query_rows =
23599                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23600            for hunk in self.buffer_snapshot().diff_hunks_in_range(
23601                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23602            ) {
23603                // Include deleted hunks that are adjacent to the query range, because
23604                // otherwise they would be missed.
23605                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23606                if hunk.status().is_deleted() {
23607                    intersects_range |= hunk.row_range.start == query_rows.end;
23608                    intersects_range |= hunk.row_range.end == query_rows.start;
23609                }
23610                if intersects_range {
23611                    if !processed_buffer_rows
23612                        .entry(hunk.buffer_id)
23613                        .or_default()
23614                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23615                    {
23616                        continue;
23617                    }
23618                    hunks.push(hunk);
23619                }
23620            }
23621        }
23622
23623        hunks
23624    }
23625
23626    fn display_diff_hunks_for_rows<'a>(
23627        &'a self,
23628        display_rows: Range<DisplayRow>,
23629        folded_buffers: &'a HashSet<BufferId>,
23630    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23631        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23632        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23633
23634        self.buffer_snapshot()
23635            .diff_hunks_in_range(buffer_start..buffer_end)
23636            .filter_map(|hunk| {
23637                if folded_buffers.contains(&hunk.buffer_id) {
23638                    return None;
23639                }
23640
23641                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23642                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23643
23644                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23645                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23646
23647                let display_hunk = if hunk_display_start.column() != 0 {
23648                    DisplayDiffHunk::Folded {
23649                        display_row: hunk_display_start.row(),
23650                    }
23651                } else {
23652                    let mut end_row = hunk_display_end.row();
23653                    if hunk_display_end.column() > 0 {
23654                        end_row.0 += 1;
23655                    }
23656                    let is_created_file = hunk.is_created_file();
23657                    DisplayDiffHunk::Unfolded {
23658                        status: hunk.status(),
23659                        diff_base_byte_range: hunk.diff_base_byte_range,
23660                        display_row_range: hunk_display_start.row()..end_row,
23661                        multi_buffer_range: Anchor::range_in_buffer(
23662                            hunk.excerpt_id,
23663                            hunk.buffer_id,
23664                            hunk.buffer_range,
23665                        ),
23666                        is_created_file,
23667                    }
23668                };
23669
23670                Some(display_hunk)
23671            })
23672    }
23673
23674    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23675        self.display_snapshot
23676            .buffer_snapshot()
23677            .language_at(position)
23678    }
23679
23680    pub fn is_focused(&self) -> bool {
23681        self.is_focused
23682    }
23683
23684    pub fn placeholder_text(&self) -> Option<String> {
23685        self.placeholder_display_snapshot
23686            .as_ref()
23687            .map(|display_map| display_map.text())
23688    }
23689
23690    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
23691        self.scroll_anchor.scroll_position(&self.display_snapshot)
23692    }
23693
23694    fn gutter_dimensions(
23695        &self,
23696        font_id: FontId,
23697        font_size: Pixels,
23698        max_line_number_width: Pixels,
23699        cx: &App,
23700    ) -> Option<GutterDimensions> {
23701        if !self.show_gutter {
23702            return None;
23703        }
23704
23705        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23706        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23707
23708        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23709            matches!(
23710                ProjectSettings::get_global(cx).git.git_gutter,
23711                GitGutterSetting::TrackedFiles
23712            )
23713        });
23714        let gutter_settings = EditorSettings::get_global(cx).gutter;
23715        let show_line_numbers = self
23716            .show_line_numbers
23717            .unwrap_or(gutter_settings.line_numbers);
23718        let line_gutter_width = if show_line_numbers {
23719            // Avoid flicker-like gutter resizes when the line number gains another digit by
23720            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23721            let min_width_for_number_on_gutter =
23722                ch_advance * gutter_settings.min_line_number_digits as f32;
23723            max_line_number_width.max(min_width_for_number_on_gutter)
23724        } else {
23725            0.0.into()
23726        };
23727
23728        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23729        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23730
23731        let git_blame_entries_width =
23732            self.git_blame_gutter_max_author_length
23733                .map(|max_author_length| {
23734                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23735                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23736
23737                    /// The number of characters to dedicate to gaps and margins.
23738                    const SPACING_WIDTH: usize = 4;
23739
23740                    let max_char_count = max_author_length.min(renderer.max_author_length())
23741                        + ::git::SHORT_SHA_LENGTH
23742                        + MAX_RELATIVE_TIMESTAMP.len()
23743                        + SPACING_WIDTH;
23744
23745                    ch_advance * max_char_count
23746                });
23747
23748        let is_singleton = self.buffer_snapshot().is_singleton();
23749
23750        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23751        left_padding += if !is_singleton {
23752            ch_width * 4.0
23753        } else if show_runnables || show_breakpoints {
23754            ch_width * 3.0
23755        } else if show_git_gutter && show_line_numbers {
23756            ch_width * 2.0
23757        } else if show_git_gutter || show_line_numbers {
23758            ch_width
23759        } else {
23760            px(0.)
23761        };
23762
23763        let shows_folds = is_singleton && gutter_settings.folds;
23764
23765        let right_padding = if shows_folds && show_line_numbers {
23766            ch_width * 4.0
23767        } else if shows_folds || (!is_singleton && show_line_numbers) {
23768            ch_width * 3.0
23769        } else if show_line_numbers {
23770            ch_width
23771        } else {
23772            px(0.)
23773        };
23774
23775        Some(GutterDimensions {
23776            left_padding,
23777            right_padding,
23778            width: line_gutter_width + left_padding + right_padding,
23779            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23780            git_blame_entries_width,
23781        })
23782    }
23783
23784    pub fn render_crease_toggle(
23785        &self,
23786        buffer_row: MultiBufferRow,
23787        row_contains_cursor: bool,
23788        editor: Entity<Editor>,
23789        window: &mut Window,
23790        cx: &mut App,
23791    ) -> Option<AnyElement> {
23792        let folded = self.is_line_folded(buffer_row);
23793        let mut is_foldable = false;
23794
23795        if let Some(crease) = self
23796            .crease_snapshot
23797            .query_row(buffer_row, self.buffer_snapshot())
23798        {
23799            is_foldable = true;
23800            match crease {
23801                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23802                    if let Some(render_toggle) = render_toggle {
23803                        let toggle_callback =
23804                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23805                                if folded {
23806                                    editor.update(cx, |editor, cx| {
23807                                        editor.fold_at(buffer_row, window, cx)
23808                                    });
23809                                } else {
23810                                    editor.update(cx, |editor, cx| {
23811                                        editor.unfold_at(buffer_row, window, cx)
23812                                    });
23813                                }
23814                            });
23815                        return Some((render_toggle)(
23816                            buffer_row,
23817                            folded,
23818                            toggle_callback,
23819                            window,
23820                            cx,
23821                        ));
23822                    }
23823                }
23824            }
23825        }
23826
23827        is_foldable |= self.starts_indent(buffer_row);
23828
23829        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23830            Some(
23831                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23832                    .toggle_state(folded)
23833                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23834                        if folded {
23835                            this.unfold_at(buffer_row, window, cx);
23836                        } else {
23837                            this.fold_at(buffer_row, window, cx);
23838                        }
23839                    }))
23840                    .into_any_element(),
23841            )
23842        } else {
23843            None
23844        }
23845    }
23846
23847    pub fn render_crease_trailer(
23848        &self,
23849        buffer_row: MultiBufferRow,
23850        window: &mut Window,
23851        cx: &mut App,
23852    ) -> Option<AnyElement> {
23853        let folded = self.is_line_folded(buffer_row);
23854        if let Crease::Inline { render_trailer, .. } = self
23855            .crease_snapshot
23856            .query_row(buffer_row, self.buffer_snapshot())?
23857        {
23858            let render_trailer = render_trailer.as_ref()?;
23859            Some(render_trailer(buffer_row, folded, window, cx))
23860        } else {
23861            None
23862        }
23863    }
23864}
23865
23866impl Deref for EditorSnapshot {
23867    type Target = DisplaySnapshot;
23868
23869    fn deref(&self) -> &Self::Target {
23870        &self.display_snapshot
23871    }
23872}
23873
23874#[derive(Clone, Debug, PartialEq, Eq)]
23875pub enum EditorEvent {
23876    InputIgnored {
23877        text: Arc<str>,
23878    },
23879    InputHandled {
23880        utf16_range_to_replace: Option<Range<isize>>,
23881        text: Arc<str>,
23882    },
23883    ExcerptsAdded {
23884        buffer: Entity<Buffer>,
23885        predecessor: ExcerptId,
23886        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23887    },
23888    ExcerptsRemoved {
23889        ids: Vec<ExcerptId>,
23890        removed_buffer_ids: Vec<BufferId>,
23891    },
23892    BufferFoldToggled {
23893        ids: Vec<ExcerptId>,
23894        folded: bool,
23895    },
23896    ExcerptsEdited {
23897        ids: Vec<ExcerptId>,
23898    },
23899    ExcerptsExpanded {
23900        ids: Vec<ExcerptId>,
23901    },
23902    BufferEdited,
23903    Edited {
23904        transaction_id: clock::Lamport,
23905    },
23906    Reparsed(BufferId),
23907    Focused,
23908    FocusedIn,
23909    Blurred,
23910    DirtyChanged,
23911    Saved,
23912    TitleChanged,
23913    SelectionsChanged {
23914        local: bool,
23915    },
23916    ScrollPositionChanged {
23917        local: bool,
23918        autoscroll: bool,
23919    },
23920    TransactionUndone {
23921        transaction_id: clock::Lamport,
23922    },
23923    TransactionBegun {
23924        transaction_id: clock::Lamport,
23925    },
23926    CursorShapeChanged,
23927    BreadcrumbsChanged,
23928    PushedToNavHistory {
23929        anchor: Anchor,
23930        is_deactivate: bool,
23931    },
23932}
23933
23934impl EventEmitter<EditorEvent> for Editor {}
23935
23936impl Focusable for Editor {
23937    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23938        self.focus_handle.clone()
23939    }
23940}
23941
23942impl Render for Editor {
23943    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23944        let settings = ThemeSettings::get_global(cx);
23945
23946        let mut text_style = match self.mode {
23947            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23948                color: cx.theme().colors().editor_foreground,
23949                font_family: settings.ui_font.family.clone(),
23950                font_features: settings.ui_font.features.clone(),
23951                font_fallbacks: settings.ui_font.fallbacks.clone(),
23952                font_size: rems(0.875).into(),
23953                font_weight: settings.ui_font.weight,
23954                line_height: relative(settings.buffer_line_height.value()),
23955                ..Default::default()
23956            },
23957            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23958                color: cx.theme().colors().editor_foreground,
23959                font_family: settings.buffer_font.family.clone(),
23960                font_features: settings.buffer_font.features.clone(),
23961                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23962                font_size: settings.buffer_font_size(cx).into(),
23963                font_weight: settings.buffer_font.weight,
23964                line_height: relative(settings.buffer_line_height.value()),
23965                ..Default::default()
23966            },
23967        };
23968        if let Some(text_style_refinement) = &self.text_style_refinement {
23969            text_style.refine(text_style_refinement)
23970        }
23971
23972        let background = match self.mode {
23973            EditorMode::SingleLine => cx.theme().system().transparent,
23974            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23975            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23976            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23977        };
23978
23979        EditorElement::new(
23980            &cx.entity(),
23981            EditorStyle {
23982                background,
23983                border: cx.theme().colors().border,
23984                local_player: cx.theme().players().local(),
23985                text: text_style,
23986                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23987                syntax: cx.theme().syntax().clone(),
23988                status: cx.theme().status().clone(),
23989                inlay_hints_style: make_inlay_hints_style(cx),
23990                edit_prediction_styles: make_suggestion_styles(cx),
23991                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23992                show_underlines: self.diagnostics_enabled(),
23993            },
23994        )
23995    }
23996}
23997
23998impl EntityInputHandler for Editor {
23999    fn text_for_range(
24000        &mut self,
24001        range_utf16: Range<usize>,
24002        adjusted_range: &mut Option<Range<usize>>,
24003        _: &mut Window,
24004        cx: &mut Context<Self>,
24005    ) -> Option<String> {
24006        let snapshot = self.buffer.read(cx).read(cx);
24007        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
24008        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
24009        if (start.0..end.0) != range_utf16 {
24010            adjusted_range.replace(start.0..end.0);
24011        }
24012        Some(snapshot.text_for_range(start..end).collect())
24013    }
24014
24015    fn selected_text_range(
24016        &mut self,
24017        ignore_disabled_input: bool,
24018        _: &mut Window,
24019        cx: &mut Context<Self>,
24020    ) -> Option<UTF16Selection> {
24021        // Prevent the IME menu from appearing when holding down an alphabetic key
24022        // while input is disabled.
24023        if !ignore_disabled_input && !self.input_enabled {
24024            return None;
24025        }
24026
24027        let selection = self
24028            .selections
24029            .newest::<OffsetUtf16>(&self.display_snapshot(cx));
24030        let range = selection.range();
24031
24032        Some(UTF16Selection {
24033            range: range.start.0..range.end.0,
24034            reversed: selection.reversed,
24035        })
24036    }
24037
24038    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
24039        let snapshot = self.buffer.read(cx).read(cx);
24040        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
24041        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
24042    }
24043
24044    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
24045        self.clear_highlights::<InputComposition>(cx);
24046        self.ime_transaction.take();
24047    }
24048
24049    fn replace_text_in_range(
24050        &mut self,
24051        range_utf16: Option<Range<usize>>,
24052        text: &str,
24053        window: &mut Window,
24054        cx: &mut Context<Self>,
24055    ) {
24056        if !self.input_enabled {
24057            cx.emit(EditorEvent::InputIgnored { text: text.into() });
24058            return;
24059        }
24060
24061        self.transact(window, cx, |this, window, cx| {
24062            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
24063                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
24064                Some(this.selection_replacement_ranges(range_utf16, cx))
24065            } else {
24066                this.marked_text_ranges(cx)
24067            };
24068
24069            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
24070                let newest_selection_id = this.selections.newest_anchor().id;
24071                this.selections
24072                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
24073                    .iter()
24074                    .zip(ranges_to_replace.iter())
24075                    .find_map(|(selection, range)| {
24076                        if selection.id == newest_selection_id {
24077                            Some(
24078                                (range.start.0 as isize - selection.head().0 as isize)
24079                                    ..(range.end.0 as isize - selection.head().0 as isize),
24080                            )
24081                        } else {
24082                            None
24083                        }
24084                    })
24085            });
24086
24087            cx.emit(EditorEvent::InputHandled {
24088                utf16_range_to_replace: range_to_replace,
24089                text: text.into(),
24090            });
24091
24092            if let Some(new_selected_ranges) = new_selected_ranges {
24093                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24094                    selections.select_ranges(new_selected_ranges)
24095                });
24096                this.backspace(&Default::default(), window, cx);
24097            }
24098
24099            this.handle_input(text, window, cx);
24100        });
24101
24102        if let Some(transaction) = self.ime_transaction {
24103            self.buffer.update(cx, |buffer, cx| {
24104                buffer.group_until_transaction(transaction, cx);
24105            });
24106        }
24107
24108        self.unmark_text(window, cx);
24109    }
24110
24111    fn replace_and_mark_text_in_range(
24112        &mut self,
24113        range_utf16: Option<Range<usize>>,
24114        text: &str,
24115        new_selected_range_utf16: Option<Range<usize>>,
24116        window: &mut Window,
24117        cx: &mut Context<Self>,
24118    ) {
24119        if !self.input_enabled {
24120            return;
24121        }
24122
24123        let transaction = self.transact(window, cx, |this, window, cx| {
24124            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
24125                let snapshot = this.buffer.read(cx).read(cx);
24126                if let Some(relative_range_utf16) = range_utf16.as_ref() {
24127                    for marked_range in &mut marked_ranges {
24128                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
24129                        marked_range.start.0 += relative_range_utf16.start;
24130                        marked_range.start =
24131                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
24132                        marked_range.end =
24133                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
24134                    }
24135                }
24136                Some(marked_ranges)
24137            } else if let Some(range_utf16) = range_utf16 {
24138                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
24139                Some(this.selection_replacement_ranges(range_utf16, cx))
24140            } else {
24141                None
24142            };
24143
24144            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
24145                let newest_selection_id = this.selections.newest_anchor().id;
24146                this.selections
24147                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
24148                    .iter()
24149                    .zip(ranges_to_replace.iter())
24150                    .find_map(|(selection, range)| {
24151                        if selection.id == newest_selection_id {
24152                            Some(
24153                                (range.start.0 as isize - selection.head().0 as isize)
24154                                    ..(range.end.0 as isize - selection.head().0 as isize),
24155                            )
24156                        } else {
24157                            None
24158                        }
24159                    })
24160            });
24161
24162            cx.emit(EditorEvent::InputHandled {
24163                utf16_range_to_replace: range_to_replace,
24164                text: text.into(),
24165            });
24166
24167            if let Some(ranges) = ranges_to_replace {
24168                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24169                    s.select_ranges(ranges)
24170                });
24171            }
24172
24173            let marked_ranges = {
24174                let snapshot = this.buffer.read(cx).read(cx);
24175                this.selections
24176                    .disjoint_anchors_arc()
24177                    .iter()
24178                    .map(|selection| {
24179                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
24180                    })
24181                    .collect::<Vec<_>>()
24182            };
24183
24184            if text.is_empty() {
24185                this.unmark_text(window, cx);
24186            } else {
24187                this.highlight_text::<InputComposition>(
24188                    marked_ranges.clone(),
24189                    HighlightStyle {
24190                        underline: Some(UnderlineStyle {
24191                            thickness: px(1.),
24192                            color: None,
24193                            wavy: false,
24194                        }),
24195                        ..Default::default()
24196                    },
24197                    cx,
24198                );
24199            }
24200
24201            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
24202            let use_autoclose = this.use_autoclose;
24203            let use_auto_surround = this.use_auto_surround;
24204            this.set_use_autoclose(false);
24205            this.set_use_auto_surround(false);
24206            this.handle_input(text, window, cx);
24207            this.set_use_autoclose(use_autoclose);
24208            this.set_use_auto_surround(use_auto_surround);
24209
24210            if let Some(new_selected_range) = new_selected_range_utf16 {
24211                let snapshot = this.buffer.read(cx).read(cx);
24212                let new_selected_ranges = marked_ranges
24213                    .into_iter()
24214                    .map(|marked_range| {
24215                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24216                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
24217                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
24218                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24219                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24220                    })
24221                    .collect::<Vec<_>>();
24222
24223                drop(snapshot);
24224                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24225                    selections.select_ranges(new_selected_ranges)
24226                });
24227            }
24228        });
24229
24230        self.ime_transaction = self.ime_transaction.or(transaction);
24231        if let Some(transaction) = self.ime_transaction {
24232            self.buffer.update(cx, |buffer, cx| {
24233                buffer.group_until_transaction(transaction, cx);
24234            });
24235        }
24236
24237        if self.text_highlights::<InputComposition>(cx).is_none() {
24238            self.ime_transaction.take();
24239        }
24240    }
24241
24242    fn bounds_for_range(
24243        &mut self,
24244        range_utf16: Range<usize>,
24245        element_bounds: gpui::Bounds<Pixels>,
24246        window: &mut Window,
24247        cx: &mut Context<Self>,
24248    ) -> Option<gpui::Bounds<Pixels>> {
24249        let text_layout_details = self.text_layout_details(window);
24250        let CharacterDimensions {
24251            em_width,
24252            em_advance,
24253            line_height,
24254        } = self.character_dimensions(window);
24255
24256        let snapshot = self.snapshot(window, cx);
24257        let scroll_position = snapshot.scroll_position();
24258        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24259
24260        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
24261        let x = Pixels::from(
24262            ScrollOffset::from(
24263                snapshot.x_for_display_point(start, &text_layout_details)
24264                    + self.gutter_dimensions.full_width(),
24265            ) - scroll_left,
24266        );
24267        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24268
24269        Some(Bounds {
24270            origin: element_bounds.origin + point(x, y),
24271            size: size(em_width, line_height),
24272        })
24273    }
24274
24275    fn character_index_for_point(
24276        &mut self,
24277        point: gpui::Point<Pixels>,
24278        _window: &mut Window,
24279        _cx: &mut Context<Self>,
24280    ) -> Option<usize> {
24281        let position_map = self.last_position_map.as_ref()?;
24282        if !position_map.text_hitbox.contains(&point) {
24283            return None;
24284        }
24285        let display_point = position_map.point_for_position(point).previous_valid;
24286        let anchor = position_map
24287            .snapshot
24288            .display_point_to_anchor(display_point, Bias::Left);
24289        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24290        Some(utf16_offset.0)
24291    }
24292
24293    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
24294        self.input_enabled
24295    }
24296}
24297
24298trait SelectionExt {
24299    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24300    fn spanned_rows(
24301        &self,
24302        include_end_if_at_line_start: bool,
24303        map: &DisplaySnapshot,
24304    ) -> Range<MultiBufferRow>;
24305}
24306
24307impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24308    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24309        let start = self
24310            .start
24311            .to_point(map.buffer_snapshot())
24312            .to_display_point(map);
24313        let end = self
24314            .end
24315            .to_point(map.buffer_snapshot())
24316            .to_display_point(map);
24317        if self.reversed {
24318            end..start
24319        } else {
24320            start..end
24321        }
24322    }
24323
24324    fn spanned_rows(
24325        &self,
24326        include_end_if_at_line_start: bool,
24327        map: &DisplaySnapshot,
24328    ) -> Range<MultiBufferRow> {
24329        let start = self.start.to_point(map.buffer_snapshot());
24330        let mut end = self.end.to_point(map.buffer_snapshot());
24331        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24332            end.row -= 1;
24333        }
24334
24335        let buffer_start = map.prev_line_boundary(start).0;
24336        let buffer_end = map.next_line_boundary(end).0;
24337        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24338    }
24339}
24340
24341impl<T: InvalidationRegion> InvalidationStack<T> {
24342    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24343    where
24344        S: Clone + ToOffset,
24345    {
24346        while let Some(region) = self.last() {
24347            let all_selections_inside_invalidation_ranges =
24348                if selections.len() == region.ranges().len() {
24349                    selections
24350                        .iter()
24351                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24352                        .all(|(selection, invalidation_range)| {
24353                            let head = selection.head().to_offset(buffer);
24354                            invalidation_range.start <= head && invalidation_range.end >= head
24355                        })
24356                } else {
24357                    false
24358                };
24359
24360            if all_selections_inside_invalidation_ranges {
24361                break;
24362            } else {
24363                self.pop();
24364            }
24365        }
24366    }
24367}
24368
24369impl<T> Default for InvalidationStack<T> {
24370    fn default() -> Self {
24371        Self(Default::default())
24372    }
24373}
24374
24375impl<T> Deref for InvalidationStack<T> {
24376    type Target = Vec<T>;
24377
24378    fn deref(&self) -> &Self::Target {
24379        &self.0
24380    }
24381}
24382
24383impl<T> DerefMut for InvalidationStack<T> {
24384    fn deref_mut(&mut self) -> &mut Self::Target {
24385        &mut self.0
24386    }
24387}
24388
24389impl InvalidationRegion for SnippetState {
24390    fn ranges(&self) -> &[Range<Anchor>] {
24391        &self.ranges[self.active_index]
24392    }
24393}
24394
24395fn edit_prediction_edit_text(
24396    current_snapshot: &BufferSnapshot,
24397    edits: &[(Range<Anchor>, impl AsRef<str>)],
24398    edit_preview: &EditPreview,
24399    include_deletions: bool,
24400    cx: &App,
24401) -> HighlightedText {
24402    let edits = edits
24403        .iter()
24404        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
24405        .collect::<Vec<_>>();
24406
24407    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24408}
24409
24410fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
24411    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24412    // Just show the raw edit text with basic styling
24413    let mut text = String::new();
24414    let mut highlights = Vec::new();
24415
24416    let insertion_highlight_style = HighlightStyle {
24417        color: Some(cx.theme().colors().text),
24418        ..Default::default()
24419    };
24420
24421    for (_, edit_text) in edits {
24422        let start_offset = text.len();
24423        text.push_str(edit_text);
24424        let end_offset = text.len();
24425
24426        if start_offset < end_offset {
24427            highlights.push((start_offset..end_offset, insertion_highlight_style));
24428        }
24429    }
24430
24431    HighlightedText {
24432        text: text.into(),
24433        highlights,
24434    }
24435}
24436
24437pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24438    match severity {
24439        lsp::DiagnosticSeverity::ERROR => colors.error,
24440        lsp::DiagnosticSeverity::WARNING => colors.warning,
24441        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24442        lsp::DiagnosticSeverity::HINT => colors.info,
24443        _ => colors.ignored,
24444    }
24445}
24446
24447pub fn styled_runs_for_code_label<'a>(
24448    label: &'a CodeLabel,
24449    syntax_theme: &'a theme::SyntaxTheme,
24450) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24451    let fade_out = HighlightStyle {
24452        fade_out: Some(0.35),
24453        ..Default::default()
24454    };
24455
24456    let mut prev_end = label.filter_range.end;
24457    label
24458        .runs
24459        .iter()
24460        .enumerate()
24461        .flat_map(move |(ix, (range, highlight_id))| {
24462            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24463                style
24464            } else {
24465                return Default::default();
24466            };
24467            let muted_style = style.highlight(fade_out);
24468
24469            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24470            if range.start >= label.filter_range.end {
24471                if range.start > prev_end {
24472                    runs.push((prev_end..range.start, fade_out));
24473                }
24474                runs.push((range.clone(), muted_style));
24475            } else if range.end <= label.filter_range.end {
24476                runs.push((range.clone(), style));
24477            } else {
24478                runs.push((range.start..label.filter_range.end, style));
24479                runs.push((label.filter_range.end..range.end, muted_style));
24480            }
24481            prev_end = cmp::max(prev_end, range.end);
24482
24483            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24484                runs.push((prev_end..label.text.len(), fade_out));
24485            }
24486
24487            runs
24488        })
24489}
24490
24491pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24492    let mut prev_index = 0;
24493    let mut prev_codepoint: Option<char> = None;
24494    text.char_indices()
24495        .chain([(text.len(), '\0')])
24496        .filter_map(move |(index, codepoint)| {
24497            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24498            let is_boundary = index == text.len()
24499                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24500                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24501            if is_boundary {
24502                let chunk = &text[prev_index..index];
24503                prev_index = index;
24504                Some(chunk)
24505            } else {
24506                None
24507            }
24508        })
24509}
24510
24511pub trait RangeToAnchorExt: Sized {
24512    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24513
24514    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24515        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
24516        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24517    }
24518}
24519
24520impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24521    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24522        let start_offset = self.start.to_offset(snapshot);
24523        let end_offset = self.end.to_offset(snapshot);
24524        if start_offset == end_offset {
24525            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24526        } else {
24527            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24528        }
24529    }
24530}
24531
24532pub trait RowExt {
24533    fn as_f64(&self) -> f64;
24534
24535    fn next_row(&self) -> Self;
24536
24537    fn previous_row(&self) -> Self;
24538
24539    fn minus(&self, other: Self) -> u32;
24540}
24541
24542impl RowExt for DisplayRow {
24543    fn as_f64(&self) -> f64 {
24544        self.0 as _
24545    }
24546
24547    fn next_row(&self) -> Self {
24548        Self(self.0 + 1)
24549    }
24550
24551    fn previous_row(&self) -> Self {
24552        Self(self.0.saturating_sub(1))
24553    }
24554
24555    fn minus(&self, other: Self) -> u32 {
24556        self.0 - other.0
24557    }
24558}
24559
24560impl RowExt for MultiBufferRow {
24561    fn as_f64(&self) -> f64 {
24562        self.0 as _
24563    }
24564
24565    fn next_row(&self) -> Self {
24566        Self(self.0 + 1)
24567    }
24568
24569    fn previous_row(&self) -> Self {
24570        Self(self.0.saturating_sub(1))
24571    }
24572
24573    fn minus(&self, other: Self) -> u32 {
24574        self.0 - other.0
24575    }
24576}
24577
24578trait RowRangeExt {
24579    type Row;
24580
24581    fn len(&self) -> usize;
24582
24583    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24584}
24585
24586impl RowRangeExt for Range<MultiBufferRow> {
24587    type Row = MultiBufferRow;
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 = MultiBufferRow> {
24594        (self.start.0..self.end.0).map(MultiBufferRow)
24595    }
24596}
24597
24598impl RowRangeExt for Range<DisplayRow> {
24599    type Row = DisplayRow;
24600
24601    fn len(&self) -> usize {
24602        (self.end.0 - self.start.0) as usize
24603    }
24604
24605    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24606        (self.start.0..self.end.0).map(DisplayRow)
24607    }
24608}
24609
24610/// If select range has more than one line, we
24611/// just point the cursor to range.start.
24612fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24613    if range.start.row == range.end.row {
24614        range
24615    } else {
24616        range.start..range.start
24617    }
24618}
24619pub struct KillRing(ClipboardItem);
24620impl Global for KillRing {}
24621
24622const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24623
24624enum BreakpointPromptEditAction {
24625    Log,
24626    Condition,
24627    HitCondition,
24628}
24629
24630struct BreakpointPromptEditor {
24631    pub(crate) prompt: Entity<Editor>,
24632    editor: WeakEntity<Editor>,
24633    breakpoint_anchor: Anchor,
24634    breakpoint: Breakpoint,
24635    edit_action: BreakpointPromptEditAction,
24636    block_ids: HashSet<CustomBlockId>,
24637    editor_margins: Arc<Mutex<EditorMargins>>,
24638    _subscriptions: Vec<Subscription>,
24639}
24640
24641impl BreakpointPromptEditor {
24642    const MAX_LINES: u8 = 4;
24643
24644    fn new(
24645        editor: WeakEntity<Editor>,
24646        breakpoint_anchor: Anchor,
24647        breakpoint: Breakpoint,
24648        edit_action: BreakpointPromptEditAction,
24649        window: &mut Window,
24650        cx: &mut Context<Self>,
24651    ) -> Self {
24652        let base_text = match edit_action {
24653            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24654            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24655            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24656        }
24657        .map(|msg| msg.to_string())
24658        .unwrap_or_default();
24659
24660        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24661        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24662
24663        let prompt = cx.new(|cx| {
24664            let mut prompt = Editor::new(
24665                EditorMode::AutoHeight {
24666                    min_lines: 1,
24667                    max_lines: Some(Self::MAX_LINES as usize),
24668                },
24669                buffer,
24670                None,
24671                window,
24672                cx,
24673            );
24674            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24675            prompt.set_show_cursor_when_unfocused(false, cx);
24676            prompt.set_placeholder_text(
24677                match edit_action {
24678                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24679                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24680                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24681                },
24682                window,
24683                cx,
24684            );
24685
24686            prompt
24687        });
24688
24689        Self {
24690            prompt,
24691            editor,
24692            breakpoint_anchor,
24693            breakpoint,
24694            edit_action,
24695            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24696            block_ids: Default::default(),
24697            _subscriptions: vec![],
24698        }
24699    }
24700
24701    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24702        self.block_ids.extend(block_ids)
24703    }
24704
24705    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24706        if let Some(editor) = self.editor.upgrade() {
24707            let message = self
24708                .prompt
24709                .read(cx)
24710                .buffer
24711                .read(cx)
24712                .as_singleton()
24713                .expect("A multi buffer in breakpoint prompt isn't possible")
24714                .read(cx)
24715                .as_rope()
24716                .to_string();
24717
24718            editor.update(cx, |editor, cx| {
24719                editor.edit_breakpoint_at_anchor(
24720                    self.breakpoint_anchor,
24721                    self.breakpoint.clone(),
24722                    match self.edit_action {
24723                        BreakpointPromptEditAction::Log => {
24724                            BreakpointEditAction::EditLogMessage(message.into())
24725                        }
24726                        BreakpointPromptEditAction::Condition => {
24727                            BreakpointEditAction::EditCondition(message.into())
24728                        }
24729                        BreakpointPromptEditAction::HitCondition => {
24730                            BreakpointEditAction::EditHitCondition(message.into())
24731                        }
24732                    },
24733                    cx,
24734                );
24735
24736                editor.remove_blocks(self.block_ids.clone(), None, cx);
24737                cx.focus_self(window);
24738            });
24739        }
24740    }
24741
24742    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24743        self.editor
24744            .update(cx, |editor, cx| {
24745                editor.remove_blocks(self.block_ids.clone(), None, cx);
24746                window.focus(&editor.focus_handle);
24747            })
24748            .log_err();
24749    }
24750
24751    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24752        let settings = ThemeSettings::get_global(cx);
24753        let text_style = TextStyle {
24754            color: if self.prompt.read(cx).read_only(cx) {
24755                cx.theme().colors().text_disabled
24756            } else {
24757                cx.theme().colors().text
24758            },
24759            font_family: settings.buffer_font.family.clone(),
24760            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24761            font_size: settings.buffer_font_size(cx).into(),
24762            font_weight: settings.buffer_font.weight,
24763            line_height: relative(settings.buffer_line_height.value()),
24764            ..Default::default()
24765        };
24766        EditorElement::new(
24767            &self.prompt,
24768            EditorStyle {
24769                background: cx.theme().colors().editor_background,
24770                local_player: cx.theme().players().local(),
24771                text: text_style,
24772                ..Default::default()
24773            },
24774        )
24775    }
24776}
24777
24778impl Render for BreakpointPromptEditor {
24779    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24780        let editor_margins = *self.editor_margins.lock();
24781        let gutter_dimensions = editor_margins.gutter;
24782        h_flex()
24783            .key_context("Editor")
24784            .bg(cx.theme().colors().editor_background)
24785            .border_y_1()
24786            .border_color(cx.theme().status().info_border)
24787            .size_full()
24788            .py(window.line_height() / 2.5)
24789            .on_action(cx.listener(Self::confirm))
24790            .on_action(cx.listener(Self::cancel))
24791            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24792            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24793    }
24794}
24795
24796impl Focusable for BreakpointPromptEditor {
24797    fn focus_handle(&self, cx: &App) -> FocusHandle {
24798        self.prompt.focus_handle(cx)
24799    }
24800}
24801
24802fn all_edits_insertions_or_deletions(
24803    edits: &Vec<(Range<Anchor>, Arc<str>)>,
24804    snapshot: &MultiBufferSnapshot,
24805) -> bool {
24806    let mut all_insertions = true;
24807    let mut all_deletions = true;
24808
24809    for (range, new_text) in edits.iter() {
24810        let range_is_empty = range.to_offset(snapshot).is_empty();
24811        let text_is_empty = new_text.is_empty();
24812
24813        if range_is_empty != text_is_empty {
24814            if range_is_empty {
24815                all_deletions = false;
24816            } else {
24817                all_insertions = false;
24818            }
24819        } else {
24820            return false;
24821        }
24822
24823        if !all_insertions && !all_deletions {
24824            return false;
24825        }
24826    }
24827    all_insertions || all_deletions
24828}
24829
24830struct MissingEditPredictionKeybindingTooltip;
24831
24832impl Render for MissingEditPredictionKeybindingTooltip {
24833    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24834        ui::tooltip_container(cx, |container, cx| {
24835            container
24836                .flex_shrink_0()
24837                .max_w_80()
24838                .min_h(rems_from_px(124.))
24839                .justify_between()
24840                .child(
24841                    v_flex()
24842                        .flex_1()
24843                        .text_ui_sm(cx)
24844                        .child(Label::new("Conflict with Accept Keybinding"))
24845                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24846                )
24847                .child(
24848                    h_flex()
24849                        .pb_1()
24850                        .gap_1()
24851                        .items_end()
24852                        .w_full()
24853                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24854                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
24855                        }))
24856                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24857                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24858                        })),
24859                )
24860        })
24861    }
24862}
24863
24864#[derive(Debug, Clone, Copy, PartialEq)]
24865pub struct LineHighlight {
24866    pub background: Background,
24867    pub border: Option<gpui::Hsla>,
24868    pub include_gutter: bool,
24869    pub type_id: Option<TypeId>,
24870}
24871
24872struct LineManipulationResult {
24873    pub new_text: String,
24874    pub line_count_before: usize,
24875    pub line_count_after: usize,
24876}
24877
24878fn render_diff_hunk_controls(
24879    row: u32,
24880    status: &DiffHunkStatus,
24881    hunk_range: Range<Anchor>,
24882    is_created_file: bool,
24883    line_height: Pixels,
24884    editor: &Entity<Editor>,
24885    _window: &mut Window,
24886    cx: &mut App,
24887) -> AnyElement {
24888    h_flex()
24889        .h(line_height)
24890        .mr_1()
24891        .gap_1()
24892        .px_0p5()
24893        .pb_1()
24894        .border_x_1()
24895        .border_b_1()
24896        .border_color(cx.theme().colors().border_variant)
24897        .rounded_b_lg()
24898        .bg(cx.theme().colors().editor_background)
24899        .gap_1()
24900        .block_mouse_except_scroll()
24901        .shadow_md()
24902        .child(if status.has_secondary_hunk() {
24903            Button::new(("stage", row as u64), "Stage")
24904                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24905                .tooltip({
24906                    let focus_handle = editor.focus_handle(cx);
24907                    move |_window, cx| {
24908                        Tooltip::for_action_in(
24909                            "Stage Hunk",
24910                            &::git::ToggleStaged,
24911                            &focus_handle,
24912                            cx,
24913                        )
24914                    }
24915                })
24916                .on_click({
24917                    let editor = editor.clone();
24918                    move |_event, _window, cx| {
24919                        editor.update(cx, |editor, cx| {
24920                            editor.stage_or_unstage_diff_hunks(
24921                                true,
24922                                vec![hunk_range.start..hunk_range.start],
24923                                cx,
24924                            );
24925                        });
24926                    }
24927                })
24928        } else {
24929            Button::new(("unstage", row as u64), "Unstage")
24930                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24931                .tooltip({
24932                    let focus_handle = editor.focus_handle(cx);
24933                    move |_window, cx| {
24934                        Tooltip::for_action_in(
24935                            "Unstage Hunk",
24936                            &::git::ToggleStaged,
24937                            &focus_handle,
24938                            cx,
24939                        )
24940                    }
24941                })
24942                .on_click({
24943                    let editor = editor.clone();
24944                    move |_event, _window, cx| {
24945                        editor.update(cx, |editor, cx| {
24946                            editor.stage_or_unstage_diff_hunks(
24947                                false,
24948                                vec![hunk_range.start..hunk_range.start],
24949                                cx,
24950                            );
24951                        });
24952                    }
24953                })
24954        })
24955        .child(
24956            Button::new(("restore", row as u64), "Restore")
24957                .tooltip({
24958                    let focus_handle = editor.focus_handle(cx);
24959                    move |_window, cx| {
24960                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
24961                    }
24962                })
24963                .on_click({
24964                    let editor = editor.clone();
24965                    move |_event, window, cx| {
24966                        editor.update(cx, |editor, cx| {
24967                            let snapshot = editor.snapshot(window, cx);
24968                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
24969                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24970                        });
24971                    }
24972                })
24973                .disabled(is_created_file),
24974        )
24975        .when(
24976            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24977            |el| {
24978                el.child(
24979                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24980                        .shape(IconButtonShape::Square)
24981                        .icon_size(IconSize::Small)
24982                        // .disabled(!has_multiple_hunks)
24983                        .tooltip({
24984                            let focus_handle = editor.focus_handle(cx);
24985                            move |_window, cx| {
24986                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
24987                            }
24988                        })
24989                        .on_click({
24990                            let editor = editor.clone();
24991                            move |_event, window, cx| {
24992                                editor.update(cx, |editor, cx| {
24993                                    let snapshot = editor.snapshot(window, cx);
24994                                    let position =
24995                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
24996                                    editor.go_to_hunk_before_or_after_position(
24997                                        &snapshot,
24998                                        position,
24999                                        Direction::Next,
25000                                        window,
25001                                        cx,
25002                                    );
25003                                    editor.expand_selected_diff_hunks(cx);
25004                                });
25005                            }
25006                        }),
25007                )
25008                .child(
25009                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
25010                        .shape(IconButtonShape::Square)
25011                        .icon_size(IconSize::Small)
25012                        // .disabled(!has_multiple_hunks)
25013                        .tooltip({
25014                            let focus_handle = editor.focus_handle(cx);
25015                            move |_window, cx| {
25016                                Tooltip::for_action_in(
25017                                    "Previous Hunk",
25018                                    &GoToPreviousHunk,
25019                                    &focus_handle,
25020                                    cx,
25021                                )
25022                            }
25023                        })
25024                        .on_click({
25025                            let editor = editor.clone();
25026                            move |_event, window, cx| {
25027                                editor.update(cx, |editor, cx| {
25028                                    let snapshot = editor.snapshot(window, cx);
25029                                    let point =
25030                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
25031                                    editor.go_to_hunk_before_or_after_position(
25032                                        &snapshot,
25033                                        point,
25034                                        Direction::Prev,
25035                                        window,
25036                                        cx,
25037                                    );
25038                                    editor.expand_selected_diff_hunks(cx);
25039                                });
25040                            }
25041                        }),
25042                )
25043            },
25044        )
25045        .into_any_element()
25046}
25047
25048pub fn multibuffer_context_lines(cx: &App) -> u32 {
25049    EditorSettings::try_get(cx)
25050        .map(|settings| settings.excerpt_context_lines)
25051        .unwrap_or(2)
25052        .min(32)
25053}