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        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3370        if !other_selections.is_empty() {
 3371            self.selections
 3372                .change_with(&self.display_snapshot(cx), |selections| {
 3373                    selections.select_anchors(other_selections);
 3374                });
 3375        }
 3376
 3377        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3378            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3379                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3380                if other_selections.is_empty() {
 3381                    return;
 3382                }
 3383                let snapshot = this.display_snapshot(cx);
 3384                this.selections.change_with(&snapshot, |selections| {
 3385                    selections.select_anchors(other_selections);
 3386                });
 3387            }
 3388        });
 3389
 3390        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3391            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3392                let these_selections = this.selections.disjoint_anchors().to_vec();
 3393                if these_selections.is_empty() {
 3394                    return;
 3395                }
 3396                other.update(cx, |other_editor, cx| {
 3397                    let snapshot = other_editor.display_snapshot(cx);
 3398                    other_editor
 3399                        .selections
 3400                        .change_with(&snapshot, |selections| {
 3401                            selections.select_anchors(these_selections);
 3402                        })
 3403                });
 3404            }
 3405        });
 3406
 3407        Subscription::join(other_subscription, this_subscription)
 3408    }
 3409
 3410    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3411    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3412    /// effects of selection change occur at the end of the transaction.
 3413    pub fn change_selections<R>(
 3414        &mut self,
 3415        effects: SelectionEffects,
 3416        window: &mut Window,
 3417        cx: &mut Context<Self>,
 3418        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 3419    ) -> R {
 3420        let snapshot = self.display_snapshot(cx);
 3421        if let Some(state) = &mut self.deferred_selection_effects_state {
 3422            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3423            state.effects.completions = effects.completions;
 3424            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3425            let (changed, result) = self.selections.change_with(&snapshot, change);
 3426            state.changed |= changed;
 3427            return result;
 3428        }
 3429        let mut state = DeferredSelectionEffectsState {
 3430            changed: false,
 3431            effects,
 3432            old_cursor_position: self.selections.newest_anchor().head(),
 3433            history_entry: SelectionHistoryEntry {
 3434                selections: self.selections.disjoint_anchors_arc(),
 3435                select_next_state: self.select_next_state.clone(),
 3436                select_prev_state: self.select_prev_state.clone(),
 3437                add_selections_state: self.add_selections_state.clone(),
 3438            },
 3439        };
 3440        let (changed, result) = self.selections.change_with(&snapshot, change);
 3441        state.changed = state.changed || changed;
 3442        if self.defer_selection_effects {
 3443            self.deferred_selection_effects_state = Some(state);
 3444        } else {
 3445            self.apply_selection_effects(state, window, cx);
 3446        }
 3447        result
 3448    }
 3449
 3450    /// Defers the effects of selection change, so that the effects of multiple calls to
 3451    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3452    /// to selection history and the state of popovers based on selection position aren't
 3453    /// erroneously updated.
 3454    pub fn with_selection_effects_deferred<R>(
 3455        &mut self,
 3456        window: &mut Window,
 3457        cx: &mut Context<Self>,
 3458        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3459    ) -> R {
 3460        let already_deferred = self.defer_selection_effects;
 3461        self.defer_selection_effects = true;
 3462        let result = update(self, window, cx);
 3463        if !already_deferred {
 3464            self.defer_selection_effects = false;
 3465            if let Some(state) = self.deferred_selection_effects_state.take() {
 3466                self.apply_selection_effects(state, window, cx);
 3467            }
 3468        }
 3469        result
 3470    }
 3471
 3472    fn apply_selection_effects(
 3473        &mut self,
 3474        state: DeferredSelectionEffectsState,
 3475        window: &mut Window,
 3476        cx: &mut Context<Self>,
 3477    ) {
 3478        if state.changed {
 3479            self.selection_history.push(state.history_entry);
 3480
 3481            if let Some(autoscroll) = state.effects.scroll {
 3482                self.request_autoscroll(autoscroll, cx);
 3483            }
 3484
 3485            let old_cursor_position = &state.old_cursor_position;
 3486
 3487            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3488
 3489            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3490                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3491            }
 3492        }
 3493    }
 3494
 3495    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3496    where
 3497        I: IntoIterator<Item = (Range<S>, T)>,
 3498        S: ToOffset,
 3499        T: Into<Arc<str>>,
 3500    {
 3501        if self.read_only(cx) {
 3502            return;
 3503        }
 3504
 3505        self.buffer
 3506            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3507    }
 3508
 3509    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3510    where
 3511        I: IntoIterator<Item = (Range<S>, T)>,
 3512        S: ToOffset,
 3513        T: Into<Arc<str>>,
 3514    {
 3515        if self.read_only(cx) {
 3516            return;
 3517        }
 3518
 3519        self.buffer.update(cx, |buffer, cx| {
 3520            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3521        });
 3522    }
 3523
 3524    pub fn edit_with_block_indent<I, S, T>(
 3525        &mut self,
 3526        edits: I,
 3527        original_indent_columns: Vec<Option<u32>>,
 3528        cx: &mut Context<Self>,
 3529    ) where
 3530        I: IntoIterator<Item = (Range<S>, T)>,
 3531        S: ToOffset,
 3532        T: Into<Arc<str>>,
 3533    {
 3534        if self.read_only(cx) {
 3535            return;
 3536        }
 3537
 3538        self.buffer.update(cx, |buffer, cx| {
 3539            buffer.edit(
 3540                edits,
 3541                Some(AutoindentMode::Block {
 3542                    original_indent_columns,
 3543                }),
 3544                cx,
 3545            )
 3546        });
 3547    }
 3548
 3549    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3550        self.hide_context_menu(window, cx);
 3551
 3552        match phase {
 3553            SelectPhase::Begin {
 3554                position,
 3555                add,
 3556                click_count,
 3557            } => self.begin_selection(position, add, click_count, window, cx),
 3558            SelectPhase::BeginColumnar {
 3559                position,
 3560                goal_column,
 3561                reset,
 3562                mode,
 3563            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3564            SelectPhase::Extend {
 3565                position,
 3566                click_count,
 3567            } => self.extend_selection(position, click_count, window, cx),
 3568            SelectPhase::Update {
 3569                position,
 3570                goal_column,
 3571                scroll_delta,
 3572            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3573            SelectPhase::End => self.end_selection(window, cx),
 3574        }
 3575    }
 3576
 3577    fn extend_selection(
 3578        &mut self,
 3579        position: DisplayPoint,
 3580        click_count: usize,
 3581        window: &mut Window,
 3582        cx: &mut Context<Self>,
 3583    ) {
 3584        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3585        let tail = self.selections.newest::<usize>(&display_map).tail();
 3586        let click_count = click_count.max(match self.selections.select_mode() {
 3587            SelectMode::Character => 1,
 3588            SelectMode::Word(_) => 2,
 3589            SelectMode::Line(_) => 3,
 3590            SelectMode::All => 4,
 3591        });
 3592        self.begin_selection(position, false, click_count, window, cx);
 3593
 3594        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3595
 3596        let current_selection = match self.selections.select_mode() {
 3597            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3598            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3599        };
 3600
 3601        let mut pending_selection = self
 3602            .selections
 3603            .pending_anchor()
 3604            .cloned()
 3605            .expect("extend_selection not called with pending selection");
 3606
 3607        if pending_selection
 3608            .start
 3609            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3610            == Ordering::Greater
 3611        {
 3612            pending_selection.start = current_selection.start;
 3613        }
 3614        if pending_selection
 3615            .end
 3616            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3617            == Ordering::Less
 3618        {
 3619            pending_selection.end = current_selection.end;
 3620            pending_selection.reversed = true;
 3621        }
 3622
 3623        let mut pending_mode = self.selections.pending_mode().unwrap();
 3624        match &mut pending_mode {
 3625            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3626            _ => {}
 3627        }
 3628
 3629        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3630            SelectionEffects::scroll(Autoscroll::fit())
 3631        } else {
 3632            SelectionEffects::no_scroll()
 3633        };
 3634
 3635        self.change_selections(effects, window, cx, |s| {
 3636            s.set_pending(pending_selection.clone(), pending_mode);
 3637            s.set_is_extending(true);
 3638        });
 3639    }
 3640
 3641    fn begin_selection(
 3642        &mut self,
 3643        position: DisplayPoint,
 3644        add: bool,
 3645        click_count: usize,
 3646        window: &mut Window,
 3647        cx: &mut Context<Self>,
 3648    ) {
 3649        if !self.focus_handle.is_focused(window) {
 3650            self.last_focused_descendant = None;
 3651            window.focus(&self.focus_handle);
 3652        }
 3653
 3654        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3655        let buffer = display_map.buffer_snapshot();
 3656        let position = display_map.clip_point(position, Bias::Left);
 3657
 3658        let start;
 3659        let end;
 3660        let mode;
 3661        let mut auto_scroll;
 3662        match click_count {
 3663            1 => {
 3664                start = buffer.anchor_before(position.to_point(&display_map));
 3665                end = start;
 3666                mode = SelectMode::Character;
 3667                auto_scroll = true;
 3668            }
 3669            2 => {
 3670                let position = display_map
 3671                    .clip_point(position, Bias::Left)
 3672                    .to_offset(&display_map, Bias::Left);
 3673                let (range, _) = buffer.surrounding_word(position, None);
 3674                start = buffer.anchor_before(range.start);
 3675                end = buffer.anchor_before(range.end);
 3676                mode = SelectMode::Word(start..end);
 3677                auto_scroll = true;
 3678            }
 3679            3 => {
 3680                let position = display_map
 3681                    .clip_point(position, Bias::Left)
 3682                    .to_point(&display_map);
 3683                let line_start = display_map.prev_line_boundary(position).0;
 3684                let next_line_start = buffer.clip_point(
 3685                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3686                    Bias::Left,
 3687                );
 3688                start = buffer.anchor_before(line_start);
 3689                end = buffer.anchor_before(next_line_start);
 3690                mode = SelectMode::Line(start..end);
 3691                auto_scroll = true;
 3692            }
 3693            _ => {
 3694                start = buffer.anchor_before(0);
 3695                end = buffer.anchor_before(buffer.len());
 3696                mode = SelectMode::All;
 3697                auto_scroll = false;
 3698            }
 3699        }
 3700        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3701
 3702        let point_to_delete: Option<usize> = {
 3703            let selected_points: Vec<Selection<Point>> =
 3704                self.selections.disjoint_in_range(start..end, &display_map);
 3705
 3706            if !add || click_count > 1 {
 3707                None
 3708            } else if !selected_points.is_empty() {
 3709                Some(selected_points[0].id)
 3710            } else {
 3711                let clicked_point_already_selected =
 3712                    self.selections.disjoint_anchors().iter().find(|selection| {
 3713                        selection.start.to_point(buffer) == start.to_point(buffer)
 3714                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3715                    });
 3716
 3717                clicked_point_already_selected.map(|selection| selection.id)
 3718            }
 3719        };
 3720
 3721        let selections_count = self.selections.count();
 3722        let effects = if auto_scroll {
 3723            SelectionEffects::default()
 3724        } else {
 3725            SelectionEffects::no_scroll()
 3726        };
 3727
 3728        self.change_selections(effects, window, cx, |s| {
 3729            if let Some(point_to_delete) = point_to_delete {
 3730                s.delete(point_to_delete);
 3731
 3732                if selections_count == 1 {
 3733                    s.set_pending_anchor_range(start..end, mode);
 3734                }
 3735            } else {
 3736                if !add {
 3737                    s.clear_disjoint();
 3738                }
 3739
 3740                s.set_pending_anchor_range(start..end, mode);
 3741            }
 3742        });
 3743    }
 3744
 3745    fn begin_columnar_selection(
 3746        &mut self,
 3747        position: DisplayPoint,
 3748        goal_column: u32,
 3749        reset: bool,
 3750        mode: ColumnarMode,
 3751        window: &mut Window,
 3752        cx: &mut Context<Self>,
 3753    ) {
 3754        if !self.focus_handle.is_focused(window) {
 3755            self.last_focused_descendant = None;
 3756            window.focus(&self.focus_handle);
 3757        }
 3758
 3759        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3760
 3761        if reset {
 3762            let pointer_position = display_map
 3763                .buffer_snapshot()
 3764                .anchor_before(position.to_point(&display_map));
 3765
 3766            self.change_selections(
 3767                SelectionEffects::scroll(Autoscroll::newest()),
 3768                window,
 3769                cx,
 3770                |s| {
 3771                    s.clear_disjoint();
 3772                    s.set_pending_anchor_range(
 3773                        pointer_position..pointer_position,
 3774                        SelectMode::Character,
 3775                    );
 3776                },
 3777            );
 3778        };
 3779
 3780        let tail = self.selections.newest::<Point>(&display_map).tail();
 3781        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3782        self.columnar_selection_state = match mode {
 3783            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3784                selection_tail: selection_anchor,
 3785                display_point: if reset {
 3786                    if position.column() != goal_column {
 3787                        Some(DisplayPoint::new(position.row(), goal_column))
 3788                    } else {
 3789                        None
 3790                    }
 3791                } else {
 3792                    None
 3793                },
 3794            }),
 3795            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3796                selection_tail: selection_anchor,
 3797            }),
 3798        };
 3799
 3800        if !reset {
 3801            self.select_columns(position, goal_column, &display_map, window, cx);
 3802        }
 3803    }
 3804
 3805    fn update_selection(
 3806        &mut self,
 3807        position: DisplayPoint,
 3808        goal_column: u32,
 3809        scroll_delta: gpui::Point<f32>,
 3810        window: &mut Window,
 3811        cx: &mut Context<Self>,
 3812    ) {
 3813        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3814
 3815        if self.columnar_selection_state.is_some() {
 3816            self.select_columns(position, goal_column, &display_map, window, cx);
 3817        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3818            let buffer = display_map.buffer_snapshot();
 3819            let head;
 3820            let tail;
 3821            let mode = self.selections.pending_mode().unwrap();
 3822            match &mode {
 3823                SelectMode::Character => {
 3824                    head = position.to_point(&display_map);
 3825                    tail = pending.tail().to_point(buffer);
 3826                }
 3827                SelectMode::Word(original_range) => {
 3828                    let offset = display_map
 3829                        .clip_point(position, Bias::Left)
 3830                        .to_offset(&display_map, Bias::Left);
 3831                    let original_range = original_range.to_offset(buffer);
 3832
 3833                    let head_offset = if buffer.is_inside_word(offset, None)
 3834                        || original_range.contains(&offset)
 3835                    {
 3836                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3837                        if word_range.start < original_range.start {
 3838                            word_range.start
 3839                        } else {
 3840                            word_range.end
 3841                        }
 3842                    } else {
 3843                        offset
 3844                    };
 3845
 3846                    head = head_offset.to_point(buffer);
 3847                    if head_offset <= original_range.start {
 3848                        tail = original_range.end.to_point(buffer);
 3849                    } else {
 3850                        tail = original_range.start.to_point(buffer);
 3851                    }
 3852                }
 3853                SelectMode::Line(original_range) => {
 3854                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3855
 3856                    let position = display_map
 3857                        .clip_point(position, Bias::Left)
 3858                        .to_point(&display_map);
 3859                    let line_start = display_map.prev_line_boundary(position).0;
 3860                    let next_line_start = buffer.clip_point(
 3861                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3862                        Bias::Left,
 3863                    );
 3864
 3865                    if line_start < original_range.start {
 3866                        head = line_start
 3867                    } else {
 3868                        head = next_line_start
 3869                    }
 3870
 3871                    if head <= original_range.start {
 3872                        tail = original_range.end;
 3873                    } else {
 3874                        tail = original_range.start;
 3875                    }
 3876                }
 3877                SelectMode::All => {
 3878                    return;
 3879                }
 3880            };
 3881
 3882            if head < tail {
 3883                pending.start = buffer.anchor_before(head);
 3884                pending.end = buffer.anchor_before(tail);
 3885                pending.reversed = true;
 3886            } else {
 3887                pending.start = buffer.anchor_before(tail);
 3888                pending.end = buffer.anchor_before(head);
 3889                pending.reversed = false;
 3890            }
 3891
 3892            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3893                s.set_pending(pending.clone(), mode);
 3894            });
 3895        } else {
 3896            log::error!("update_selection dispatched with no pending selection");
 3897            return;
 3898        }
 3899
 3900        self.apply_scroll_delta(scroll_delta, window, cx);
 3901        cx.notify();
 3902    }
 3903
 3904    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3905        self.columnar_selection_state.take();
 3906        if let Some(pending_mode) = self.selections.pending_mode() {
 3907            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3908            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3909                s.select(selections);
 3910                s.clear_pending();
 3911                if s.is_extending() {
 3912                    s.set_is_extending(false);
 3913                } else {
 3914                    s.set_select_mode(pending_mode);
 3915                }
 3916            });
 3917        }
 3918    }
 3919
 3920    fn select_columns(
 3921        &mut self,
 3922        head: DisplayPoint,
 3923        goal_column: u32,
 3924        display_map: &DisplaySnapshot,
 3925        window: &mut Window,
 3926        cx: &mut Context<Self>,
 3927    ) {
 3928        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3929            return;
 3930        };
 3931
 3932        let tail = match columnar_state {
 3933            ColumnarSelectionState::FromMouse {
 3934                selection_tail,
 3935                display_point,
 3936            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3937            ColumnarSelectionState::FromSelection { selection_tail } => {
 3938                selection_tail.to_display_point(display_map)
 3939            }
 3940        };
 3941
 3942        let start_row = cmp::min(tail.row(), head.row());
 3943        let end_row = cmp::max(tail.row(), head.row());
 3944        let start_column = cmp::min(tail.column(), goal_column);
 3945        let end_column = cmp::max(tail.column(), goal_column);
 3946        let reversed = start_column < tail.column();
 3947
 3948        let selection_ranges = (start_row.0..=end_row.0)
 3949            .map(DisplayRow)
 3950            .filter_map(|row| {
 3951                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3952                    || start_column <= display_map.line_len(row))
 3953                    && !display_map.is_block_line(row)
 3954                {
 3955                    let start = display_map
 3956                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3957                        .to_point(display_map);
 3958                    let end = display_map
 3959                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3960                        .to_point(display_map);
 3961                    if reversed {
 3962                        Some(end..start)
 3963                    } else {
 3964                        Some(start..end)
 3965                    }
 3966                } else {
 3967                    None
 3968                }
 3969            })
 3970            .collect::<Vec<_>>();
 3971        if selection_ranges.is_empty() {
 3972            return;
 3973        }
 3974
 3975        let ranges = match columnar_state {
 3976            ColumnarSelectionState::FromMouse { .. } => {
 3977                let mut non_empty_ranges = selection_ranges
 3978                    .iter()
 3979                    .filter(|selection_range| selection_range.start != selection_range.end)
 3980                    .peekable();
 3981                if non_empty_ranges.peek().is_some() {
 3982                    non_empty_ranges.cloned().collect()
 3983                } else {
 3984                    selection_ranges
 3985                }
 3986            }
 3987            _ => selection_ranges,
 3988        };
 3989
 3990        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3991            s.select_ranges(ranges);
 3992        });
 3993        cx.notify();
 3994    }
 3995
 3996    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 3997        self.selections
 3998            .all_adjusted(snapshot)
 3999            .iter()
 4000            .any(|selection| !selection.is_empty())
 4001    }
 4002
 4003    pub fn has_pending_nonempty_selection(&self) -> bool {
 4004        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4005            Some(Selection { start, end, .. }) => start != end,
 4006            None => false,
 4007        };
 4008
 4009        pending_nonempty_selection
 4010            || (self.columnar_selection_state.is_some()
 4011                && self.selections.disjoint_anchors().len() > 1)
 4012    }
 4013
 4014    pub fn has_pending_selection(&self) -> bool {
 4015        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4016    }
 4017
 4018    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4019        self.selection_mark_mode = false;
 4020        self.selection_drag_state = SelectionDragState::None;
 4021
 4022        if self.clear_expanded_diff_hunks(cx) {
 4023            cx.notify();
 4024            return;
 4025        }
 4026        if self.dismiss_menus_and_popups(true, window, cx) {
 4027            return;
 4028        }
 4029
 4030        if self.mode.is_full()
 4031            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4032        {
 4033            return;
 4034        }
 4035
 4036        cx.propagate();
 4037    }
 4038
 4039    pub fn dismiss_menus_and_popups(
 4040        &mut self,
 4041        is_user_requested: bool,
 4042        window: &mut Window,
 4043        cx: &mut Context<Self>,
 4044    ) -> bool {
 4045        if self.take_rename(false, window, cx).is_some() {
 4046            return true;
 4047        }
 4048
 4049        if self.hide_blame_popover(true, cx) {
 4050            return true;
 4051        }
 4052
 4053        if hide_hover(self, cx) {
 4054            return true;
 4055        }
 4056
 4057        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 4058            return true;
 4059        }
 4060
 4061        if self.hide_context_menu(window, cx).is_some() {
 4062            return true;
 4063        }
 4064
 4065        if self.mouse_context_menu.take().is_some() {
 4066            return true;
 4067        }
 4068
 4069        if is_user_requested && self.discard_edit_prediction(true, cx) {
 4070            return true;
 4071        }
 4072
 4073        if self.snippet_stack.pop().is_some() {
 4074            return true;
 4075        }
 4076
 4077        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4078            self.dismiss_diagnostics(cx);
 4079            return true;
 4080        }
 4081
 4082        false
 4083    }
 4084
 4085    fn linked_editing_ranges_for(
 4086        &self,
 4087        selection: Range<text::Anchor>,
 4088        cx: &App,
 4089    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4090        if self.linked_edit_ranges.is_empty() {
 4091            return None;
 4092        }
 4093        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4094            selection.end.buffer_id.and_then(|end_buffer_id| {
 4095                if selection.start.buffer_id != Some(end_buffer_id) {
 4096                    return None;
 4097                }
 4098                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4099                let snapshot = buffer.read(cx).snapshot();
 4100                self.linked_edit_ranges
 4101                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4102                    .map(|ranges| (ranges, snapshot, buffer))
 4103            })?;
 4104        use text::ToOffset as TO;
 4105        // find offset from the start of current range to current cursor position
 4106        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4107
 4108        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4109        let start_difference = start_offset - start_byte_offset;
 4110        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4111        let end_difference = end_offset - start_byte_offset;
 4112        // Current range has associated linked ranges.
 4113        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4114        for range in linked_ranges.iter() {
 4115            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4116            let end_offset = start_offset + end_difference;
 4117            let start_offset = start_offset + start_difference;
 4118            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4119                continue;
 4120            }
 4121            if self.selections.disjoint_anchor_ranges().any(|s| {
 4122                if s.start.buffer_id != selection.start.buffer_id
 4123                    || s.end.buffer_id != selection.end.buffer_id
 4124                {
 4125                    return false;
 4126                }
 4127                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4128                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4129            }) {
 4130                continue;
 4131            }
 4132            let start = buffer_snapshot.anchor_after(start_offset);
 4133            let end = buffer_snapshot.anchor_after(end_offset);
 4134            linked_edits
 4135                .entry(buffer.clone())
 4136                .or_default()
 4137                .push(start..end);
 4138        }
 4139        Some(linked_edits)
 4140    }
 4141
 4142    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4143        let text: Arc<str> = text.into();
 4144
 4145        if self.read_only(cx) {
 4146            return;
 4147        }
 4148
 4149        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4150
 4151        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4152        let mut bracket_inserted = false;
 4153        let mut edits = Vec::new();
 4154        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4155        let mut new_selections = Vec::with_capacity(selections.len());
 4156        let mut new_autoclose_regions = Vec::new();
 4157        let snapshot = self.buffer.read(cx).read(cx);
 4158        let mut clear_linked_edit_ranges = false;
 4159
 4160        for (selection, autoclose_region) in
 4161            self.selections_with_autoclose_regions(selections, &snapshot)
 4162        {
 4163            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4164                // Determine if the inserted text matches the opening or closing
 4165                // bracket of any of this language's bracket pairs.
 4166                let mut bracket_pair = None;
 4167                let mut is_bracket_pair_start = false;
 4168                let mut is_bracket_pair_end = false;
 4169                if !text.is_empty() {
 4170                    let mut bracket_pair_matching_end = None;
 4171                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4172                    //  and they are removing the character that triggered IME popup.
 4173                    for (pair, enabled) in scope.brackets() {
 4174                        if !pair.close && !pair.surround {
 4175                            continue;
 4176                        }
 4177
 4178                        if enabled && pair.start.ends_with(text.as_ref()) {
 4179                            let prefix_len = pair.start.len() - text.len();
 4180                            let preceding_text_matches_prefix = prefix_len == 0
 4181                                || (selection.start.column >= (prefix_len as u32)
 4182                                    && snapshot.contains_str_at(
 4183                                        Point::new(
 4184                                            selection.start.row,
 4185                                            selection.start.column - (prefix_len as u32),
 4186                                        ),
 4187                                        &pair.start[..prefix_len],
 4188                                    ));
 4189                            if preceding_text_matches_prefix {
 4190                                bracket_pair = Some(pair.clone());
 4191                                is_bracket_pair_start = true;
 4192                                break;
 4193                            }
 4194                        }
 4195                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4196                        {
 4197                            // take first bracket pair matching end, but don't break in case a later bracket
 4198                            // pair matches start
 4199                            bracket_pair_matching_end = Some(pair.clone());
 4200                        }
 4201                    }
 4202                    if let Some(end) = bracket_pair_matching_end
 4203                        && bracket_pair.is_none()
 4204                    {
 4205                        bracket_pair = Some(end);
 4206                        is_bracket_pair_end = true;
 4207                    }
 4208                }
 4209
 4210                if let Some(bracket_pair) = bracket_pair {
 4211                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4212                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4213                    let auto_surround =
 4214                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4215                    if selection.is_empty() {
 4216                        if is_bracket_pair_start {
 4217                            // If the inserted text is a suffix of an opening bracket and the
 4218                            // selection is preceded by the rest of the opening bracket, then
 4219                            // insert the closing bracket.
 4220                            let following_text_allows_autoclose = snapshot
 4221                                .chars_at(selection.start)
 4222                                .next()
 4223                                .is_none_or(|c| scope.should_autoclose_before(c));
 4224
 4225                            let preceding_text_allows_autoclose = selection.start.column == 0
 4226                                || snapshot
 4227                                    .reversed_chars_at(selection.start)
 4228                                    .next()
 4229                                    .is_none_or(|c| {
 4230                                        bracket_pair.start != bracket_pair.end
 4231                                            || !snapshot
 4232                                                .char_classifier_at(selection.start)
 4233                                                .is_word(c)
 4234                                    });
 4235
 4236                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4237                                && bracket_pair.start.len() == 1
 4238                            {
 4239                                let target = bracket_pair.start.chars().next().unwrap();
 4240                                let current_line_count = snapshot
 4241                                    .reversed_chars_at(selection.start)
 4242                                    .take_while(|&c| c != '\n')
 4243                                    .filter(|&c| c == target)
 4244                                    .count();
 4245                                current_line_count % 2 == 1
 4246                            } else {
 4247                                false
 4248                            };
 4249
 4250                            if autoclose
 4251                                && bracket_pair.close
 4252                                && following_text_allows_autoclose
 4253                                && preceding_text_allows_autoclose
 4254                                && !is_closing_quote
 4255                            {
 4256                                let anchor = snapshot.anchor_before(selection.end);
 4257                                new_selections.push((selection.map(|_| anchor), text.len()));
 4258                                new_autoclose_regions.push((
 4259                                    anchor,
 4260                                    text.len(),
 4261                                    selection.id,
 4262                                    bracket_pair.clone(),
 4263                                ));
 4264                                edits.push((
 4265                                    selection.range(),
 4266                                    format!("{}{}", text, bracket_pair.end).into(),
 4267                                ));
 4268                                bracket_inserted = true;
 4269                                continue;
 4270                            }
 4271                        }
 4272
 4273                        if let Some(region) = autoclose_region {
 4274                            // If the selection is followed by an auto-inserted closing bracket,
 4275                            // then don't insert that closing bracket again; just move the selection
 4276                            // past the closing bracket.
 4277                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4278                                && text.as_ref() == region.pair.end.as_str()
 4279                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4280                            if should_skip {
 4281                                let anchor = snapshot.anchor_after(selection.end);
 4282                                new_selections
 4283                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4284                                continue;
 4285                            }
 4286                        }
 4287
 4288                        let always_treat_brackets_as_autoclosed = snapshot
 4289                            .language_settings_at(selection.start, cx)
 4290                            .always_treat_brackets_as_autoclosed;
 4291                        if always_treat_brackets_as_autoclosed
 4292                            && is_bracket_pair_end
 4293                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4294                        {
 4295                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4296                            // and the inserted text is a closing bracket and the selection is followed
 4297                            // by the closing bracket then move the selection past the closing bracket.
 4298                            let anchor = snapshot.anchor_after(selection.end);
 4299                            new_selections.push((selection.map(|_| anchor), text.len()));
 4300                            continue;
 4301                        }
 4302                    }
 4303                    // If an opening bracket is 1 character long and is typed while
 4304                    // text is selected, then surround that text with the bracket pair.
 4305                    else if auto_surround
 4306                        && bracket_pair.surround
 4307                        && is_bracket_pair_start
 4308                        && bracket_pair.start.chars().count() == 1
 4309                    {
 4310                        edits.push((selection.start..selection.start, text.clone()));
 4311                        edits.push((
 4312                            selection.end..selection.end,
 4313                            bracket_pair.end.as_str().into(),
 4314                        ));
 4315                        bracket_inserted = true;
 4316                        new_selections.push((
 4317                            Selection {
 4318                                id: selection.id,
 4319                                start: snapshot.anchor_after(selection.start),
 4320                                end: snapshot.anchor_before(selection.end),
 4321                                reversed: selection.reversed,
 4322                                goal: selection.goal,
 4323                            },
 4324                            0,
 4325                        ));
 4326                        continue;
 4327                    }
 4328                }
 4329            }
 4330
 4331            if self.auto_replace_emoji_shortcode
 4332                && selection.is_empty()
 4333                && text.as_ref().ends_with(':')
 4334                && let Some(possible_emoji_short_code) =
 4335                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4336                && !possible_emoji_short_code.is_empty()
 4337                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4338            {
 4339                let emoji_shortcode_start = Point::new(
 4340                    selection.start.row,
 4341                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4342                );
 4343
 4344                // Remove shortcode from buffer
 4345                edits.push((
 4346                    emoji_shortcode_start..selection.start,
 4347                    "".to_string().into(),
 4348                ));
 4349                new_selections.push((
 4350                    Selection {
 4351                        id: selection.id,
 4352                        start: snapshot.anchor_after(emoji_shortcode_start),
 4353                        end: snapshot.anchor_before(selection.start),
 4354                        reversed: selection.reversed,
 4355                        goal: selection.goal,
 4356                    },
 4357                    0,
 4358                ));
 4359
 4360                // Insert emoji
 4361                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4362                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4363                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4364
 4365                continue;
 4366            }
 4367
 4368            // If not handling any auto-close operation, then just replace the selected
 4369            // text with the given input and move the selection to the end of the
 4370            // newly inserted text.
 4371            let anchor = snapshot.anchor_after(selection.end);
 4372            if !self.linked_edit_ranges.is_empty() {
 4373                let start_anchor = snapshot.anchor_before(selection.start);
 4374
 4375                let is_word_char = text.chars().next().is_none_or(|char| {
 4376                    let classifier = snapshot
 4377                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4378                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4379                    classifier.is_word(char)
 4380                });
 4381
 4382                if is_word_char {
 4383                    if let Some(ranges) = self
 4384                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4385                    {
 4386                        for (buffer, edits) in ranges {
 4387                            linked_edits
 4388                                .entry(buffer.clone())
 4389                                .or_default()
 4390                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4391                        }
 4392                    }
 4393                } else {
 4394                    clear_linked_edit_ranges = true;
 4395                }
 4396            }
 4397
 4398            new_selections.push((selection.map(|_| anchor), 0));
 4399            edits.push((selection.start..selection.end, text.clone()));
 4400        }
 4401
 4402        drop(snapshot);
 4403
 4404        self.transact(window, cx, |this, window, cx| {
 4405            if clear_linked_edit_ranges {
 4406                this.linked_edit_ranges.clear();
 4407            }
 4408            let initial_buffer_versions =
 4409                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4410
 4411            this.buffer.update(cx, |buffer, cx| {
 4412                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4413            });
 4414            for (buffer, edits) in linked_edits {
 4415                buffer.update(cx, |buffer, cx| {
 4416                    let snapshot = buffer.snapshot();
 4417                    let edits = edits
 4418                        .into_iter()
 4419                        .map(|(range, text)| {
 4420                            use text::ToPoint as TP;
 4421                            let end_point = TP::to_point(&range.end, &snapshot);
 4422                            let start_point = TP::to_point(&range.start, &snapshot);
 4423                            (start_point..end_point, text)
 4424                        })
 4425                        .sorted_by_key(|(range, _)| range.start);
 4426                    buffer.edit(edits, None, cx);
 4427                })
 4428            }
 4429            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4430            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4431            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4432            let new_selections =
 4433                resolve_selections_wrapping_blocks::<usize, _>(new_anchor_selections, &map)
 4434                    .zip(new_selection_deltas)
 4435                    .map(|(selection, delta)| Selection {
 4436                        id: selection.id,
 4437                        start: selection.start + delta,
 4438                        end: selection.end + delta,
 4439                        reversed: selection.reversed,
 4440                        goal: SelectionGoal::None,
 4441                    })
 4442                    .collect::<Vec<_>>();
 4443
 4444            let mut i = 0;
 4445            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4446                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4447                let start = map.buffer_snapshot().anchor_before(position);
 4448                let end = map.buffer_snapshot().anchor_after(position);
 4449                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4450                    match existing_state
 4451                        .range
 4452                        .start
 4453                        .cmp(&start, map.buffer_snapshot())
 4454                    {
 4455                        Ordering::Less => i += 1,
 4456                        Ordering::Greater => break,
 4457                        Ordering::Equal => {
 4458                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4459                                Ordering::Less => i += 1,
 4460                                Ordering::Equal => break,
 4461                                Ordering::Greater => break,
 4462                            }
 4463                        }
 4464                    }
 4465                }
 4466                this.autoclose_regions.insert(
 4467                    i,
 4468                    AutocloseRegion {
 4469                        selection_id,
 4470                        range: start..end,
 4471                        pair,
 4472                    },
 4473                );
 4474            }
 4475
 4476            let had_active_edit_prediction = this.has_active_edit_prediction();
 4477            this.change_selections(
 4478                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4479                window,
 4480                cx,
 4481                |s| s.select(new_selections),
 4482            );
 4483
 4484            if !bracket_inserted
 4485                && let Some(on_type_format_task) =
 4486                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4487            {
 4488                on_type_format_task.detach_and_log_err(cx);
 4489            }
 4490
 4491            let editor_settings = EditorSettings::get_global(cx);
 4492            if bracket_inserted
 4493                && (editor_settings.auto_signature_help
 4494                    || editor_settings.show_signature_help_after_edits)
 4495            {
 4496                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4497            }
 4498
 4499            let trigger_in_words =
 4500                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4501            if this.hard_wrap.is_some() {
 4502                let latest: Range<Point> = this.selections.newest(&map).range();
 4503                if latest.is_empty()
 4504                    && this
 4505                        .buffer()
 4506                        .read(cx)
 4507                        .snapshot(cx)
 4508                        .line_len(MultiBufferRow(latest.start.row))
 4509                        == latest.start.column
 4510                {
 4511                    this.rewrap_impl(
 4512                        RewrapOptions {
 4513                            override_language_settings: true,
 4514                            preserve_existing_whitespace: true,
 4515                        },
 4516                        cx,
 4517                    )
 4518                }
 4519            }
 4520            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4521            refresh_linked_ranges(this, window, cx);
 4522            this.refresh_edit_prediction(true, false, window, cx);
 4523            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4524        });
 4525    }
 4526
 4527    fn find_possible_emoji_shortcode_at_position(
 4528        snapshot: &MultiBufferSnapshot,
 4529        position: Point,
 4530    ) -> Option<String> {
 4531        let mut chars = Vec::new();
 4532        let mut found_colon = false;
 4533        for char in snapshot.reversed_chars_at(position).take(100) {
 4534            // Found a possible emoji shortcode in the middle of the buffer
 4535            if found_colon {
 4536                if char.is_whitespace() {
 4537                    chars.reverse();
 4538                    return Some(chars.iter().collect());
 4539                }
 4540                // If the previous character is not a whitespace, we are in the middle of a word
 4541                // and we only want to complete the shortcode if the word is made up of other emojis
 4542                let mut containing_word = String::new();
 4543                for ch in snapshot
 4544                    .reversed_chars_at(position)
 4545                    .skip(chars.len() + 1)
 4546                    .take(100)
 4547                {
 4548                    if ch.is_whitespace() {
 4549                        break;
 4550                    }
 4551                    containing_word.push(ch);
 4552                }
 4553                let containing_word = containing_word.chars().rev().collect::<String>();
 4554                if util::word_consists_of_emojis(containing_word.as_str()) {
 4555                    chars.reverse();
 4556                    return Some(chars.iter().collect());
 4557                }
 4558            }
 4559
 4560            if char.is_whitespace() || !char.is_ascii() {
 4561                return None;
 4562            }
 4563            if char == ':' {
 4564                found_colon = true;
 4565            } else {
 4566                chars.push(char);
 4567            }
 4568        }
 4569        // Found a possible emoji shortcode at the beginning of the buffer
 4570        chars.reverse();
 4571        Some(chars.iter().collect())
 4572    }
 4573
 4574    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4575        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4576        self.transact(window, cx, |this, window, cx| {
 4577            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4578                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
 4579                let multi_buffer = this.buffer.read(cx);
 4580                let buffer = multi_buffer.snapshot(cx);
 4581                selections
 4582                    .iter()
 4583                    .map(|selection| {
 4584                        let start_point = selection.start.to_point(&buffer);
 4585                        let mut existing_indent =
 4586                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4587                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4588                        let start = selection.start;
 4589                        let end = selection.end;
 4590                        let selection_is_empty = start == end;
 4591                        let language_scope = buffer.language_scope_at(start);
 4592                        let (
 4593                            comment_delimiter,
 4594                            doc_delimiter,
 4595                            insert_extra_newline,
 4596                            indent_on_newline,
 4597                            indent_on_extra_newline,
 4598                        ) = if let Some(language) = &language_scope {
 4599                            let mut insert_extra_newline =
 4600                                insert_extra_newline_brackets(&buffer, start..end, language)
 4601                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4602
 4603                            // Comment extension on newline is allowed only for cursor selections
 4604                            let comment_delimiter = maybe!({
 4605                                if !selection_is_empty {
 4606                                    return None;
 4607                                }
 4608
 4609                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4610                                    return None;
 4611                                }
 4612
 4613                                let delimiters = language.line_comment_prefixes();
 4614                                let max_len_of_delimiter =
 4615                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4616                                let (snapshot, range) =
 4617                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4618
 4619                                let num_of_whitespaces = snapshot
 4620                                    .chars_for_range(range.clone())
 4621                                    .take_while(|c| c.is_whitespace())
 4622                                    .count();
 4623                                let comment_candidate = snapshot
 4624                                    .chars_for_range(range.clone())
 4625                                    .skip(num_of_whitespaces)
 4626                                    .take(max_len_of_delimiter)
 4627                                    .collect::<String>();
 4628                                let (delimiter, trimmed_len) = delimiters
 4629                                    .iter()
 4630                                    .filter_map(|delimiter| {
 4631                                        let prefix = delimiter.trim_end();
 4632                                        if comment_candidate.starts_with(prefix) {
 4633                                            Some((delimiter, prefix.len()))
 4634                                        } else {
 4635                                            None
 4636                                        }
 4637                                    })
 4638                                    .max_by_key(|(_, len)| *len)?;
 4639
 4640                                if let Some(BlockCommentConfig {
 4641                                    start: block_start, ..
 4642                                }) = language.block_comment()
 4643                                {
 4644                                    let block_start_trimmed = block_start.trim_end();
 4645                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4646                                        let line_content = snapshot
 4647                                            .chars_for_range(range)
 4648                                            .skip(num_of_whitespaces)
 4649                                            .take(block_start_trimmed.len())
 4650                                            .collect::<String>();
 4651
 4652                                        if line_content.starts_with(block_start_trimmed) {
 4653                                            return None;
 4654                                        }
 4655                                    }
 4656                                }
 4657
 4658                                let cursor_is_placed_after_comment_marker =
 4659                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4660                                if cursor_is_placed_after_comment_marker {
 4661                                    Some(delimiter.clone())
 4662                                } else {
 4663                                    None
 4664                                }
 4665                            });
 4666
 4667                            let mut indent_on_newline = IndentSize::spaces(0);
 4668                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4669
 4670                            let doc_delimiter = maybe!({
 4671                                if !selection_is_empty {
 4672                                    return None;
 4673                                }
 4674
 4675                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4676                                    return None;
 4677                                }
 4678
 4679                                let BlockCommentConfig {
 4680                                    start: start_tag,
 4681                                    end: end_tag,
 4682                                    prefix: delimiter,
 4683                                    tab_size: len,
 4684                                } = language.documentation_comment()?;
 4685                                let is_within_block_comment = buffer
 4686                                    .language_scope_at(start_point)
 4687                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4688                                if !is_within_block_comment {
 4689                                    return None;
 4690                                }
 4691
 4692                                let (snapshot, range) =
 4693                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4694
 4695                                let num_of_whitespaces = snapshot
 4696                                    .chars_for_range(range.clone())
 4697                                    .take_while(|c| c.is_whitespace())
 4698                                    .count();
 4699
 4700                                // 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.
 4701                                let column = start_point.column;
 4702                                let cursor_is_after_start_tag = {
 4703                                    let start_tag_len = start_tag.len();
 4704                                    let start_tag_line = snapshot
 4705                                        .chars_for_range(range.clone())
 4706                                        .skip(num_of_whitespaces)
 4707                                        .take(start_tag_len)
 4708                                        .collect::<String>();
 4709                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4710                                        num_of_whitespaces + start_tag_len <= column as usize
 4711                                    } else {
 4712                                        false
 4713                                    }
 4714                                };
 4715
 4716                                let cursor_is_after_delimiter = {
 4717                                    let delimiter_trim = delimiter.trim_end();
 4718                                    let delimiter_line = snapshot
 4719                                        .chars_for_range(range.clone())
 4720                                        .skip(num_of_whitespaces)
 4721                                        .take(delimiter_trim.len())
 4722                                        .collect::<String>();
 4723                                    if delimiter_line.starts_with(delimiter_trim) {
 4724                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4725                                    } else {
 4726                                        false
 4727                                    }
 4728                                };
 4729
 4730                                let cursor_is_before_end_tag_if_exists = {
 4731                                    let mut char_position = 0u32;
 4732                                    let mut end_tag_offset = None;
 4733
 4734                                    'outer: for chunk in snapshot.text_for_range(range) {
 4735                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4736                                            let chars_before_match =
 4737                                                chunk[..byte_pos].chars().count() as u32;
 4738                                            end_tag_offset =
 4739                                                Some(char_position + chars_before_match);
 4740                                            break 'outer;
 4741                                        }
 4742                                        char_position += chunk.chars().count() as u32;
 4743                                    }
 4744
 4745                                    if let Some(end_tag_offset) = end_tag_offset {
 4746                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4747                                        if cursor_is_after_start_tag {
 4748                                            if cursor_is_before_end_tag {
 4749                                                insert_extra_newline = true;
 4750                                            }
 4751                                            let cursor_is_at_start_of_end_tag =
 4752                                                column == end_tag_offset;
 4753                                            if cursor_is_at_start_of_end_tag {
 4754                                                indent_on_extra_newline.len = *len;
 4755                                            }
 4756                                        }
 4757                                        cursor_is_before_end_tag
 4758                                    } else {
 4759                                        true
 4760                                    }
 4761                                };
 4762
 4763                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4764                                    && cursor_is_before_end_tag_if_exists
 4765                                {
 4766                                    if cursor_is_after_start_tag {
 4767                                        indent_on_newline.len = *len;
 4768                                    }
 4769                                    Some(delimiter.clone())
 4770                                } else {
 4771                                    None
 4772                                }
 4773                            });
 4774
 4775                            (
 4776                                comment_delimiter,
 4777                                doc_delimiter,
 4778                                insert_extra_newline,
 4779                                indent_on_newline,
 4780                                indent_on_extra_newline,
 4781                            )
 4782                        } else {
 4783                            (
 4784                                None,
 4785                                None,
 4786                                false,
 4787                                IndentSize::default(),
 4788                                IndentSize::default(),
 4789                            )
 4790                        };
 4791
 4792                        let prevent_auto_indent = doc_delimiter.is_some();
 4793                        let delimiter = comment_delimiter.or(doc_delimiter);
 4794
 4795                        let capacity_for_delimiter =
 4796                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4797                        let mut new_text = String::with_capacity(
 4798                            1 + capacity_for_delimiter
 4799                                + existing_indent.len as usize
 4800                                + indent_on_newline.len as usize
 4801                                + indent_on_extra_newline.len as usize,
 4802                        );
 4803                        new_text.push('\n');
 4804                        new_text.extend(existing_indent.chars());
 4805                        new_text.extend(indent_on_newline.chars());
 4806
 4807                        if let Some(delimiter) = &delimiter {
 4808                            new_text.push_str(delimiter);
 4809                        }
 4810
 4811                        if insert_extra_newline {
 4812                            new_text.push('\n');
 4813                            new_text.extend(existing_indent.chars());
 4814                            new_text.extend(indent_on_extra_newline.chars());
 4815                        }
 4816
 4817                        let anchor = buffer.anchor_after(end);
 4818                        let new_selection = selection.map(|_| anchor);
 4819                        (
 4820                            ((start..end, new_text), prevent_auto_indent),
 4821                            (insert_extra_newline, new_selection),
 4822                        )
 4823                    })
 4824                    .unzip()
 4825            };
 4826
 4827            let mut auto_indent_edits = Vec::new();
 4828            let mut edits = Vec::new();
 4829            for (edit, prevent_auto_indent) in edits_with_flags {
 4830                if prevent_auto_indent {
 4831                    edits.push(edit);
 4832                } else {
 4833                    auto_indent_edits.push(edit);
 4834                }
 4835            }
 4836            if !edits.is_empty() {
 4837                this.edit(edits, cx);
 4838            }
 4839            if !auto_indent_edits.is_empty() {
 4840                this.edit_with_autoindent(auto_indent_edits, cx);
 4841            }
 4842
 4843            let buffer = this.buffer.read(cx).snapshot(cx);
 4844            let new_selections = selection_info
 4845                .into_iter()
 4846                .map(|(extra_newline_inserted, new_selection)| {
 4847                    let mut cursor = new_selection.end.to_point(&buffer);
 4848                    if extra_newline_inserted {
 4849                        cursor.row -= 1;
 4850                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4851                    }
 4852                    new_selection.map(|_| cursor)
 4853                })
 4854                .collect();
 4855
 4856            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4857            this.refresh_edit_prediction(true, false, window, cx);
 4858        });
 4859    }
 4860
 4861    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4862        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4863
 4864        let buffer = self.buffer.read(cx);
 4865        let snapshot = buffer.snapshot(cx);
 4866
 4867        let mut edits = Vec::new();
 4868        let mut rows = Vec::new();
 4869
 4870        for (rows_inserted, selection) in self
 4871            .selections
 4872            .all_adjusted(&self.display_snapshot(cx))
 4873            .into_iter()
 4874            .enumerate()
 4875        {
 4876            let cursor = selection.head();
 4877            let row = cursor.row;
 4878
 4879            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4880
 4881            let newline = "\n".to_string();
 4882            edits.push((start_of_line..start_of_line, newline));
 4883
 4884            rows.push(row + rows_inserted as u32);
 4885        }
 4886
 4887        self.transact(window, cx, |editor, window, cx| {
 4888            editor.edit(edits, cx);
 4889
 4890            editor.change_selections(Default::default(), window, cx, |s| {
 4891                let mut index = 0;
 4892                s.move_cursors_with(|map, _, _| {
 4893                    let row = rows[index];
 4894                    index += 1;
 4895
 4896                    let point = Point::new(row, 0);
 4897                    let boundary = map.next_line_boundary(point).1;
 4898                    let clipped = map.clip_point(boundary, Bias::Left);
 4899
 4900                    (clipped, SelectionGoal::None)
 4901                });
 4902            });
 4903
 4904            let mut indent_edits = Vec::new();
 4905            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4906            for row in rows {
 4907                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4908                for (row, indent) in indents {
 4909                    if indent.len == 0 {
 4910                        continue;
 4911                    }
 4912
 4913                    let text = match indent.kind {
 4914                        IndentKind::Space => " ".repeat(indent.len as usize),
 4915                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4916                    };
 4917                    let point = Point::new(row.0, 0);
 4918                    indent_edits.push((point..point, text));
 4919                }
 4920            }
 4921            editor.edit(indent_edits, cx);
 4922        });
 4923    }
 4924
 4925    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4926        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4927
 4928        let buffer = self.buffer.read(cx);
 4929        let snapshot = buffer.snapshot(cx);
 4930
 4931        let mut edits = Vec::new();
 4932        let mut rows = Vec::new();
 4933        let mut rows_inserted = 0;
 4934
 4935        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 4936            let cursor = selection.head();
 4937            let row = cursor.row;
 4938
 4939            let point = Point::new(row + 1, 0);
 4940            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4941
 4942            let newline = "\n".to_string();
 4943            edits.push((start_of_line..start_of_line, newline));
 4944
 4945            rows_inserted += 1;
 4946            rows.push(row + rows_inserted);
 4947        }
 4948
 4949        self.transact(window, cx, |editor, window, cx| {
 4950            editor.edit(edits, cx);
 4951
 4952            editor.change_selections(Default::default(), window, cx, |s| {
 4953                let mut index = 0;
 4954                s.move_cursors_with(|map, _, _| {
 4955                    let row = rows[index];
 4956                    index += 1;
 4957
 4958                    let point = Point::new(row, 0);
 4959                    let boundary = map.next_line_boundary(point).1;
 4960                    let clipped = map.clip_point(boundary, Bias::Left);
 4961
 4962                    (clipped, SelectionGoal::None)
 4963                });
 4964            });
 4965
 4966            let mut indent_edits = Vec::new();
 4967            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4968            for row in rows {
 4969                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4970                for (row, indent) in indents {
 4971                    if indent.len == 0 {
 4972                        continue;
 4973                    }
 4974
 4975                    let text = match indent.kind {
 4976                        IndentKind::Space => " ".repeat(indent.len as usize),
 4977                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4978                    };
 4979                    let point = Point::new(row.0, 0);
 4980                    indent_edits.push((point..point, text));
 4981                }
 4982            }
 4983            editor.edit(indent_edits, cx);
 4984        });
 4985    }
 4986
 4987    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4988        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4989            original_indent_columns: Vec::new(),
 4990        });
 4991        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4992    }
 4993
 4994    fn insert_with_autoindent_mode(
 4995        &mut self,
 4996        text: &str,
 4997        autoindent_mode: Option<AutoindentMode>,
 4998        window: &mut Window,
 4999        cx: &mut Context<Self>,
 5000    ) {
 5001        if self.read_only(cx) {
 5002            return;
 5003        }
 5004
 5005        let text: Arc<str> = text.into();
 5006        self.transact(window, cx, |this, window, cx| {
 5007            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5008            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5009                let anchors = {
 5010                    let snapshot = buffer.read(cx);
 5011                    old_selections
 5012                        .iter()
 5013                        .map(|s| {
 5014                            let anchor = snapshot.anchor_after(s.head());
 5015                            s.map(|_| anchor)
 5016                        })
 5017                        .collect::<Vec<_>>()
 5018                };
 5019                buffer.edit(
 5020                    old_selections
 5021                        .iter()
 5022                        .map(|s| (s.start..s.end, text.clone())),
 5023                    autoindent_mode,
 5024                    cx,
 5025                );
 5026                anchors
 5027            });
 5028
 5029            this.change_selections(Default::default(), window, cx, |s| {
 5030                s.select_anchors(selection_anchors);
 5031            });
 5032
 5033            cx.notify();
 5034        });
 5035    }
 5036
 5037    fn trigger_completion_on_input(
 5038        &mut self,
 5039        text: &str,
 5040        trigger_in_words: bool,
 5041        window: &mut Window,
 5042        cx: &mut Context<Self>,
 5043    ) {
 5044        let completions_source = self
 5045            .context_menu
 5046            .borrow()
 5047            .as_ref()
 5048            .and_then(|menu| match menu {
 5049                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5050                CodeContextMenu::CodeActions(_) => None,
 5051            });
 5052
 5053        match completions_source {
 5054            Some(CompletionsMenuSource::Words { .. }) => {
 5055                self.open_or_update_completions_menu(
 5056                    Some(CompletionsMenuSource::Words {
 5057                        ignore_threshold: false,
 5058                    }),
 5059                    None,
 5060                    window,
 5061                    cx,
 5062                );
 5063            }
 5064            Some(CompletionsMenuSource::Normal)
 5065            | Some(CompletionsMenuSource::SnippetChoices)
 5066            | None
 5067                if self.is_completion_trigger(
 5068                    text,
 5069                    trigger_in_words,
 5070                    completions_source.is_some(),
 5071                    cx,
 5072                ) =>
 5073            {
 5074                self.show_completions(
 5075                    &ShowCompletions {
 5076                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 5077                    },
 5078                    window,
 5079                    cx,
 5080                )
 5081            }
 5082            _ => {
 5083                self.hide_context_menu(window, cx);
 5084            }
 5085        }
 5086    }
 5087
 5088    fn is_completion_trigger(
 5089        &self,
 5090        text: &str,
 5091        trigger_in_words: bool,
 5092        menu_is_open: bool,
 5093        cx: &mut Context<Self>,
 5094    ) -> bool {
 5095        let position = self.selections.newest_anchor().head();
 5096        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 5097            return false;
 5098        };
 5099
 5100        if let Some(completion_provider) = &self.completion_provider {
 5101            completion_provider.is_completion_trigger(
 5102                &buffer,
 5103                position.text_anchor,
 5104                text,
 5105                trigger_in_words,
 5106                menu_is_open,
 5107                cx,
 5108            )
 5109        } else {
 5110            false
 5111        }
 5112    }
 5113
 5114    /// If any empty selections is touching the start of its innermost containing autoclose
 5115    /// region, expand it to select the brackets.
 5116    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5117        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5118        let buffer = self.buffer.read(cx).read(cx);
 5119        let new_selections = self
 5120            .selections_with_autoclose_regions(selections, &buffer)
 5121            .map(|(mut selection, region)| {
 5122                if !selection.is_empty() {
 5123                    return selection;
 5124                }
 5125
 5126                if let Some(region) = region {
 5127                    let mut range = region.range.to_offset(&buffer);
 5128                    if selection.start == range.start && range.start >= region.pair.start.len() {
 5129                        range.start -= region.pair.start.len();
 5130                        if buffer.contains_str_at(range.start, &region.pair.start)
 5131                            && buffer.contains_str_at(range.end, &region.pair.end)
 5132                        {
 5133                            range.end += region.pair.end.len();
 5134                            selection.start = range.start;
 5135                            selection.end = range.end;
 5136
 5137                            return selection;
 5138                        }
 5139                    }
 5140                }
 5141
 5142                let always_treat_brackets_as_autoclosed = buffer
 5143                    .language_settings_at(selection.start, cx)
 5144                    .always_treat_brackets_as_autoclosed;
 5145
 5146                if !always_treat_brackets_as_autoclosed {
 5147                    return selection;
 5148                }
 5149
 5150                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5151                    for (pair, enabled) in scope.brackets() {
 5152                        if !enabled || !pair.close {
 5153                            continue;
 5154                        }
 5155
 5156                        if buffer.contains_str_at(selection.start, &pair.end) {
 5157                            let pair_start_len = pair.start.len();
 5158                            if buffer.contains_str_at(
 5159                                selection.start.saturating_sub(pair_start_len),
 5160                                &pair.start,
 5161                            ) {
 5162                                selection.start -= pair_start_len;
 5163                                selection.end += pair.end.len();
 5164
 5165                                return selection;
 5166                            }
 5167                        }
 5168                    }
 5169                }
 5170
 5171                selection
 5172            })
 5173            .collect();
 5174
 5175        drop(buffer);
 5176        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5177            selections.select(new_selections)
 5178        });
 5179    }
 5180
 5181    /// Iterate the given selections, and for each one, find the smallest surrounding
 5182    /// autoclose region. This uses the ordering of the selections and the autoclose
 5183    /// regions to avoid repeated comparisons.
 5184    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5185        &'a self,
 5186        selections: impl IntoIterator<Item = Selection<D>>,
 5187        buffer: &'a MultiBufferSnapshot,
 5188    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5189        let mut i = 0;
 5190        let mut regions = self.autoclose_regions.as_slice();
 5191        selections.into_iter().map(move |selection| {
 5192            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5193
 5194            let mut enclosing = None;
 5195            while let Some(pair_state) = regions.get(i) {
 5196                if pair_state.range.end.to_offset(buffer) < range.start {
 5197                    regions = &regions[i + 1..];
 5198                    i = 0;
 5199                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5200                    break;
 5201                } else {
 5202                    if pair_state.selection_id == selection.id {
 5203                        enclosing = Some(pair_state);
 5204                    }
 5205                    i += 1;
 5206                }
 5207            }
 5208
 5209            (selection, enclosing)
 5210        })
 5211    }
 5212
 5213    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5214    fn invalidate_autoclose_regions(
 5215        &mut self,
 5216        mut selections: &[Selection<Anchor>],
 5217        buffer: &MultiBufferSnapshot,
 5218    ) {
 5219        self.autoclose_regions.retain(|state| {
 5220            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5221                return false;
 5222            }
 5223
 5224            let mut i = 0;
 5225            while let Some(selection) = selections.get(i) {
 5226                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5227                    selections = &selections[1..];
 5228                    continue;
 5229                }
 5230                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5231                    break;
 5232                }
 5233                if selection.id == state.selection_id {
 5234                    return true;
 5235                } else {
 5236                    i += 1;
 5237                }
 5238            }
 5239            false
 5240        });
 5241    }
 5242
 5243    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5244        let offset = position.to_offset(buffer);
 5245        let (word_range, kind) =
 5246            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5247        if offset > word_range.start && kind == Some(CharKind::Word) {
 5248            Some(
 5249                buffer
 5250                    .text_for_range(word_range.start..offset)
 5251                    .collect::<String>(),
 5252            )
 5253        } else {
 5254            None
 5255        }
 5256    }
 5257
 5258    pub fn visible_excerpts(
 5259        &self,
 5260        cx: &mut Context<Editor>,
 5261    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5262        let Some(project) = self.project() else {
 5263            return HashMap::default();
 5264        };
 5265        let project = project.read(cx);
 5266        let multi_buffer = self.buffer().read(cx);
 5267        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5268        let multi_buffer_visible_start = self
 5269            .scroll_manager
 5270            .anchor()
 5271            .anchor
 5272            .to_point(&multi_buffer_snapshot);
 5273        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5274            multi_buffer_visible_start
 5275                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5276            Bias::Left,
 5277        );
 5278        multi_buffer_snapshot
 5279            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5280            .into_iter()
 5281            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5282            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5283                let buffer_file = project::File::from_dyn(buffer.file())?;
 5284                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5285                let worktree_entry = buffer_worktree
 5286                    .read(cx)
 5287                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5288                if worktree_entry.is_ignored {
 5289                    None
 5290                } else {
 5291                    Some((
 5292                        excerpt_id,
 5293                        (
 5294                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5295                            buffer.version().clone(),
 5296                            excerpt_visible_range,
 5297                        ),
 5298                    ))
 5299                }
 5300            })
 5301            .collect()
 5302    }
 5303
 5304    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5305        TextLayoutDetails {
 5306            text_system: window.text_system().clone(),
 5307            editor_style: self.style.clone().unwrap(),
 5308            rem_size: window.rem_size(),
 5309            scroll_anchor: self.scroll_manager.anchor(),
 5310            visible_rows: self.visible_line_count(),
 5311            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5312        }
 5313    }
 5314
 5315    fn trigger_on_type_formatting(
 5316        &self,
 5317        input: String,
 5318        window: &mut Window,
 5319        cx: &mut Context<Self>,
 5320    ) -> Option<Task<Result<()>>> {
 5321        if input.len() != 1 {
 5322            return None;
 5323        }
 5324
 5325        let project = self.project()?;
 5326        let position = self.selections.newest_anchor().head();
 5327        let (buffer, buffer_position) = self
 5328            .buffer
 5329            .read(cx)
 5330            .text_anchor_for_position(position, cx)?;
 5331
 5332        let settings = language_settings::language_settings(
 5333            buffer
 5334                .read(cx)
 5335                .language_at(buffer_position)
 5336                .map(|l| l.name()),
 5337            buffer.read(cx).file(),
 5338            cx,
 5339        );
 5340        if !settings.use_on_type_format {
 5341            return None;
 5342        }
 5343
 5344        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5345        // hence we do LSP request & edit on host side only — add formats to host's history.
 5346        let push_to_lsp_host_history = true;
 5347        // If this is not the host, append its history with new edits.
 5348        let push_to_client_history = project.read(cx).is_via_collab();
 5349
 5350        let on_type_formatting = project.update(cx, |project, cx| {
 5351            project.on_type_format(
 5352                buffer.clone(),
 5353                buffer_position,
 5354                input,
 5355                push_to_lsp_host_history,
 5356                cx,
 5357            )
 5358        });
 5359        Some(cx.spawn_in(window, async move |editor, cx| {
 5360            if let Some(transaction) = on_type_formatting.await? {
 5361                if push_to_client_history {
 5362                    buffer
 5363                        .update(cx, |buffer, _| {
 5364                            buffer.push_transaction(transaction, Instant::now());
 5365                            buffer.finalize_last_transaction();
 5366                        })
 5367                        .ok();
 5368                }
 5369                editor.update(cx, |editor, cx| {
 5370                    editor.refresh_document_highlights(cx);
 5371                })?;
 5372            }
 5373            Ok(())
 5374        }))
 5375    }
 5376
 5377    pub fn show_word_completions(
 5378        &mut self,
 5379        _: &ShowWordCompletions,
 5380        window: &mut Window,
 5381        cx: &mut Context<Self>,
 5382    ) {
 5383        self.open_or_update_completions_menu(
 5384            Some(CompletionsMenuSource::Words {
 5385                ignore_threshold: true,
 5386            }),
 5387            None,
 5388            window,
 5389            cx,
 5390        );
 5391    }
 5392
 5393    pub fn show_completions(
 5394        &mut self,
 5395        options: &ShowCompletions,
 5396        window: &mut Window,
 5397        cx: &mut Context<Self>,
 5398    ) {
 5399        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5400    }
 5401
 5402    fn open_or_update_completions_menu(
 5403        &mut self,
 5404        requested_source: Option<CompletionsMenuSource>,
 5405        trigger: Option<&str>,
 5406        window: &mut Window,
 5407        cx: &mut Context<Self>,
 5408    ) {
 5409        if self.pending_rename.is_some() {
 5410            return;
 5411        }
 5412
 5413        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5414
 5415        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5416        // inserted and selected. To handle that case, the start of the selection is used so that
 5417        // the menu starts with all choices.
 5418        let position = self
 5419            .selections
 5420            .newest_anchor()
 5421            .start
 5422            .bias_right(&multibuffer_snapshot);
 5423        if position.diff_base_anchor.is_some() {
 5424            return;
 5425        }
 5426        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5427        let Some(buffer) = buffer_position
 5428            .buffer_id
 5429            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5430        else {
 5431            return;
 5432        };
 5433        let buffer_snapshot = buffer.read(cx).snapshot();
 5434
 5435        let query: Option<Arc<String>> =
 5436            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5437                .map(|query| query.into());
 5438
 5439        drop(multibuffer_snapshot);
 5440
 5441        // Hide the current completions menu when query is empty. Without this, cached
 5442        // completions from before the trigger char may be reused (#32774).
 5443        if query.is_none() {
 5444            let menu_is_open = matches!(
 5445                self.context_menu.borrow().as_ref(),
 5446                Some(CodeContextMenu::Completions(_))
 5447            );
 5448            if menu_is_open {
 5449                self.hide_context_menu(window, cx);
 5450            }
 5451        }
 5452
 5453        let mut ignore_word_threshold = false;
 5454        let provider = match requested_source {
 5455            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5456            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5457                ignore_word_threshold = ignore_threshold;
 5458                None
 5459            }
 5460            Some(CompletionsMenuSource::SnippetChoices) => {
 5461                log::error!("bug: SnippetChoices requested_source is not handled");
 5462                None
 5463            }
 5464        };
 5465
 5466        let sort_completions = provider
 5467            .as_ref()
 5468            .is_some_and(|provider| provider.sort_completions());
 5469
 5470        let filter_completions = provider
 5471            .as_ref()
 5472            .is_none_or(|provider| provider.filter_completions());
 5473
 5474        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5475            if filter_completions {
 5476                menu.filter(query.clone(), provider.clone(), window, cx);
 5477            }
 5478            // When `is_incomplete` is false, no need to re-query completions when the current query
 5479            // is a suffix of the initial query.
 5480            if !menu.is_incomplete {
 5481                // If the new query is a suffix of the old query (typing more characters) and
 5482                // the previous result was complete, the existing completions can be filtered.
 5483                //
 5484                // Note that this is always true for snippet completions.
 5485                let query_matches = match (&menu.initial_query, &query) {
 5486                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5487                    (None, _) => true,
 5488                    _ => false,
 5489                };
 5490                if query_matches {
 5491                    let position_matches = if menu.initial_position == position {
 5492                        true
 5493                    } else {
 5494                        let snapshot = self.buffer.read(cx).read(cx);
 5495                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5496                    };
 5497                    if position_matches {
 5498                        return;
 5499                    }
 5500                }
 5501            }
 5502        };
 5503
 5504        let trigger_kind = match trigger {
 5505            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5506                CompletionTriggerKind::TRIGGER_CHARACTER
 5507            }
 5508            _ => CompletionTriggerKind::INVOKED,
 5509        };
 5510        let completion_context = CompletionContext {
 5511            trigger_character: trigger.and_then(|trigger| {
 5512                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5513                    Some(String::from(trigger))
 5514                } else {
 5515                    None
 5516                }
 5517            }),
 5518            trigger_kind,
 5519        };
 5520
 5521        let Anchor {
 5522            excerpt_id: buffer_excerpt_id,
 5523            text_anchor: buffer_position,
 5524            ..
 5525        } = buffer_position;
 5526
 5527        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5528            buffer_snapshot.surrounding_word(buffer_position, None)
 5529        {
 5530            let word_to_exclude = buffer_snapshot
 5531                .text_for_range(word_range.clone())
 5532                .collect::<String>();
 5533            (
 5534                buffer_snapshot.anchor_before(word_range.start)
 5535                    ..buffer_snapshot.anchor_after(buffer_position),
 5536                Some(word_to_exclude),
 5537            )
 5538        } else {
 5539            (buffer_position..buffer_position, None)
 5540        };
 5541
 5542        let language = buffer_snapshot
 5543            .language_at(buffer_position)
 5544            .map(|language| language.name());
 5545
 5546        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5547            .completions
 5548            .clone();
 5549
 5550        let show_completion_documentation = buffer_snapshot
 5551            .settings_at(buffer_position, cx)
 5552            .show_completion_documentation;
 5553
 5554        // The document can be large, so stay in reasonable bounds when searching for words,
 5555        // otherwise completion pop-up might be slow to appear.
 5556        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5557        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5558        let min_word_search = buffer_snapshot.clip_point(
 5559            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5560            Bias::Left,
 5561        );
 5562        let max_word_search = buffer_snapshot.clip_point(
 5563            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5564            Bias::Right,
 5565        );
 5566        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5567            ..buffer_snapshot.point_to_offset(max_word_search);
 5568
 5569        let skip_digits = query
 5570            .as_ref()
 5571            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5572
 5573        let omit_word_completions = !self.word_completions_enabled
 5574            || (!ignore_word_threshold
 5575                && match &query {
 5576                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5577                    None => completion_settings.words_min_length != 0,
 5578                });
 5579
 5580        let (mut words, provider_responses) = match &provider {
 5581            Some(provider) => {
 5582                let provider_responses = provider.completions(
 5583                    buffer_excerpt_id,
 5584                    &buffer,
 5585                    buffer_position,
 5586                    completion_context,
 5587                    window,
 5588                    cx,
 5589                );
 5590
 5591                let words = match (omit_word_completions, completion_settings.words) {
 5592                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5593                        Task::ready(BTreeMap::default())
 5594                    }
 5595                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5596                        .background_spawn(async move {
 5597                            buffer_snapshot.words_in_range(WordsQuery {
 5598                                fuzzy_contents: None,
 5599                                range: word_search_range,
 5600                                skip_digits,
 5601                            })
 5602                        }),
 5603                };
 5604
 5605                (words, provider_responses)
 5606            }
 5607            None => {
 5608                let words = if omit_word_completions {
 5609                    Task::ready(BTreeMap::default())
 5610                } else {
 5611                    cx.background_spawn(async move {
 5612                        buffer_snapshot.words_in_range(WordsQuery {
 5613                            fuzzy_contents: None,
 5614                            range: word_search_range,
 5615                            skip_digits,
 5616                        })
 5617                    })
 5618                };
 5619                (words, Task::ready(Ok(Vec::new())))
 5620            }
 5621        };
 5622
 5623        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5624
 5625        let id = post_inc(&mut self.next_completion_id);
 5626        let task = cx.spawn_in(window, async move |editor, cx| {
 5627            let Ok(()) = editor.update(cx, |this, _| {
 5628                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5629            }) else {
 5630                return;
 5631            };
 5632
 5633            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5634            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5635            let mut completions = Vec::new();
 5636            let mut is_incomplete = false;
 5637            let mut display_options: Option<CompletionDisplayOptions> = None;
 5638            if let Some(provider_responses) = provider_responses.await.log_err()
 5639                && !provider_responses.is_empty()
 5640            {
 5641                for response in provider_responses {
 5642                    completions.extend(response.completions);
 5643                    is_incomplete = is_incomplete || response.is_incomplete;
 5644                    match display_options.as_mut() {
 5645                        None => {
 5646                            display_options = Some(response.display_options);
 5647                        }
 5648                        Some(options) => options.merge(&response.display_options),
 5649                    }
 5650                }
 5651                if completion_settings.words == WordsCompletionMode::Fallback {
 5652                    words = Task::ready(BTreeMap::default());
 5653                }
 5654            }
 5655            let display_options = display_options.unwrap_or_default();
 5656
 5657            let mut words = words.await;
 5658            if let Some(word_to_exclude) = &word_to_exclude {
 5659                words.remove(word_to_exclude);
 5660            }
 5661            for lsp_completion in &completions {
 5662                words.remove(&lsp_completion.new_text);
 5663            }
 5664            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5665                replace_range: word_replace_range.clone(),
 5666                new_text: word.clone(),
 5667                label: CodeLabel::plain(word, None),
 5668                icon_path: None,
 5669                documentation: None,
 5670                source: CompletionSource::BufferWord {
 5671                    word_range,
 5672                    resolved: false,
 5673                },
 5674                insert_text_mode: Some(InsertTextMode::AS_IS),
 5675                confirm: None,
 5676            }));
 5677
 5678            let menu = if completions.is_empty() {
 5679                None
 5680            } else {
 5681                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5682                    let languages = editor
 5683                        .workspace
 5684                        .as_ref()
 5685                        .and_then(|(workspace, _)| workspace.upgrade())
 5686                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5687                    let menu = CompletionsMenu::new(
 5688                        id,
 5689                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5690                        sort_completions,
 5691                        show_completion_documentation,
 5692                        position,
 5693                        query.clone(),
 5694                        is_incomplete,
 5695                        buffer.clone(),
 5696                        completions.into(),
 5697                        display_options,
 5698                        snippet_sort_order,
 5699                        languages,
 5700                        language,
 5701                        cx,
 5702                    );
 5703
 5704                    let query = if filter_completions { query } else { None };
 5705                    let matches_task = if let Some(query) = query {
 5706                        menu.do_async_filtering(query, cx)
 5707                    } else {
 5708                        Task::ready(menu.unfiltered_matches())
 5709                    };
 5710                    (menu, matches_task)
 5711                }) else {
 5712                    return;
 5713                };
 5714
 5715                let matches = matches_task.await;
 5716
 5717                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5718                    // Newer menu already set, so exit.
 5719                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5720                        editor.context_menu.borrow().as_ref()
 5721                        && prev_menu.id > id
 5722                    {
 5723                        return;
 5724                    };
 5725
 5726                    // Only valid to take prev_menu because it the new menu is immediately set
 5727                    // below, or the menu is hidden.
 5728                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5729                        editor.context_menu.borrow_mut().take()
 5730                    {
 5731                        let position_matches =
 5732                            if prev_menu.initial_position == menu.initial_position {
 5733                                true
 5734                            } else {
 5735                                let snapshot = editor.buffer.read(cx).read(cx);
 5736                                prev_menu.initial_position.to_offset(&snapshot)
 5737                                    == menu.initial_position.to_offset(&snapshot)
 5738                            };
 5739                        if position_matches {
 5740                            // Preserve markdown cache before `set_filter_results` because it will
 5741                            // try to populate the documentation cache.
 5742                            menu.preserve_markdown_cache(prev_menu);
 5743                        }
 5744                    };
 5745
 5746                    menu.set_filter_results(matches, provider, window, cx);
 5747                }) else {
 5748                    return;
 5749                };
 5750
 5751                menu.visible().then_some(menu)
 5752            };
 5753
 5754            editor
 5755                .update_in(cx, |editor, window, cx| {
 5756                    if editor.focus_handle.is_focused(window)
 5757                        && let Some(menu) = menu
 5758                    {
 5759                        *editor.context_menu.borrow_mut() =
 5760                            Some(CodeContextMenu::Completions(menu));
 5761
 5762                        crate::hover_popover::hide_hover(editor, cx);
 5763                        if editor.show_edit_predictions_in_menu() {
 5764                            editor.update_visible_edit_prediction(window, cx);
 5765                        } else {
 5766                            editor.discard_edit_prediction(false, cx);
 5767                        }
 5768
 5769                        cx.notify();
 5770                        return;
 5771                    }
 5772
 5773                    if editor.completion_tasks.len() <= 1 {
 5774                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5775                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5776                        // If it was already hidden and we don't show edit predictions in the menu,
 5777                        // we should also show the edit prediction when available.
 5778                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5779                            editor.update_visible_edit_prediction(window, cx);
 5780                        }
 5781                    }
 5782                })
 5783                .ok();
 5784        });
 5785
 5786        self.completion_tasks.push((id, task));
 5787    }
 5788
 5789    #[cfg(feature = "test-support")]
 5790    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5791        let menu = self.context_menu.borrow();
 5792        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5793            let completions = menu.completions.borrow();
 5794            Some(completions.to_vec())
 5795        } else {
 5796            None
 5797        }
 5798    }
 5799
 5800    pub fn with_completions_menu_matching_id<R>(
 5801        &self,
 5802        id: CompletionId,
 5803        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5804    ) -> R {
 5805        let mut context_menu = self.context_menu.borrow_mut();
 5806        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5807            return f(None);
 5808        };
 5809        if completions_menu.id != id {
 5810            return f(None);
 5811        }
 5812        f(Some(completions_menu))
 5813    }
 5814
 5815    pub fn confirm_completion(
 5816        &mut self,
 5817        action: &ConfirmCompletion,
 5818        window: &mut Window,
 5819        cx: &mut Context<Self>,
 5820    ) -> Option<Task<Result<()>>> {
 5821        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5822        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5823    }
 5824
 5825    pub fn confirm_completion_insert(
 5826        &mut self,
 5827        _: &ConfirmCompletionInsert,
 5828        window: &mut Window,
 5829        cx: &mut Context<Self>,
 5830    ) -> Option<Task<Result<()>>> {
 5831        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5832        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5833    }
 5834
 5835    pub fn confirm_completion_replace(
 5836        &mut self,
 5837        _: &ConfirmCompletionReplace,
 5838        window: &mut Window,
 5839        cx: &mut Context<Self>,
 5840    ) -> Option<Task<Result<()>>> {
 5841        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5842        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5843    }
 5844
 5845    pub fn compose_completion(
 5846        &mut self,
 5847        action: &ComposeCompletion,
 5848        window: &mut Window,
 5849        cx: &mut Context<Self>,
 5850    ) -> Option<Task<Result<()>>> {
 5851        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5852        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5853    }
 5854
 5855    fn do_completion(
 5856        &mut self,
 5857        item_ix: Option<usize>,
 5858        intent: CompletionIntent,
 5859        window: &mut Window,
 5860        cx: &mut Context<Editor>,
 5861    ) -> Option<Task<Result<()>>> {
 5862        use language::ToOffset as _;
 5863
 5864        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5865        else {
 5866            return None;
 5867        };
 5868
 5869        let candidate_id = {
 5870            let entries = completions_menu.entries.borrow();
 5871            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5872            if self.show_edit_predictions_in_menu() {
 5873                self.discard_edit_prediction(true, cx);
 5874            }
 5875            mat.candidate_id
 5876        };
 5877
 5878        let completion = completions_menu
 5879            .completions
 5880            .borrow()
 5881            .get(candidate_id)?
 5882            .clone();
 5883        cx.stop_propagation();
 5884
 5885        let buffer_handle = completions_menu.buffer.clone();
 5886
 5887        let CompletionEdit {
 5888            new_text,
 5889            snippet,
 5890            replace_range,
 5891        } = process_completion_for_edit(
 5892            &completion,
 5893            intent,
 5894            &buffer_handle,
 5895            &completions_menu.initial_position.text_anchor,
 5896            cx,
 5897        );
 5898
 5899        let buffer = buffer_handle.read(cx);
 5900        let snapshot = self.buffer.read(cx).snapshot(cx);
 5901        let newest_anchor = self.selections.newest_anchor();
 5902        let replace_range_multibuffer = {
 5903            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5904            excerpt.map_range_from_buffer(replace_range.clone())
 5905        };
 5906        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5907            return None;
 5908        }
 5909
 5910        let old_text = buffer
 5911            .text_for_range(replace_range.clone())
 5912            .collect::<String>();
 5913        let lookbehind = newest_anchor
 5914            .start
 5915            .text_anchor
 5916            .to_offset(buffer)
 5917            .saturating_sub(replace_range.start);
 5918        let lookahead = replace_range
 5919            .end
 5920            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5921        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5922        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5923
 5924        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5925        let mut ranges = Vec::new();
 5926        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5927
 5928        for selection in &selections {
 5929            let range = if selection.id == newest_anchor.id {
 5930                replace_range_multibuffer.clone()
 5931            } else {
 5932                let mut range = selection.range();
 5933
 5934                // if prefix is present, don't duplicate it
 5935                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5936                    range.start = range.start.saturating_sub(lookbehind);
 5937
 5938                    // if suffix is also present, mimic the newest cursor and replace it
 5939                    if selection.id != newest_anchor.id
 5940                        && snapshot.contains_str_at(range.end, suffix)
 5941                    {
 5942                        range.end += lookahead;
 5943                    }
 5944                }
 5945                range
 5946            };
 5947
 5948            ranges.push(range.clone());
 5949
 5950            if !self.linked_edit_ranges.is_empty() {
 5951                let start_anchor = snapshot.anchor_before(range.start);
 5952                let end_anchor = snapshot.anchor_after(range.end);
 5953                if let Some(ranges) = self
 5954                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5955                {
 5956                    for (buffer, edits) in ranges {
 5957                        linked_edits
 5958                            .entry(buffer.clone())
 5959                            .or_default()
 5960                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5961                    }
 5962                }
 5963            }
 5964        }
 5965
 5966        let common_prefix_len = old_text
 5967            .chars()
 5968            .zip(new_text.chars())
 5969            .take_while(|(a, b)| a == b)
 5970            .map(|(a, _)| a.len_utf8())
 5971            .sum::<usize>();
 5972
 5973        cx.emit(EditorEvent::InputHandled {
 5974            utf16_range_to_replace: None,
 5975            text: new_text[common_prefix_len..].into(),
 5976        });
 5977
 5978        self.transact(window, cx, |editor, window, cx| {
 5979            if let Some(mut snippet) = snippet {
 5980                snippet.text = new_text.to_string();
 5981                editor
 5982                    .insert_snippet(&ranges, snippet, window, cx)
 5983                    .log_err();
 5984            } else {
 5985                editor.buffer.update(cx, |multi_buffer, cx| {
 5986                    let auto_indent = match completion.insert_text_mode {
 5987                        Some(InsertTextMode::AS_IS) => None,
 5988                        _ => editor.autoindent_mode.clone(),
 5989                    };
 5990                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5991                    multi_buffer.edit(edits, auto_indent, cx);
 5992                });
 5993            }
 5994            for (buffer, edits) in linked_edits {
 5995                buffer.update(cx, |buffer, cx| {
 5996                    let snapshot = buffer.snapshot();
 5997                    let edits = edits
 5998                        .into_iter()
 5999                        .map(|(range, text)| {
 6000                            use text::ToPoint as TP;
 6001                            let end_point = TP::to_point(&range.end, &snapshot);
 6002                            let start_point = TP::to_point(&range.start, &snapshot);
 6003                            (start_point..end_point, text)
 6004                        })
 6005                        .sorted_by_key(|(range, _)| range.start);
 6006                    buffer.edit(edits, None, cx);
 6007                })
 6008            }
 6009
 6010            editor.refresh_edit_prediction(true, false, window, cx);
 6011        });
 6012        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6013
 6014        let show_new_completions_on_confirm = completion
 6015            .confirm
 6016            .as_ref()
 6017            .is_some_and(|confirm| confirm(intent, window, cx));
 6018        if show_new_completions_on_confirm {
 6019            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6020        }
 6021
 6022        let provider = self.completion_provider.as_ref()?;
 6023        drop(completion);
 6024        let apply_edits = provider.apply_additional_edits_for_completion(
 6025            buffer_handle,
 6026            completions_menu.completions.clone(),
 6027            candidate_id,
 6028            true,
 6029            cx,
 6030        );
 6031
 6032        let editor_settings = EditorSettings::get_global(cx);
 6033        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6034            // After the code completion is finished, users often want to know what signatures are needed.
 6035            // so we should automatically call signature_help
 6036            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6037        }
 6038
 6039        Some(cx.foreground_executor().spawn(async move {
 6040            apply_edits.await?;
 6041            Ok(())
 6042        }))
 6043    }
 6044
 6045    pub fn toggle_code_actions(
 6046        &mut self,
 6047        action: &ToggleCodeActions,
 6048        window: &mut Window,
 6049        cx: &mut Context<Self>,
 6050    ) {
 6051        let quick_launch = action.quick_launch;
 6052        let mut context_menu = self.context_menu.borrow_mut();
 6053        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6054            if code_actions.deployed_from == action.deployed_from {
 6055                // Toggle if we're selecting the same one
 6056                *context_menu = None;
 6057                cx.notify();
 6058                return;
 6059            } else {
 6060                // Otherwise, clear it and start a new one
 6061                *context_menu = None;
 6062                cx.notify();
 6063            }
 6064        }
 6065        drop(context_menu);
 6066        let snapshot = self.snapshot(window, cx);
 6067        let deployed_from = action.deployed_from.clone();
 6068        let action = action.clone();
 6069        self.completion_tasks.clear();
 6070        self.discard_edit_prediction(false, cx);
 6071
 6072        let multibuffer_point = match &action.deployed_from {
 6073            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6074                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6075            }
 6076            _ => self
 6077                .selections
 6078                .newest::<Point>(&snapshot.display_snapshot)
 6079                .head(),
 6080        };
 6081        let Some((buffer, buffer_row)) = snapshot
 6082            .buffer_snapshot()
 6083            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6084            .and_then(|(buffer_snapshot, range)| {
 6085                self.buffer()
 6086                    .read(cx)
 6087                    .buffer(buffer_snapshot.remote_id())
 6088                    .map(|buffer| (buffer, range.start.row))
 6089            })
 6090        else {
 6091            return;
 6092        };
 6093        let buffer_id = buffer.read(cx).remote_id();
 6094        let tasks = self
 6095            .tasks
 6096            .get(&(buffer_id, buffer_row))
 6097            .map(|t| Arc::new(t.to_owned()));
 6098
 6099        if !self.focus_handle.is_focused(window) {
 6100            return;
 6101        }
 6102        let project = self.project.clone();
 6103
 6104        let code_actions_task = match deployed_from {
 6105            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6106            _ => self.code_actions(buffer_row, window, cx),
 6107        };
 6108
 6109        let runnable_task = match deployed_from {
 6110            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6111            _ => {
 6112                let mut task_context_task = Task::ready(None);
 6113                if let Some(tasks) = &tasks
 6114                    && let Some(project) = project
 6115                {
 6116                    task_context_task =
 6117                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6118                }
 6119
 6120                cx.spawn_in(window, {
 6121                    let buffer = buffer.clone();
 6122                    async move |editor, cx| {
 6123                        let task_context = task_context_task.await;
 6124
 6125                        let resolved_tasks =
 6126                            tasks
 6127                                .zip(task_context.clone())
 6128                                .map(|(tasks, task_context)| ResolvedTasks {
 6129                                    templates: tasks.resolve(&task_context).collect(),
 6130                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6131                                        multibuffer_point.row,
 6132                                        tasks.column,
 6133                                    )),
 6134                                });
 6135                        let debug_scenarios = editor
 6136                            .update(cx, |editor, cx| {
 6137                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6138                            })?
 6139                            .await;
 6140                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6141                    }
 6142                })
 6143            }
 6144        };
 6145
 6146        cx.spawn_in(window, async move |editor, cx| {
 6147            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6148            let code_actions = code_actions_task.await;
 6149            let spawn_straight_away = quick_launch
 6150                && resolved_tasks
 6151                    .as_ref()
 6152                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6153                && code_actions
 6154                    .as_ref()
 6155                    .is_none_or(|actions| actions.is_empty())
 6156                && debug_scenarios.is_empty();
 6157
 6158            editor.update_in(cx, |editor, window, cx| {
 6159                crate::hover_popover::hide_hover(editor, cx);
 6160                let actions = CodeActionContents::new(
 6161                    resolved_tasks,
 6162                    code_actions,
 6163                    debug_scenarios,
 6164                    task_context.unwrap_or_default(),
 6165                );
 6166
 6167                // Don't show the menu if there are no actions available
 6168                if actions.is_empty() {
 6169                    cx.notify();
 6170                    return Task::ready(Ok(()));
 6171                }
 6172
 6173                *editor.context_menu.borrow_mut() =
 6174                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6175                        buffer,
 6176                        actions,
 6177                        selected_item: Default::default(),
 6178                        scroll_handle: UniformListScrollHandle::default(),
 6179                        deployed_from,
 6180                    }));
 6181                cx.notify();
 6182                if spawn_straight_away
 6183                    && let Some(task) = editor.confirm_code_action(
 6184                        &ConfirmCodeAction { item_ix: Some(0) },
 6185                        window,
 6186                        cx,
 6187                    )
 6188                {
 6189                    return task;
 6190                }
 6191
 6192                Task::ready(Ok(()))
 6193            })
 6194        })
 6195        .detach_and_log_err(cx);
 6196    }
 6197
 6198    fn debug_scenarios(
 6199        &mut self,
 6200        resolved_tasks: &Option<ResolvedTasks>,
 6201        buffer: &Entity<Buffer>,
 6202        cx: &mut App,
 6203    ) -> Task<Vec<task::DebugScenario>> {
 6204        maybe!({
 6205            let project = self.project()?;
 6206            let dap_store = project.read(cx).dap_store();
 6207            let mut scenarios = vec![];
 6208            let resolved_tasks = resolved_tasks.as_ref()?;
 6209            let buffer = buffer.read(cx);
 6210            let language = buffer.language()?;
 6211            let file = buffer.file();
 6212            let debug_adapter = language_settings(language.name().into(), file, cx)
 6213                .debuggers
 6214                .first()
 6215                .map(SharedString::from)
 6216                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6217
 6218            dap_store.update(cx, |dap_store, cx| {
 6219                for (_, task) in &resolved_tasks.templates {
 6220                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6221                        task.original_task().clone(),
 6222                        debug_adapter.clone().into(),
 6223                        task.display_label().to_owned().into(),
 6224                        cx,
 6225                    );
 6226                    scenarios.push(maybe_scenario);
 6227                }
 6228            });
 6229            Some(cx.background_spawn(async move {
 6230                futures::future::join_all(scenarios)
 6231                    .await
 6232                    .into_iter()
 6233                    .flatten()
 6234                    .collect::<Vec<_>>()
 6235            }))
 6236        })
 6237        .unwrap_or_else(|| Task::ready(vec![]))
 6238    }
 6239
 6240    fn code_actions(
 6241        &mut self,
 6242        buffer_row: u32,
 6243        window: &mut Window,
 6244        cx: &mut Context<Self>,
 6245    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6246        let mut task = self.code_actions_task.take();
 6247        cx.spawn_in(window, async move |editor, cx| {
 6248            while let Some(prev_task) = task {
 6249                prev_task.await.log_err();
 6250                task = editor
 6251                    .update(cx, |this, _| this.code_actions_task.take())
 6252                    .ok()?;
 6253            }
 6254
 6255            editor
 6256                .update(cx, |editor, cx| {
 6257                    editor
 6258                        .available_code_actions
 6259                        .clone()
 6260                        .and_then(|(location, code_actions)| {
 6261                            let snapshot = location.buffer.read(cx).snapshot();
 6262                            let point_range = location.range.to_point(&snapshot);
 6263                            let point_range = point_range.start.row..=point_range.end.row;
 6264                            if point_range.contains(&buffer_row) {
 6265                                Some(code_actions)
 6266                            } else {
 6267                                None
 6268                            }
 6269                        })
 6270                })
 6271                .ok()
 6272                .flatten()
 6273        })
 6274    }
 6275
 6276    pub fn confirm_code_action(
 6277        &mut self,
 6278        action: &ConfirmCodeAction,
 6279        window: &mut Window,
 6280        cx: &mut Context<Self>,
 6281    ) -> Option<Task<Result<()>>> {
 6282        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6283
 6284        let actions_menu =
 6285            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6286                menu
 6287            } else {
 6288                return None;
 6289            };
 6290
 6291        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6292        let action = actions_menu.actions.get(action_ix)?;
 6293        let title = action.label();
 6294        let buffer = actions_menu.buffer;
 6295        let workspace = self.workspace()?;
 6296
 6297        match action {
 6298            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6299                workspace.update(cx, |workspace, cx| {
 6300                    workspace.schedule_resolved_task(
 6301                        task_source_kind,
 6302                        resolved_task,
 6303                        false,
 6304                        window,
 6305                        cx,
 6306                    );
 6307
 6308                    Some(Task::ready(Ok(())))
 6309                })
 6310            }
 6311            CodeActionsItem::CodeAction {
 6312                excerpt_id,
 6313                action,
 6314                provider,
 6315            } => {
 6316                let apply_code_action =
 6317                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6318                let workspace = workspace.downgrade();
 6319                Some(cx.spawn_in(window, async move |editor, cx| {
 6320                    let project_transaction = apply_code_action.await?;
 6321                    Self::open_project_transaction(
 6322                        &editor,
 6323                        workspace,
 6324                        project_transaction,
 6325                        title,
 6326                        cx,
 6327                    )
 6328                    .await
 6329                }))
 6330            }
 6331            CodeActionsItem::DebugScenario(scenario) => {
 6332                let context = actions_menu.actions.context;
 6333
 6334                workspace.update(cx, |workspace, cx| {
 6335                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6336                    workspace.start_debug_session(
 6337                        scenario,
 6338                        context,
 6339                        Some(buffer),
 6340                        None,
 6341                        window,
 6342                        cx,
 6343                    );
 6344                });
 6345                Some(Task::ready(Ok(())))
 6346            }
 6347        }
 6348    }
 6349
 6350    pub async fn open_project_transaction(
 6351        editor: &WeakEntity<Editor>,
 6352        workspace: WeakEntity<Workspace>,
 6353        transaction: ProjectTransaction,
 6354        title: String,
 6355        cx: &mut AsyncWindowContext,
 6356    ) -> Result<()> {
 6357        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6358        cx.update(|_, cx| {
 6359            entries.sort_unstable_by_key(|(buffer, _)| {
 6360                buffer.read(cx).file().map(|f| f.path().clone())
 6361            });
 6362        })?;
 6363        if entries.is_empty() {
 6364            return Ok(());
 6365        }
 6366
 6367        // If the project transaction's edits are all contained within this editor, then
 6368        // avoid opening a new editor to display them.
 6369
 6370        if let [(buffer, transaction)] = &*entries {
 6371            let excerpt = editor.update(cx, |editor, cx| {
 6372                editor
 6373                    .buffer()
 6374                    .read(cx)
 6375                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6376            })?;
 6377            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6378                && excerpted_buffer == *buffer
 6379            {
 6380                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6381                    let excerpt_range = excerpt_range.to_offset(buffer);
 6382                    buffer
 6383                        .edited_ranges_for_transaction::<usize>(transaction)
 6384                        .all(|range| {
 6385                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6386                        })
 6387                })?;
 6388
 6389                if all_edits_within_excerpt {
 6390                    return Ok(());
 6391                }
 6392            }
 6393        }
 6394
 6395        let mut ranges_to_highlight = Vec::new();
 6396        let excerpt_buffer = cx.new(|cx| {
 6397            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6398            for (buffer_handle, transaction) in &entries {
 6399                let edited_ranges = buffer_handle
 6400                    .read(cx)
 6401                    .edited_ranges_for_transaction::<Point>(transaction)
 6402                    .collect::<Vec<_>>();
 6403                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6404                    PathKey::for_buffer(buffer_handle, cx),
 6405                    buffer_handle.clone(),
 6406                    edited_ranges,
 6407                    multibuffer_context_lines(cx),
 6408                    cx,
 6409                );
 6410
 6411                ranges_to_highlight.extend(ranges);
 6412            }
 6413            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6414            multibuffer
 6415        })?;
 6416
 6417        workspace.update_in(cx, |workspace, window, cx| {
 6418            let project = workspace.project().clone();
 6419            let editor =
 6420                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6421            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6422            editor.update(cx, |editor, cx| {
 6423                editor.highlight_background::<Self>(
 6424                    &ranges_to_highlight,
 6425                    |theme| theme.colors().editor_highlighted_line_background,
 6426                    cx,
 6427                );
 6428            });
 6429        })?;
 6430
 6431        Ok(())
 6432    }
 6433
 6434    pub fn clear_code_action_providers(&mut self) {
 6435        self.code_action_providers.clear();
 6436        self.available_code_actions.take();
 6437    }
 6438
 6439    pub fn add_code_action_provider(
 6440        &mut self,
 6441        provider: Rc<dyn CodeActionProvider>,
 6442        window: &mut Window,
 6443        cx: &mut Context<Self>,
 6444    ) {
 6445        if self
 6446            .code_action_providers
 6447            .iter()
 6448            .any(|existing_provider| existing_provider.id() == provider.id())
 6449        {
 6450            return;
 6451        }
 6452
 6453        self.code_action_providers.push(provider);
 6454        self.refresh_code_actions(window, cx);
 6455    }
 6456
 6457    pub fn remove_code_action_provider(
 6458        &mut self,
 6459        id: Arc<str>,
 6460        window: &mut Window,
 6461        cx: &mut Context<Self>,
 6462    ) {
 6463        self.code_action_providers
 6464            .retain(|provider| provider.id() != id);
 6465        self.refresh_code_actions(window, cx);
 6466    }
 6467
 6468    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6469        !self.code_action_providers.is_empty()
 6470            && EditorSettings::get_global(cx).toolbar.code_actions
 6471    }
 6472
 6473    pub fn has_available_code_actions(&self) -> bool {
 6474        self.available_code_actions
 6475            .as_ref()
 6476            .is_some_and(|(_, actions)| !actions.is_empty())
 6477    }
 6478
 6479    fn render_inline_code_actions(
 6480        &self,
 6481        icon_size: ui::IconSize,
 6482        display_row: DisplayRow,
 6483        is_active: bool,
 6484        cx: &mut Context<Self>,
 6485    ) -> AnyElement {
 6486        let show_tooltip = !self.context_menu_visible();
 6487        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6488            .icon_size(icon_size)
 6489            .shape(ui::IconButtonShape::Square)
 6490            .icon_color(ui::Color::Hidden)
 6491            .toggle_state(is_active)
 6492            .when(show_tooltip, |this| {
 6493                this.tooltip({
 6494                    let focus_handle = self.focus_handle.clone();
 6495                    move |_window, cx| {
 6496                        Tooltip::for_action_in(
 6497                            "Toggle Code Actions",
 6498                            &ToggleCodeActions {
 6499                                deployed_from: None,
 6500                                quick_launch: false,
 6501                            },
 6502                            &focus_handle,
 6503                            cx,
 6504                        )
 6505                    }
 6506                })
 6507            })
 6508            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6509                window.focus(&editor.focus_handle(cx));
 6510                editor.toggle_code_actions(
 6511                    &crate::actions::ToggleCodeActions {
 6512                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6513                            display_row,
 6514                        )),
 6515                        quick_launch: false,
 6516                    },
 6517                    window,
 6518                    cx,
 6519                );
 6520            }))
 6521            .into_any_element()
 6522    }
 6523
 6524    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6525        &self.context_menu
 6526    }
 6527
 6528    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6529        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6530            cx.background_executor()
 6531                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6532                .await;
 6533
 6534            let (start_buffer, start, _, end, newest_selection) = this
 6535                .update(cx, |this, cx| {
 6536                    let newest_selection = this.selections.newest_anchor().clone();
 6537                    if newest_selection.head().diff_base_anchor.is_some() {
 6538                        return None;
 6539                    }
 6540                    let display_snapshot = this.display_snapshot(cx);
 6541                    let newest_selection_adjusted =
 6542                        this.selections.newest_adjusted(&display_snapshot);
 6543                    let buffer = this.buffer.read(cx);
 6544
 6545                    let (start_buffer, start) =
 6546                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6547                    let (end_buffer, end) =
 6548                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6549
 6550                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6551                })?
 6552                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6553                .context(
 6554                    "Expected selection to lie in a single buffer when refreshing code actions",
 6555                )?;
 6556            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6557                let providers = this.code_action_providers.clone();
 6558                let tasks = this
 6559                    .code_action_providers
 6560                    .iter()
 6561                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6562                    .collect::<Vec<_>>();
 6563                (providers, tasks)
 6564            })?;
 6565
 6566            let mut actions = Vec::new();
 6567            for (provider, provider_actions) in
 6568                providers.into_iter().zip(future::join_all(tasks).await)
 6569            {
 6570                if let Some(provider_actions) = provider_actions.log_err() {
 6571                    actions.extend(provider_actions.into_iter().map(|action| {
 6572                        AvailableCodeAction {
 6573                            excerpt_id: newest_selection.start.excerpt_id,
 6574                            action,
 6575                            provider: provider.clone(),
 6576                        }
 6577                    }));
 6578                }
 6579            }
 6580
 6581            this.update(cx, |this, cx| {
 6582                this.available_code_actions = if actions.is_empty() {
 6583                    None
 6584                } else {
 6585                    Some((
 6586                        Location {
 6587                            buffer: start_buffer,
 6588                            range: start..end,
 6589                        },
 6590                        actions.into(),
 6591                    ))
 6592                };
 6593                cx.notify();
 6594            })
 6595        }));
 6596    }
 6597
 6598    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6599        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6600            self.show_git_blame_inline = false;
 6601
 6602            self.show_git_blame_inline_delay_task =
 6603                Some(cx.spawn_in(window, async move |this, cx| {
 6604                    cx.background_executor().timer(delay).await;
 6605
 6606                    this.update(cx, |this, cx| {
 6607                        this.show_git_blame_inline = true;
 6608                        cx.notify();
 6609                    })
 6610                    .log_err();
 6611                }));
 6612        }
 6613    }
 6614
 6615    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6616        let snapshot = self.snapshot(window, cx);
 6617        let cursor = self
 6618            .selections
 6619            .newest::<Point>(&snapshot.display_snapshot)
 6620            .head();
 6621        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6622        else {
 6623            return;
 6624        };
 6625
 6626        let Some(blame) = self.blame.as_ref() else {
 6627            return;
 6628        };
 6629
 6630        let row_info = RowInfo {
 6631            buffer_id: Some(buffer.remote_id()),
 6632            buffer_row: Some(point.row),
 6633            ..Default::default()
 6634        };
 6635        let Some((buffer, blame_entry)) = blame
 6636            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6637            .flatten()
 6638        else {
 6639            return;
 6640        };
 6641
 6642        let anchor = self.selections.newest_anchor().head();
 6643        let position = self.to_pixel_point(anchor, &snapshot, window);
 6644        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6645            self.show_blame_popover(
 6646                buffer,
 6647                &blame_entry,
 6648                position + last_bounds.origin,
 6649                true,
 6650                cx,
 6651            );
 6652        };
 6653    }
 6654
 6655    fn show_blame_popover(
 6656        &mut self,
 6657        buffer: BufferId,
 6658        blame_entry: &BlameEntry,
 6659        position: gpui::Point<Pixels>,
 6660        ignore_timeout: bool,
 6661        cx: &mut Context<Self>,
 6662    ) {
 6663        if let Some(state) = &mut self.inline_blame_popover {
 6664            state.hide_task.take();
 6665        } else {
 6666            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6667            let blame_entry = blame_entry.clone();
 6668            let show_task = cx.spawn(async move |editor, cx| {
 6669                if !ignore_timeout {
 6670                    cx.background_executor()
 6671                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6672                        .await;
 6673                }
 6674                editor
 6675                    .update(cx, |editor, cx| {
 6676                        editor.inline_blame_popover_show_task.take();
 6677                        let Some(blame) = editor.blame.as_ref() else {
 6678                            return;
 6679                        };
 6680                        let blame = blame.read(cx);
 6681                        let details = blame.details_for_entry(buffer, &blame_entry);
 6682                        let markdown = cx.new(|cx| {
 6683                            Markdown::new(
 6684                                details
 6685                                    .as_ref()
 6686                                    .map(|message| message.message.clone())
 6687                                    .unwrap_or_default(),
 6688                                None,
 6689                                None,
 6690                                cx,
 6691                            )
 6692                        });
 6693                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6694                            position,
 6695                            hide_task: None,
 6696                            popover_bounds: None,
 6697                            popover_state: InlineBlamePopoverState {
 6698                                scroll_handle: ScrollHandle::new(),
 6699                                commit_message: details,
 6700                                markdown,
 6701                            },
 6702                            keyboard_grace: ignore_timeout,
 6703                        });
 6704                        cx.notify();
 6705                    })
 6706                    .ok();
 6707            });
 6708            self.inline_blame_popover_show_task = Some(show_task);
 6709        }
 6710    }
 6711
 6712    fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6713        self.inline_blame_popover_show_task.take();
 6714        if let Some(state) = &mut self.inline_blame_popover {
 6715            let hide_task = cx.spawn(async move |editor, cx| {
 6716                if !ignore_timeout {
 6717                    cx.background_executor()
 6718                        .timer(std::time::Duration::from_millis(100))
 6719                        .await;
 6720                }
 6721                editor
 6722                    .update(cx, |editor, cx| {
 6723                        editor.inline_blame_popover.take();
 6724                        cx.notify();
 6725                    })
 6726                    .ok();
 6727            });
 6728            state.hide_task = Some(hide_task);
 6729            true
 6730        } else {
 6731            false
 6732        }
 6733    }
 6734
 6735    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6736        if self.pending_rename.is_some() {
 6737            return None;
 6738        }
 6739
 6740        let provider = self.semantics_provider.clone()?;
 6741        let buffer = self.buffer.read(cx);
 6742        let newest_selection = self.selections.newest_anchor().clone();
 6743        let cursor_position = newest_selection.head();
 6744        let (cursor_buffer, cursor_buffer_position) =
 6745            buffer.text_anchor_for_position(cursor_position, cx)?;
 6746        let (tail_buffer, tail_buffer_position) =
 6747            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6748        if cursor_buffer != tail_buffer {
 6749            return None;
 6750        }
 6751
 6752        let snapshot = cursor_buffer.read(cx).snapshot();
 6753        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6754        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6755        if start_word_range != end_word_range {
 6756            self.document_highlights_task.take();
 6757            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6758            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6759            return None;
 6760        }
 6761
 6762        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 6763        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6764            cx.background_executor()
 6765                .timer(Duration::from_millis(debounce))
 6766                .await;
 6767
 6768            let highlights = if let Some(highlights) = cx
 6769                .update(|cx| {
 6770                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6771                })
 6772                .ok()
 6773                .flatten()
 6774            {
 6775                highlights.await.log_err()
 6776            } else {
 6777                None
 6778            };
 6779
 6780            if let Some(highlights) = highlights {
 6781                this.update(cx, |this, cx| {
 6782                    if this.pending_rename.is_some() {
 6783                        return;
 6784                    }
 6785
 6786                    let buffer = this.buffer.read(cx);
 6787                    if buffer
 6788                        .text_anchor_for_position(cursor_position, cx)
 6789                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6790                    {
 6791                        return;
 6792                    }
 6793
 6794                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6795                    let mut write_ranges = Vec::new();
 6796                    let mut read_ranges = Vec::new();
 6797                    for highlight in highlights {
 6798                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6799                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6800                        {
 6801                            let start = highlight
 6802                                .range
 6803                                .start
 6804                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6805                            let end = highlight
 6806                                .range
 6807                                .end
 6808                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6809                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6810                                continue;
 6811                            }
 6812
 6813                            let range =
 6814                                Anchor::range_in_buffer(excerpt_id, buffer_id, *start..*end);
 6815                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6816                                write_ranges.push(range);
 6817                            } else {
 6818                                read_ranges.push(range);
 6819                            }
 6820                        }
 6821                    }
 6822
 6823                    this.highlight_background::<DocumentHighlightRead>(
 6824                        &read_ranges,
 6825                        |theme| theme.colors().editor_document_highlight_read_background,
 6826                        cx,
 6827                    );
 6828                    this.highlight_background::<DocumentHighlightWrite>(
 6829                        &write_ranges,
 6830                        |theme| theme.colors().editor_document_highlight_write_background,
 6831                        cx,
 6832                    );
 6833                    cx.notify();
 6834                })
 6835                .log_err();
 6836            }
 6837        }));
 6838        None
 6839    }
 6840
 6841    fn prepare_highlight_query_from_selection(
 6842        &mut self,
 6843        window: &Window,
 6844        cx: &mut Context<Editor>,
 6845    ) -> Option<(String, Range<Anchor>)> {
 6846        if matches!(self.mode, EditorMode::SingleLine) {
 6847            return None;
 6848        }
 6849        if !EditorSettings::get_global(cx).selection_highlight {
 6850            return None;
 6851        }
 6852        if self.selections.count() != 1 || self.selections.line_mode() {
 6853            return None;
 6854        }
 6855        let snapshot = self.snapshot(window, cx);
 6856        let selection = self.selections.newest::<Point>(&snapshot);
 6857        // If the selection spans multiple rows OR it is empty
 6858        if selection.start.row != selection.end.row
 6859            || selection.start.column == selection.end.column
 6860        {
 6861            return None;
 6862        }
 6863        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 6864        let query = snapshot
 6865            .buffer_snapshot()
 6866            .text_for_range(selection_anchor_range.clone())
 6867            .collect::<String>();
 6868        if query.trim().is_empty() {
 6869            return None;
 6870        }
 6871        Some((query, selection_anchor_range))
 6872    }
 6873
 6874    fn update_selection_occurrence_highlights(
 6875        &mut self,
 6876        query_text: String,
 6877        query_range: Range<Anchor>,
 6878        multi_buffer_range_to_query: Range<Point>,
 6879        use_debounce: bool,
 6880        window: &mut Window,
 6881        cx: &mut Context<Editor>,
 6882    ) -> Task<()> {
 6883        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6884        cx.spawn_in(window, async move |editor, cx| {
 6885            if use_debounce {
 6886                cx.background_executor()
 6887                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6888                    .await;
 6889            }
 6890            let match_task = cx.background_spawn(async move {
 6891                let buffer_ranges = multi_buffer_snapshot
 6892                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6893                    .into_iter()
 6894                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6895                let mut match_ranges = Vec::new();
 6896                let Ok(regex) = project::search::SearchQuery::text(
 6897                    query_text.clone(),
 6898                    false,
 6899                    false,
 6900                    false,
 6901                    Default::default(),
 6902                    Default::default(),
 6903                    false,
 6904                    None,
 6905                ) else {
 6906                    return Vec::default();
 6907                };
 6908                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 6909                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6910                    match_ranges.extend(
 6911                        regex
 6912                            .search(buffer_snapshot, Some(search_range.clone()))
 6913                            .await
 6914                            .into_iter()
 6915                            .filter_map(|match_range| {
 6916                                let match_start = buffer_snapshot
 6917                                    .anchor_after(search_range.start + match_range.start);
 6918                                let match_end = buffer_snapshot
 6919                                    .anchor_before(search_range.start + match_range.end);
 6920                                let match_anchor_range = Anchor::range_in_buffer(
 6921                                    excerpt_id,
 6922                                    buffer_snapshot.remote_id(),
 6923                                    match_start..match_end,
 6924                                );
 6925                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6926                            }),
 6927                    );
 6928                }
 6929                match_ranges
 6930            });
 6931            let match_ranges = match_task.await;
 6932            editor
 6933                .update_in(cx, |editor, _, cx| {
 6934                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6935                    if !match_ranges.is_empty() {
 6936                        editor.highlight_background::<SelectedTextHighlight>(
 6937                            &match_ranges,
 6938                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6939                            cx,
 6940                        )
 6941                    }
 6942                })
 6943                .log_err();
 6944        })
 6945    }
 6946
 6947    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6948        struct NewlineFold;
 6949        let type_id = std::any::TypeId::of::<NewlineFold>();
 6950        if !self.mode.is_single_line() {
 6951            return;
 6952        }
 6953        let snapshot = self.snapshot(window, cx);
 6954        if snapshot.buffer_snapshot().max_point().row == 0 {
 6955            return;
 6956        }
 6957        let task = cx.background_spawn(async move {
 6958            let new_newlines = snapshot
 6959                .buffer_chars_at(0)
 6960                .filter_map(|(c, i)| {
 6961                    if c == '\n' {
 6962                        Some(
 6963                            snapshot.buffer_snapshot().anchor_after(i)
 6964                                ..snapshot.buffer_snapshot().anchor_before(i + 1),
 6965                        )
 6966                    } else {
 6967                        None
 6968                    }
 6969                })
 6970                .collect::<Vec<_>>();
 6971            let existing_newlines = snapshot
 6972                .folds_in_range(0..snapshot.buffer_snapshot().len())
 6973                .filter_map(|fold| {
 6974                    if fold.placeholder.type_tag == Some(type_id) {
 6975                        Some(fold.range.start..fold.range.end)
 6976                    } else {
 6977                        None
 6978                    }
 6979                })
 6980                .collect::<Vec<_>>();
 6981
 6982            (new_newlines, existing_newlines)
 6983        });
 6984        self.folding_newlines = cx.spawn(async move |this, cx| {
 6985            let (new_newlines, existing_newlines) = task.await;
 6986            if new_newlines == existing_newlines {
 6987                return;
 6988            }
 6989            let placeholder = FoldPlaceholder {
 6990                render: Arc::new(move |_, _, cx| {
 6991                    div()
 6992                        .bg(cx.theme().status().hint_background)
 6993                        .border_b_1()
 6994                        .size_full()
 6995                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6996                        .border_color(cx.theme().status().hint)
 6997                        .child("\\n")
 6998                        .into_any()
 6999                }),
 7000                constrain_width: false,
 7001                merge_adjacent: false,
 7002                type_tag: Some(type_id),
 7003            };
 7004            let creases = new_newlines
 7005                .into_iter()
 7006                .map(|range| Crease::simple(range, placeholder.clone()))
 7007                .collect();
 7008            this.update(cx, |this, cx| {
 7009                this.display_map.update(cx, |display_map, cx| {
 7010                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7011                    display_map.fold(creases, cx);
 7012                });
 7013            })
 7014            .ok();
 7015        });
 7016    }
 7017
 7018    fn refresh_selected_text_highlights(
 7019        &mut self,
 7020        on_buffer_edit: bool,
 7021        window: &mut Window,
 7022        cx: &mut Context<Editor>,
 7023    ) {
 7024        let Some((query_text, query_range)) =
 7025            self.prepare_highlight_query_from_selection(window, cx)
 7026        else {
 7027            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7028            self.quick_selection_highlight_task.take();
 7029            self.debounced_selection_highlight_task.take();
 7030            return;
 7031        };
 7032        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7033        if on_buffer_edit
 7034            || self
 7035                .quick_selection_highlight_task
 7036                .as_ref()
 7037                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7038        {
 7039            let multi_buffer_visible_start = self
 7040                .scroll_manager
 7041                .anchor()
 7042                .anchor
 7043                .to_point(&multi_buffer_snapshot);
 7044            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7045                multi_buffer_visible_start
 7046                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7047                Bias::Left,
 7048            );
 7049            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7050            self.quick_selection_highlight_task = Some((
 7051                query_range.clone(),
 7052                self.update_selection_occurrence_highlights(
 7053                    query_text.clone(),
 7054                    query_range.clone(),
 7055                    multi_buffer_visible_range,
 7056                    false,
 7057                    window,
 7058                    cx,
 7059                ),
 7060            ));
 7061        }
 7062        if on_buffer_edit
 7063            || self
 7064                .debounced_selection_highlight_task
 7065                .as_ref()
 7066                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7067        {
 7068            let multi_buffer_start = multi_buffer_snapshot
 7069                .anchor_before(0)
 7070                .to_point(&multi_buffer_snapshot);
 7071            let multi_buffer_end = multi_buffer_snapshot
 7072                .anchor_after(multi_buffer_snapshot.len())
 7073                .to_point(&multi_buffer_snapshot);
 7074            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7075            self.debounced_selection_highlight_task = Some((
 7076                query_range.clone(),
 7077                self.update_selection_occurrence_highlights(
 7078                    query_text,
 7079                    query_range,
 7080                    multi_buffer_full_range,
 7081                    true,
 7082                    window,
 7083                    cx,
 7084                ),
 7085            ));
 7086        }
 7087    }
 7088
 7089    pub fn refresh_edit_prediction(
 7090        &mut self,
 7091        debounce: bool,
 7092        user_requested: bool,
 7093        window: &mut Window,
 7094        cx: &mut Context<Self>,
 7095    ) -> Option<()> {
 7096        if DisableAiSettings::get_global(cx).disable_ai {
 7097            return None;
 7098        }
 7099
 7100        let provider = self.edit_prediction_provider()?;
 7101        let cursor = self.selections.newest_anchor().head();
 7102        let (buffer, cursor_buffer_position) =
 7103            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7104
 7105        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7106            self.discard_edit_prediction(false, cx);
 7107            return None;
 7108        }
 7109
 7110        self.update_visible_edit_prediction(window, cx);
 7111
 7112        if !user_requested
 7113            && (!self.should_show_edit_predictions()
 7114                || !self.is_focused(window)
 7115                || buffer.read(cx).is_empty())
 7116        {
 7117            self.discard_edit_prediction(false, cx);
 7118            return None;
 7119        }
 7120
 7121        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7122        Some(())
 7123    }
 7124
 7125    fn show_edit_predictions_in_menu(&self) -> bool {
 7126        match self.edit_prediction_settings {
 7127            EditPredictionSettings::Disabled => false,
 7128            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7129        }
 7130    }
 7131
 7132    pub fn edit_predictions_enabled(&self) -> bool {
 7133        match self.edit_prediction_settings {
 7134            EditPredictionSettings::Disabled => false,
 7135            EditPredictionSettings::Enabled { .. } => true,
 7136        }
 7137    }
 7138
 7139    fn edit_prediction_requires_modifier(&self) -> bool {
 7140        match self.edit_prediction_settings {
 7141            EditPredictionSettings::Disabled => false,
 7142            EditPredictionSettings::Enabled {
 7143                preview_requires_modifier,
 7144                ..
 7145            } => preview_requires_modifier,
 7146        }
 7147    }
 7148
 7149    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7150        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7151            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7152            self.discard_edit_prediction(false, cx);
 7153        } else {
 7154            let selection = self.selections.newest_anchor();
 7155            let cursor = selection.head();
 7156
 7157            if let Some((buffer, cursor_buffer_position)) =
 7158                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7159            {
 7160                self.edit_prediction_settings =
 7161                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7162            }
 7163        }
 7164    }
 7165
 7166    fn edit_prediction_settings_at_position(
 7167        &self,
 7168        buffer: &Entity<Buffer>,
 7169        buffer_position: language::Anchor,
 7170        cx: &App,
 7171    ) -> EditPredictionSettings {
 7172        if !self.mode.is_full()
 7173            || !self.show_edit_predictions_override.unwrap_or(true)
 7174            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7175        {
 7176            return EditPredictionSettings::Disabled;
 7177        }
 7178
 7179        let buffer = buffer.read(cx);
 7180
 7181        let file = buffer.file();
 7182
 7183        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7184            return EditPredictionSettings::Disabled;
 7185        };
 7186
 7187        let by_provider = matches!(
 7188            self.menu_edit_predictions_policy,
 7189            MenuEditPredictionsPolicy::ByProvider
 7190        );
 7191
 7192        let show_in_menu = by_provider
 7193            && self
 7194                .edit_prediction_provider
 7195                .as_ref()
 7196                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7197
 7198        let preview_requires_modifier =
 7199            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7200
 7201        EditPredictionSettings::Enabled {
 7202            show_in_menu,
 7203            preview_requires_modifier,
 7204        }
 7205    }
 7206
 7207    fn should_show_edit_predictions(&self) -> bool {
 7208        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7209    }
 7210
 7211    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7212        matches!(
 7213            self.edit_prediction_preview,
 7214            EditPredictionPreview::Active { .. }
 7215        )
 7216    }
 7217
 7218    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7219        let cursor = self.selections.newest_anchor().head();
 7220        if let Some((buffer, cursor_position)) =
 7221            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7222        {
 7223            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7224        } else {
 7225            false
 7226        }
 7227    }
 7228
 7229    pub fn supports_minimap(&self, cx: &App) -> bool {
 7230        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7231    }
 7232
 7233    fn edit_predictions_enabled_in_buffer(
 7234        &self,
 7235        buffer: &Entity<Buffer>,
 7236        buffer_position: language::Anchor,
 7237        cx: &App,
 7238    ) -> bool {
 7239        maybe!({
 7240            if self.read_only(cx) {
 7241                return Some(false);
 7242            }
 7243            let provider = self.edit_prediction_provider()?;
 7244            if !provider.is_enabled(buffer, buffer_position, cx) {
 7245                return Some(false);
 7246            }
 7247            let buffer = buffer.read(cx);
 7248            let Some(file) = buffer.file() else {
 7249                return Some(true);
 7250            };
 7251            let settings = all_language_settings(Some(file), cx);
 7252            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7253        })
 7254        .unwrap_or(false)
 7255    }
 7256
 7257    fn cycle_edit_prediction(
 7258        &mut self,
 7259        direction: Direction,
 7260        window: &mut Window,
 7261        cx: &mut Context<Self>,
 7262    ) -> Option<()> {
 7263        let provider = self.edit_prediction_provider()?;
 7264        let cursor = self.selections.newest_anchor().head();
 7265        let (buffer, cursor_buffer_position) =
 7266            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7267        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7268            return None;
 7269        }
 7270
 7271        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7272        self.update_visible_edit_prediction(window, cx);
 7273
 7274        Some(())
 7275    }
 7276
 7277    pub fn show_edit_prediction(
 7278        &mut self,
 7279        _: &ShowEditPrediction,
 7280        window: &mut Window,
 7281        cx: &mut Context<Self>,
 7282    ) {
 7283        if !self.has_active_edit_prediction() {
 7284            self.refresh_edit_prediction(false, true, window, cx);
 7285            return;
 7286        }
 7287
 7288        self.update_visible_edit_prediction(window, cx);
 7289    }
 7290
 7291    pub fn display_cursor_names(
 7292        &mut self,
 7293        _: &DisplayCursorNames,
 7294        window: &mut Window,
 7295        cx: &mut Context<Self>,
 7296    ) {
 7297        self.show_cursor_names(window, cx);
 7298    }
 7299
 7300    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7301        self.show_cursor_names = true;
 7302        cx.notify();
 7303        cx.spawn_in(window, async move |this, cx| {
 7304            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7305            this.update(cx, |this, cx| {
 7306                this.show_cursor_names = false;
 7307                cx.notify()
 7308            })
 7309            .ok()
 7310        })
 7311        .detach();
 7312    }
 7313
 7314    pub fn next_edit_prediction(
 7315        &mut self,
 7316        _: &NextEditPrediction,
 7317        window: &mut Window,
 7318        cx: &mut Context<Self>,
 7319    ) {
 7320        if self.has_active_edit_prediction() {
 7321            self.cycle_edit_prediction(Direction::Next, window, cx);
 7322        } else {
 7323            let is_copilot_disabled = self
 7324                .refresh_edit_prediction(false, true, window, cx)
 7325                .is_none();
 7326            if is_copilot_disabled {
 7327                cx.propagate();
 7328            }
 7329        }
 7330    }
 7331
 7332    pub fn previous_edit_prediction(
 7333        &mut self,
 7334        _: &PreviousEditPrediction,
 7335        window: &mut Window,
 7336        cx: &mut Context<Self>,
 7337    ) {
 7338        if self.has_active_edit_prediction() {
 7339            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7340        } else {
 7341            let is_copilot_disabled = self
 7342                .refresh_edit_prediction(false, true, window, cx)
 7343                .is_none();
 7344            if is_copilot_disabled {
 7345                cx.propagate();
 7346            }
 7347        }
 7348    }
 7349
 7350    pub fn accept_edit_prediction(
 7351        &mut self,
 7352        _: &AcceptEditPrediction,
 7353        window: &mut Window,
 7354        cx: &mut Context<Self>,
 7355    ) {
 7356        if self.show_edit_predictions_in_menu() {
 7357            self.hide_context_menu(window, cx);
 7358        }
 7359
 7360        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7361            return;
 7362        };
 7363
 7364        match &active_edit_prediction.completion {
 7365            EditPrediction::MoveWithin { target, .. } => {
 7366                let target = *target;
 7367
 7368                if let Some(position_map) = &self.last_position_map {
 7369                    if position_map
 7370                        .visible_row_range
 7371                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7372                        || !self.edit_prediction_requires_modifier()
 7373                    {
 7374                        self.unfold_ranges(&[target..target], true, false, cx);
 7375                        // Note that this is also done in vim's handler of the Tab action.
 7376                        self.change_selections(
 7377                            SelectionEffects::scroll(Autoscroll::newest()),
 7378                            window,
 7379                            cx,
 7380                            |selections| {
 7381                                selections.select_anchor_ranges([target..target]);
 7382                            },
 7383                        );
 7384                        self.clear_row_highlights::<EditPredictionPreview>();
 7385
 7386                        self.edit_prediction_preview
 7387                            .set_previous_scroll_position(None);
 7388                    } else {
 7389                        self.edit_prediction_preview
 7390                            .set_previous_scroll_position(Some(
 7391                                position_map.snapshot.scroll_anchor,
 7392                            ));
 7393
 7394                        self.highlight_rows::<EditPredictionPreview>(
 7395                            target..target,
 7396                            cx.theme().colors().editor_highlighted_line_background,
 7397                            RowHighlightOptions {
 7398                                autoscroll: true,
 7399                                ..Default::default()
 7400                            },
 7401                            cx,
 7402                        );
 7403                        self.request_autoscroll(Autoscroll::fit(), cx);
 7404                    }
 7405                }
 7406            }
 7407            EditPrediction::MoveOutside { snapshot, target } => {
 7408                if let Some(workspace) = self.workspace() {
 7409                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7410                        .detach_and_log_err(cx);
 7411                }
 7412            }
 7413            EditPrediction::Edit { edits, .. } => {
 7414                self.report_edit_prediction_event(
 7415                    active_edit_prediction.completion_id.clone(),
 7416                    true,
 7417                    cx,
 7418                );
 7419
 7420                if let Some(provider) = self.edit_prediction_provider() {
 7421                    provider.accept(cx);
 7422                }
 7423
 7424                // Store the transaction ID and selections before applying the edit
 7425                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7426
 7427                let snapshot = self.buffer.read(cx).snapshot(cx);
 7428                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7429
 7430                self.buffer.update(cx, |buffer, cx| {
 7431                    buffer.edit(edits.iter().cloned(), None, cx)
 7432                });
 7433
 7434                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7435                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7436                });
 7437
 7438                let selections = self.selections.disjoint_anchors_arc();
 7439                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7440                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7441                    if has_new_transaction {
 7442                        self.selection_history
 7443                            .insert_transaction(transaction_id_now, selections);
 7444                    }
 7445                }
 7446
 7447                self.update_visible_edit_prediction(window, cx);
 7448                if self.active_edit_prediction.is_none() {
 7449                    self.refresh_edit_prediction(true, true, window, cx);
 7450                }
 7451
 7452                cx.notify();
 7453            }
 7454        }
 7455
 7456        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7457    }
 7458
 7459    pub fn accept_partial_edit_prediction(
 7460        &mut self,
 7461        _: &AcceptPartialEditPrediction,
 7462        window: &mut Window,
 7463        cx: &mut Context<Self>,
 7464    ) {
 7465        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7466            return;
 7467        };
 7468        if self.selections.count() != 1 {
 7469            return;
 7470        }
 7471
 7472        match &active_edit_prediction.completion {
 7473            EditPrediction::MoveWithin { target, .. } => {
 7474                let target = *target;
 7475                self.change_selections(
 7476                    SelectionEffects::scroll(Autoscroll::newest()),
 7477                    window,
 7478                    cx,
 7479                    |selections| {
 7480                        selections.select_anchor_ranges([target..target]);
 7481                    },
 7482                );
 7483            }
 7484            EditPrediction::MoveOutside { snapshot, target } => {
 7485                if let Some(workspace) = self.workspace() {
 7486                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7487                        .detach_and_log_err(cx);
 7488                }
 7489            }
 7490            EditPrediction::Edit { edits, .. } => {
 7491                self.report_edit_prediction_event(
 7492                    active_edit_prediction.completion_id.clone(),
 7493                    true,
 7494                    cx,
 7495                );
 7496
 7497                // Find an insertion that starts at the cursor position.
 7498                let snapshot = self.buffer.read(cx).snapshot(cx);
 7499                let cursor_offset = self
 7500                    .selections
 7501                    .newest::<usize>(&self.display_snapshot(cx))
 7502                    .head();
 7503                let insertion = edits.iter().find_map(|(range, text)| {
 7504                    let range = range.to_offset(&snapshot);
 7505                    if range.is_empty() && range.start == cursor_offset {
 7506                        Some(text)
 7507                    } else {
 7508                        None
 7509                    }
 7510                });
 7511
 7512                if let Some(text) = insertion {
 7513                    let mut partial_completion = text
 7514                        .chars()
 7515                        .by_ref()
 7516                        .take_while(|c| c.is_alphabetic())
 7517                        .collect::<String>();
 7518                    if partial_completion.is_empty() {
 7519                        partial_completion = text
 7520                            .chars()
 7521                            .by_ref()
 7522                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7523                            .collect::<String>();
 7524                    }
 7525
 7526                    cx.emit(EditorEvent::InputHandled {
 7527                        utf16_range_to_replace: None,
 7528                        text: partial_completion.clone().into(),
 7529                    });
 7530
 7531                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7532
 7533                    self.refresh_edit_prediction(true, true, window, cx);
 7534                    cx.notify();
 7535                } else {
 7536                    self.accept_edit_prediction(&Default::default(), window, cx);
 7537                }
 7538            }
 7539        }
 7540    }
 7541
 7542    fn discard_edit_prediction(
 7543        &mut self,
 7544        should_report_edit_prediction_event: bool,
 7545        cx: &mut Context<Self>,
 7546    ) -> bool {
 7547        if should_report_edit_prediction_event {
 7548            let completion_id = self
 7549                .active_edit_prediction
 7550                .as_ref()
 7551                .and_then(|active_completion| active_completion.completion_id.clone());
 7552
 7553            self.report_edit_prediction_event(completion_id, false, cx);
 7554        }
 7555
 7556        if let Some(provider) = self.edit_prediction_provider() {
 7557            provider.discard(cx);
 7558        }
 7559
 7560        self.take_active_edit_prediction(cx)
 7561    }
 7562
 7563    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7564        let Some(provider) = self.edit_prediction_provider() else {
 7565            return;
 7566        };
 7567
 7568        let Some((_, buffer, _)) = self
 7569            .buffer
 7570            .read(cx)
 7571            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7572        else {
 7573            return;
 7574        };
 7575
 7576        let extension = buffer
 7577            .read(cx)
 7578            .file()
 7579            .and_then(|file| Some(file.path().extension()?.to_string()));
 7580
 7581        let event_type = match accepted {
 7582            true => "Edit Prediction Accepted",
 7583            false => "Edit Prediction Discarded",
 7584        };
 7585        telemetry::event!(
 7586            event_type,
 7587            provider = provider.name(),
 7588            prediction_id = id,
 7589            suggestion_accepted = accepted,
 7590            file_extension = extension,
 7591        );
 7592    }
 7593
 7594    fn open_editor_at_anchor(
 7595        snapshot: &language::BufferSnapshot,
 7596        target: language::Anchor,
 7597        workspace: &Entity<Workspace>,
 7598        window: &mut Window,
 7599        cx: &mut App,
 7600    ) -> Task<Result<()>> {
 7601        workspace.update(cx, |workspace, cx| {
 7602            let path = snapshot.file().map(|file| file.full_path(cx));
 7603            let Some(path) =
 7604                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7605            else {
 7606                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7607            };
 7608            let target = text::ToPoint::to_point(&target, snapshot);
 7609            let item = workspace.open_path(path, None, true, window, cx);
 7610            window.spawn(cx, async move |cx| {
 7611                let Some(editor) = item.await?.downcast::<Editor>() else {
 7612                    return Ok(());
 7613                };
 7614                editor
 7615                    .update_in(cx, |editor, window, cx| {
 7616                        editor.go_to_singleton_buffer_point(target, window, cx);
 7617                    })
 7618                    .ok();
 7619                anyhow::Ok(())
 7620            })
 7621        })
 7622    }
 7623
 7624    pub fn has_active_edit_prediction(&self) -> bool {
 7625        self.active_edit_prediction.is_some()
 7626    }
 7627
 7628    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7629        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7630            return false;
 7631        };
 7632
 7633        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7634        self.clear_highlights::<EditPredictionHighlight>(cx);
 7635        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7636        true
 7637    }
 7638
 7639    /// Returns true when we're displaying the edit prediction popover below the cursor
 7640    /// like we are not previewing and the LSP autocomplete menu is visible
 7641    /// or we are in `when_holding_modifier` mode.
 7642    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7643        if self.edit_prediction_preview_is_active()
 7644            || !self.show_edit_predictions_in_menu()
 7645            || !self.edit_predictions_enabled()
 7646        {
 7647            return false;
 7648        }
 7649
 7650        if self.has_visible_completions_menu() {
 7651            return true;
 7652        }
 7653
 7654        has_completion && self.edit_prediction_requires_modifier()
 7655    }
 7656
 7657    fn handle_modifiers_changed(
 7658        &mut self,
 7659        modifiers: Modifiers,
 7660        position_map: &PositionMap,
 7661        window: &mut Window,
 7662        cx: &mut Context<Self>,
 7663    ) {
 7664        // Ensure that the edit prediction preview is updated, even when not
 7665        // enabled, if there's an active edit prediction preview.
 7666        if self.show_edit_predictions_in_menu()
 7667            || matches!(
 7668                self.edit_prediction_preview,
 7669                EditPredictionPreview::Active { .. }
 7670            )
 7671        {
 7672            self.update_edit_prediction_preview(&modifiers, window, cx);
 7673        }
 7674
 7675        self.update_selection_mode(&modifiers, position_map, window, cx);
 7676
 7677        let mouse_position = window.mouse_position();
 7678        if !position_map.text_hitbox.is_hovered(window) {
 7679            return;
 7680        }
 7681
 7682        self.update_hovered_link(
 7683            position_map.point_for_position(mouse_position),
 7684            &position_map.snapshot,
 7685            modifiers,
 7686            window,
 7687            cx,
 7688        )
 7689    }
 7690
 7691    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7692        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7693            MultiCursorModifier::Alt => modifiers.secondary(),
 7694            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7695        }
 7696    }
 7697
 7698    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7699        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7700            MultiCursorModifier::Alt => modifiers.alt,
 7701            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7702        }
 7703    }
 7704
 7705    fn columnar_selection_mode(
 7706        modifiers: &Modifiers,
 7707        cx: &mut Context<Self>,
 7708    ) -> Option<ColumnarMode> {
 7709        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7710            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 7711                Some(ColumnarMode::FromMouse)
 7712            } else if Self::is_alt_pressed(modifiers, cx) {
 7713                Some(ColumnarMode::FromSelection)
 7714            } else {
 7715                None
 7716            }
 7717        } else {
 7718            None
 7719        }
 7720    }
 7721
 7722    fn update_selection_mode(
 7723        &mut self,
 7724        modifiers: &Modifiers,
 7725        position_map: &PositionMap,
 7726        window: &mut Window,
 7727        cx: &mut Context<Self>,
 7728    ) {
 7729        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7730            return;
 7731        };
 7732        if self.selections.pending_anchor().is_none() {
 7733            return;
 7734        }
 7735
 7736        let mouse_position = window.mouse_position();
 7737        let point_for_position = position_map.point_for_position(mouse_position);
 7738        let position = point_for_position.previous_valid;
 7739
 7740        self.select(
 7741            SelectPhase::BeginColumnar {
 7742                position,
 7743                reset: false,
 7744                mode,
 7745                goal_column: point_for_position.exact_unclipped.column(),
 7746            },
 7747            window,
 7748            cx,
 7749        );
 7750    }
 7751
 7752    fn update_edit_prediction_preview(
 7753        &mut self,
 7754        modifiers: &Modifiers,
 7755        window: &mut Window,
 7756        cx: &mut Context<Self>,
 7757    ) {
 7758        let mut modifiers_held = false;
 7759        if let Some(accept_keystroke) = self
 7760            .accept_edit_prediction_keybind(false, window, cx)
 7761            .keystroke()
 7762        {
 7763            modifiers_held = modifiers_held
 7764                || (accept_keystroke.modifiers() == modifiers
 7765                    && accept_keystroke.modifiers().modified());
 7766        };
 7767        if let Some(accept_partial_keystroke) = self
 7768            .accept_edit_prediction_keybind(true, window, cx)
 7769            .keystroke()
 7770        {
 7771            modifiers_held = modifiers_held
 7772                || (accept_partial_keystroke.modifiers() == modifiers
 7773                    && accept_partial_keystroke.modifiers().modified());
 7774        }
 7775
 7776        if modifiers_held {
 7777            if matches!(
 7778                self.edit_prediction_preview,
 7779                EditPredictionPreview::Inactive { .. }
 7780            ) {
 7781                self.edit_prediction_preview = EditPredictionPreview::Active {
 7782                    previous_scroll_position: None,
 7783                    since: Instant::now(),
 7784                };
 7785
 7786                self.update_visible_edit_prediction(window, cx);
 7787                cx.notify();
 7788            }
 7789        } else if let EditPredictionPreview::Active {
 7790            previous_scroll_position,
 7791            since,
 7792        } = self.edit_prediction_preview
 7793        {
 7794            if let (Some(previous_scroll_position), Some(position_map)) =
 7795                (previous_scroll_position, self.last_position_map.as_ref())
 7796            {
 7797                self.set_scroll_position(
 7798                    previous_scroll_position
 7799                        .scroll_position(&position_map.snapshot.display_snapshot),
 7800                    window,
 7801                    cx,
 7802                );
 7803            }
 7804
 7805            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7806                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7807            };
 7808            self.clear_row_highlights::<EditPredictionPreview>();
 7809            self.update_visible_edit_prediction(window, cx);
 7810            cx.notify();
 7811        }
 7812    }
 7813
 7814    fn update_visible_edit_prediction(
 7815        &mut self,
 7816        _window: &mut Window,
 7817        cx: &mut Context<Self>,
 7818    ) -> Option<()> {
 7819        if DisableAiSettings::get_global(cx).disable_ai {
 7820            return None;
 7821        }
 7822
 7823        if self.ime_transaction.is_some() {
 7824            self.discard_edit_prediction(false, cx);
 7825            return None;
 7826        }
 7827
 7828        let selection = self.selections.newest_anchor();
 7829        let cursor = selection.head();
 7830        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7831        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7832        let excerpt_id = cursor.excerpt_id;
 7833
 7834        let show_in_menu = self.show_edit_predictions_in_menu();
 7835        let completions_menu_has_precedence = !show_in_menu
 7836            && (self.context_menu.borrow().is_some()
 7837                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7838
 7839        if completions_menu_has_precedence
 7840            || !offset_selection.is_empty()
 7841            || self
 7842                .active_edit_prediction
 7843                .as_ref()
 7844                .is_some_and(|completion| {
 7845                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7846                        return false;
 7847                    };
 7848                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7849                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7850                    !invalidation_range.contains(&offset_selection.head())
 7851                })
 7852        {
 7853            self.discard_edit_prediction(false, cx);
 7854            return None;
 7855        }
 7856
 7857        self.take_active_edit_prediction(cx);
 7858        let Some(provider) = self.edit_prediction_provider() else {
 7859            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7860            return None;
 7861        };
 7862
 7863        let (buffer, cursor_buffer_position) =
 7864            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7865
 7866        self.edit_prediction_settings =
 7867            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7868
 7869        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7870
 7871        if self.edit_prediction_indent_conflict {
 7872            let cursor_point = cursor.to_point(&multibuffer);
 7873
 7874            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7875
 7876            if let Some((_, indent)) = indents.iter().next()
 7877                && indent.len == cursor_point.column
 7878            {
 7879                self.edit_prediction_indent_conflict = false;
 7880            }
 7881        }
 7882
 7883        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7884
 7885        let (completion_id, edits, edit_preview) = match edit_prediction {
 7886            edit_prediction::EditPrediction::Local {
 7887                id,
 7888                edits,
 7889                edit_preview,
 7890            } => (id, edits, edit_preview),
 7891            edit_prediction::EditPrediction::Jump {
 7892                id,
 7893                snapshot,
 7894                target,
 7895            } => {
 7896                self.stale_edit_prediction_in_menu = None;
 7897                self.active_edit_prediction = Some(EditPredictionState {
 7898                    inlay_ids: vec![],
 7899                    completion: EditPrediction::MoveOutside { snapshot, target },
 7900                    completion_id: id,
 7901                    invalidation_range: None,
 7902                });
 7903                cx.notify();
 7904                return Some(());
 7905            }
 7906        };
 7907
 7908        let edits = edits
 7909            .into_iter()
 7910            .flat_map(|(range, new_text)| {
 7911                Some((
 7912                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 7913                    new_text,
 7914                ))
 7915            })
 7916            .collect::<Vec<_>>();
 7917        if edits.is_empty() {
 7918            return None;
 7919        }
 7920
 7921        let first_edit_start = edits.first().unwrap().0.start;
 7922        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7923        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7924
 7925        let last_edit_end = edits.last().unwrap().0.end;
 7926        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7927        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7928
 7929        let cursor_row = cursor.to_point(&multibuffer).row;
 7930
 7931        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7932
 7933        let mut inlay_ids = Vec::new();
 7934        let invalidation_row_range;
 7935        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7936            Some(cursor_row..edit_end_row)
 7937        } else if cursor_row > edit_end_row {
 7938            Some(edit_start_row..cursor_row)
 7939        } else {
 7940            None
 7941        };
 7942        let supports_jump = self
 7943            .edit_prediction_provider
 7944            .as_ref()
 7945            .map(|provider| provider.provider.supports_jump_to_edit())
 7946            .unwrap_or(true);
 7947
 7948        let is_move = supports_jump
 7949            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7950        let completion = if is_move {
 7951            invalidation_row_range =
 7952                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7953            let target = first_edit_start;
 7954            EditPrediction::MoveWithin { target, snapshot }
 7955        } else {
 7956            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7957                && !self.edit_predictions_hidden_for_vim_mode;
 7958
 7959            if show_completions_in_buffer {
 7960                if edits
 7961                    .iter()
 7962                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7963                {
 7964                    let mut inlays = Vec::new();
 7965                    for (range, new_text) in &edits {
 7966                        let inlay = Inlay::edit_prediction(
 7967                            post_inc(&mut self.next_inlay_id),
 7968                            range.start,
 7969                            new_text.as_ref(),
 7970                        );
 7971                        inlay_ids.push(inlay.id);
 7972                        inlays.push(inlay);
 7973                    }
 7974
 7975                    self.splice_inlays(&[], inlays, cx);
 7976                } else {
 7977                    let background_color = cx.theme().status().deleted_background;
 7978                    self.highlight_text::<EditPredictionHighlight>(
 7979                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7980                        HighlightStyle {
 7981                            background_color: Some(background_color),
 7982                            ..Default::default()
 7983                        },
 7984                        cx,
 7985                    );
 7986                }
 7987            }
 7988
 7989            invalidation_row_range = edit_start_row..edit_end_row;
 7990
 7991            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7992                if provider.show_tab_accept_marker() {
 7993                    EditDisplayMode::TabAccept
 7994                } else {
 7995                    EditDisplayMode::Inline
 7996                }
 7997            } else {
 7998                EditDisplayMode::DiffPopover
 7999            };
 8000
 8001            EditPrediction::Edit {
 8002                edits,
 8003                edit_preview,
 8004                display_mode,
 8005                snapshot,
 8006            }
 8007        };
 8008
 8009        let invalidation_range = multibuffer
 8010            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8011            ..multibuffer.anchor_after(Point::new(
 8012                invalidation_row_range.end,
 8013                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8014            ));
 8015
 8016        self.stale_edit_prediction_in_menu = None;
 8017        self.active_edit_prediction = Some(EditPredictionState {
 8018            inlay_ids,
 8019            completion,
 8020            completion_id,
 8021            invalidation_range: Some(invalidation_range),
 8022        });
 8023
 8024        cx.notify();
 8025
 8026        Some(())
 8027    }
 8028
 8029    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8030        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8031    }
 8032
 8033    fn clear_tasks(&mut self) {
 8034        self.tasks.clear()
 8035    }
 8036
 8037    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8038        if self.tasks.insert(key, value).is_some() {
 8039            // This case should hopefully be rare, but just in case...
 8040            log::error!(
 8041                "multiple different run targets found on a single line, only the last target will be rendered"
 8042            )
 8043        }
 8044    }
 8045
 8046    /// Get all display points of breakpoints that will be rendered within editor
 8047    ///
 8048    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8049    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8050    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8051    fn active_breakpoints(
 8052        &self,
 8053        range: Range<DisplayRow>,
 8054        window: &mut Window,
 8055        cx: &mut Context<Self>,
 8056    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8057        let mut breakpoint_display_points = HashMap::default();
 8058
 8059        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8060            return breakpoint_display_points;
 8061        };
 8062
 8063        let snapshot = self.snapshot(window, cx);
 8064
 8065        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8066        let Some(project) = self.project() else {
 8067            return breakpoint_display_points;
 8068        };
 8069
 8070        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8071            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8072
 8073        for (buffer_snapshot, range, excerpt_id) in
 8074            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8075        {
 8076            let Some(buffer) = project
 8077                .read(cx)
 8078                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8079            else {
 8080                continue;
 8081            };
 8082            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8083                &buffer,
 8084                Some(
 8085                    buffer_snapshot.anchor_before(range.start)
 8086                        ..buffer_snapshot.anchor_after(range.end),
 8087                ),
 8088                buffer_snapshot,
 8089                cx,
 8090            );
 8091            for (breakpoint, state) in breakpoints {
 8092                let multi_buffer_anchor =
 8093                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8094                let position = multi_buffer_anchor
 8095                    .to_point(&multi_buffer_snapshot)
 8096                    .to_display_point(&snapshot);
 8097
 8098                breakpoint_display_points.insert(
 8099                    position.row(),
 8100                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8101                );
 8102            }
 8103        }
 8104
 8105        breakpoint_display_points
 8106    }
 8107
 8108    fn breakpoint_context_menu(
 8109        &self,
 8110        anchor: Anchor,
 8111        window: &mut Window,
 8112        cx: &mut Context<Self>,
 8113    ) -> Entity<ui::ContextMenu> {
 8114        let weak_editor = cx.weak_entity();
 8115        let focus_handle = self.focus_handle(cx);
 8116
 8117        let row = self
 8118            .buffer
 8119            .read(cx)
 8120            .snapshot(cx)
 8121            .summary_for_anchor::<Point>(&anchor)
 8122            .row;
 8123
 8124        let breakpoint = self
 8125            .breakpoint_at_row(row, window, cx)
 8126            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8127
 8128        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8129            "Edit Log Breakpoint"
 8130        } else {
 8131            "Set Log Breakpoint"
 8132        };
 8133
 8134        let condition_breakpoint_msg = if breakpoint
 8135            .as_ref()
 8136            .is_some_and(|bp| bp.1.condition.is_some())
 8137        {
 8138            "Edit Condition Breakpoint"
 8139        } else {
 8140            "Set Condition Breakpoint"
 8141        };
 8142
 8143        let hit_condition_breakpoint_msg = if breakpoint
 8144            .as_ref()
 8145            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8146        {
 8147            "Edit Hit Condition Breakpoint"
 8148        } else {
 8149            "Set Hit Condition Breakpoint"
 8150        };
 8151
 8152        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8153            "Unset Breakpoint"
 8154        } else {
 8155            "Set Breakpoint"
 8156        };
 8157
 8158        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8159
 8160        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8161            BreakpointState::Enabled => Some("Disable"),
 8162            BreakpointState::Disabled => Some("Enable"),
 8163        });
 8164
 8165        let (anchor, breakpoint) =
 8166            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8167
 8168        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8169            menu.on_blur_subscription(Subscription::new(|| {}))
 8170                .context(focus_handle)
 8171                .when(run_to_cursor, |this| {
 8172                    let weak_editor = weak_editor.clone();
 8173                    this.entry("Run to cursor", None, move |window, cx| {
 8174                        weak_editor
 8175                            .update(cx, |editor, cx| {
 8176                                editor.change_selections(
 8177                                    SelectionEffects::no_scroll(),
 8178                                    window,
 8179                                    cx,
 8180                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8181                                );
 8182                            })
 8183                            .ok();
 8184
 8185                        window.dispatch_action(Box::new(RunToCursor), cx);
 8186                    })
 8187                    .separator()
 8188                })
 8189                .when_some(toggle_state_msg, |this, msg| {
 8190                    this.entry(msg, None, {
 8191                        let weak_editor = weak_editor.clone();
 8192                        let breakpoint = breakpoint.clone();
 8193                        move |_window, cx| {
 8194                            weak_editor
 8195                                .update(cx, |this, cx| {
 8196                                    this.edit_breakpoint_at_anchor(
 8197                                        anchor,
 8198                                        breakpoint.as_ref().clone(),
 8199                                        BreakpointEditAction::InvertState,
 8200                                        cx,
 8201                                    );
 8202                                })
 8203                                .log_err();
 8204                        }
 8205                    })
 8206                })
 8207                .entry(set_breakpoint_msg, None, {
 8208                    let weak_editor = weak_editor.clone();
 8209                    let breakpoint = breakpoint.clone();
 8210                    move |_window, cx| {
 8211                        weak_editor
 8212                            .update(cx, |this, cx| {
 8213                                this.edit_breakpoint_at_anchor(
 8214                                    anchor,
 8215                                    breakpoint.as_ref().clone(),
 8216                                    BreakpointEditAction::Toggle,
 8217                                    cx,
 8218                                );
 8219                            })
 8220                            .log_err();
 8221                    }
 8222                })
 8223                .entry(log_breakpoint_msg, None, {
 8224                    let breakpoint = breakpoint.clone();
 8225                    let weak_editor = weak_editor.clone();
 8226                    move |window, cx| {
 8227                        weak_editor
 8228                            .update(cx, |this, cx| {
 8229                                this.add_edit_breakpoint_block(
 8230                                    anchor,
 8231                                    breakpoint.as_ref(),
 8232                                    BreakpointPromptEditAction::Log,
 8233                                    window,
 8234                                    cx,
 8235                                );
 8236                            })
 8237                            .log_err();
 8238                    }
 8239                })
 8240                .entry(condition_breakpoint_msg, None, {
 8241                    let breakpoint = breakpoint.clone();
 8242                    let weak_editor = weak_editor.clone();
 8243                    move |window, cx| {
 8244                        weak_editor
 8245                            .update(cx, |this, cx| {
 8246                                this.add_edit_breakpoint_block(
 8247                                    anchor,
 8248                                    breakpoint.as_ref(),
 8249                                    BreakpointPromptEditAction::Condition,
 8250                                    window,
 8251                                    cx,
 8252                                );
 8253                            })
 8254                            .log_err();
 8255                    }
 8256                })
 8257                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8258                    weak_editor
 8259                        .update(cx, |this, cx| {
 8260                            this.add_edit_breakpoint_block(
 8261                                anchor,
 8262                                breakpoint.as_ref(),
 8263                                BreakpointPromptEditAction::HitCondition,
 8264                                window,
 8265                                cx,
 8266                            );
 8267                        })
 8268                        .log_err();
 8269                })
 8270        })
 8271    }
 8272
 8273    fn render_breakpoint(
 8274        &self,
 8275        position: Anchor,
 8276        row: DisplayRow,
 8277        breakpoint: &Breakpoint,
 8278        state: Option<BreakpointSessionState>,
 8279        cx: &mut Context<Self>,
 8280    ) -> IconButton {
 8281        let is_rejected = state.is_some_and(|s| !s.verified);
 8282        // Is it a breakpoint that shows up when hovering over gutter?
 8283        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8284            (false, false),
 8285            |PhantomBreakpointIndicator {
 8286                 is_active,
 8287                 display_row,
 8288                 collides_with_existing_breakpoint,
 8289             }| {
 8290                (
 8291                    is_active && display_row == row,
 8292                    collides_with_existing_breakpoint,
 8293                )
 8294            },
 8295        );
 8296
 8297        let (color, icon) = {
 8298            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8299                (false, false) => ui::IconName::DebugBreakpoint,
 8300                (true, false) => ui::IconName::DebugLogBreakpoint,
 8301                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8302                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8303            };
 8304
 8305            let color = if is_phantom {
 8306                Color::Hint
 8307            } else if is_rejected {
 8308                Color::Disabled
 8309            } else {
 8310                Color::Debugger
 8311            };
 8312
 8313            (color, icon)
 8314        };
 8315
 8316        let breakpoint = Arc::from(breakpoint.clone());
 8317
 8318        let alt_as_text = gpui::Keystroke {
 8319            modifiers: Modifiers::secondary_key(),
 8320            ..Default::default()
 8321        };
 8322        let primary_action_text = if breakpoint.is_disabled() {
 8323            "Enable breakpoint"
 8324        } else if is_phantom && !collides_with_existing {
 8325            "Set breakpoint"
 8326        } else {
 8327            "Unset breakpoint"
 8328        };
 8329        let focus_handle = self.focus_handle.clone();
 8330
 8331        let meta = if is_rejected {
 8332            SharedString::from("No executable code is associated with this line.")
 8333        } else if collides_with_existing && !breakpoint.is_disabled() {
 8334            SharedString::from(format!(
 8335                "{alt_as_text}-click to disable,\nright-click for more options."
 8336            ))
 8337        } else {
 8338            SharedString::from("Right-click for more options.")
 8339        };
 8340        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8341            .icon_size(IconSize::XSmall)
 8342            .size(ui::ButtonSize::None)
 8343            .when(is_rejected, |this| {
 8344                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8345            })
 8346            .icon_color(color)
 8347            .style(ButtonStyle::Transparent)
 8348            .on_click(cx.listener({
 8349                move |editor, event: &ClickEvent, window, cx| {
 8350                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8351                        BreakpointEditAction::InvertState
 8352                    } else {
 8353                        BreakpointEditAction::Toggle
 8354                    };
 8355
 8356                    window.focus(&editor.focus_handle(cx));
 8357                    editor.edit_breakpoint_at_anchor(
 8358                        position,
 8359                        breakpoint.as_ref().clone(),
 8360                        edit_action,
 8361                        cx,
 8362                    );
 8363                }
 8364            }))
 8365            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8366                editor.set_breakpoint_context_menu(
 8367                    row,
 8368                    Some(position),
 8369                    event.position(),
 8370                    window,
 8371                    cx,
 8372                );
 8373            }))
 8374            .tooltip(move |_window, cx| {
 8375                Tooltip::with_meta_in(
 8376                    primary_action_text,
 8377                    Some(&ToggleBreakpoint),
 8378                    meta.clone(),
 8379                    &focus_handle,
 8380                    cx,
 8381                )
 8382            })
 8383    }
 8384
 8385    fn build_tasks_context(
 8386        project: &Entity<Project>,
 8387        buffer: &Entity<Buffer>,
 8388        buffer_row: u32,
 8389        tasks: &Arc<RunnableTasks>,
 8390        cx: &mut Context<Self>,
 8391    ) -> Task<Option<task::TaskContext>> {
 8392        let position = Point::new(buffer_row, tasks.column);
 8393        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8394        let location = Location {
 8395            buffer: buffer.clone(),
 8396            range: range_start..range_start,
 8397        };
 8398        // Fill in the environmental variables from the tree-sitter captures
 8399        let mut captured_task_variables = TaskVariables::default();
 8400        for (capture_name, value) in tasks.extra_variables.clone() {
 8401            captured_task_variables.insert(
 8402                task::VariableName::Custom(capture_name.into()),
 8403                value.clone(),
 8404            );
 8405        }
 8406        project.update(cx, |project, cx| {
 8407            project.task_store().update(cx, |task_store, cx| {
 8408                task_store.task_context_for_location(captured_task_variables, location, cx)
 8409            })
 8410        })
 8411    }
 8412
 8413    pub fn spawn_nearest_task(
 8414        &mut self,
 8415        action: &SpawnNearestTask,
 8416        window: &mut Window,
 8417        cx: &mut Context<Self>,
 8418    ) {
 8419        let Some((workspace, _)) = self.workspace.clone() else {
 8420            return;
 8421        };
 8422        let Some(project) = self.project.clone() else {
 8423            return;
 8424        };
 8425
 8426        // Try to find a closest, enclosing node using tree-sitter that has a task
 8427        let Some((buffer, buffer_row, tasks)) = self
 8428            .find_enclosing_node_task(cx)
 8429            // Or find the task that's closest in row-distance.
 8430            .or_else(|| self.find_closest_task(cx))
 8431        else {
 8432            return;
 8433        };
 8434
 8435        let reveal_strategy = action.reveal;
 8436        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8437        cx.spawn_in(window, async move |_, cx| {
 8438            let context = task_context.await?;
 8439            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8440
 8441            let resolved = &mut resolved_task.resolved;
 8442            resolved.reveal = reveal_strategy;
 8443
 8444            workspace
 8445                .update_in(cx, |workspace, window, cx| {
 8446                    workspace.schedule_resolved_task(
 8447                        task_source_kind,
 8448                        resolved_task,
 8449                        false,
 8450                        window,
 8451                        cx,
 8452                    );
 8453                })
 8454                .ok()
 8455        })
 8456        .detach();
 8457    }
 8458
 8459    fn find_closest_task(
 8460        &mut self,
 8461        cx: &mut Context<Self>,
 8462    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8463        let cursor_row = self
 8464            .selections
 8465            .newest_adjusted(&self.display_snapshot(cx))
 8466            .head()
 8467            .row;
 8468
 8469        let ((buffer_id, row), tasks) = self
 8470            .tasks
 8471            .iter()
 8472            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8473
 8474        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8475        let tasks = Arc::new(tasks.to_owned());
 8476        Some((buffer, *row, tasks))
 8477    }
 8478
 8479    fn find_enclosing_node_task(
 8480        &mut self,
 8481        cx: &mut Context<Self>,
 8482    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8483        let snapshot = self.buffer.read(cx).snapshot(cx);
 8484        let offset = self
 8485            .selections
 8486            .newest::<usize>(&self.display_snapshot(cx))
 8487            .head();
 8488        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8489        let buffer_id = excerpt.buffer().remote_id();
 8490
 8491        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8492        let mut cursor = layer.node().walk();
 8493
 8494        while cursor.goto_first_child_for_byte(offset).is_some() {
 8495            if cursor.node().end_byte() == offset {
 8496                cursor.goto_next_sibling();
 8497            }
 8498        }
 8499
 8500        // Ascend to the smallest ancestor that contains the range and has a task.
 8501        loop {
 8502            let node = cursor.node();
 8503            let node_range = node.byte_range();
 8504            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8505
 8506            // Check if this node contains our offset
 8507            if node_range.start <= offset && node_range.end >= offset {
 8508                // If it contains offset, check for task
 8509                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8510                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8511                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8512                }
 8513            }
 8514
 8515            if !cursor.goto_parent() {
 8516                break;
 8517            }
 8518        }
 8519        None
 8520    }
 8521
 8522    fn render_run_indicator(
 8523        &self,
 8524        _style: &EditorStyle,
 8525        is_active: bool,
 8526        row: DisplayRow,
 8527        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8528        cx: &mut Context<Self>,
 8529    ) -> IconButton {
 8530        let color = Color::Muted;
 8531        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8532
 8533        IconButton::new(
 8534            ("run_indicator", row.0 as usize),
 8535            ui::IconName::PlayOutlined,
 8536        )
 8537        .shape(ui::IconButtonShape::Square)
 8538        .icon_size(IconSize::XSmall)
 8539        .icon_color(color)
 8540        .toggle_state(is_active)
 8541        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8542            let quick_launch = match e {
 8543                ClickEvent::Keyboard(_) => true,
 8544                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8545            };
 8546
 8547            window.focus(&editor.focus_handle(cx));
 8548            editor.toggle_code_actions(
 8549                &ToggleCodeActions {
 8550                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8551                    quick_launch,
 8552                },
 8553                window,
 8554                cx,
 8555            );
 8556        }))
 8557        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8558            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8559        }))
 8560    }
 8561
 8562    pub fn context_menu_visible(&self) -> bool {
 8563        !self.edit_prediction_preview_is_active()
 8564            && self
 8565                .context_menu
 8566                .borrow()
 8567                .as_ref()
 8568                .is_some_and(|menu| menu.visible())
 8569    }
 8570
 8571    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8572        self.context_menu
 8573            .borrow()
 8574            .as_ref()
 8575            .map(|menu| menu.origin())
 8576    }
 8577
 8578    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8579        self.context_menu_options = Some(options);
 8580    }
 8581
 8582    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8583    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8584
 8585    fn render_edit_prediction_popover(
 8586        &mut self,
 8587        text_bounds: &Bounds<Pixels>,
 8588        content_origin: gpui::Point<Pixels>,
 8589        right_margin: Pixels,
 8590        editor_snapshot: &EditorSnapshot,
 8591        visible_row_range: Range<DisplayRow>,
 8592        scroll_top: ScrollOffset,
 8593        scroll_bottom: ScrollOffset,
 8594        line_layouts: &[LineWithInvisibles],
 8595        line_height: Pixels,
 8596        scroll_position: gpui::Point<ScrollOffset>,
 8597        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8598        newest_selection_head: Option<DisplayPoint>,
 8599        editor_width: Pixels,
 8600        style: &EditorStyle,
 8601        window: &mut Window,
 8602        cx: &mut App,
 8603    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8604        if self.mode().is_minimap() {
 8605            return None;
 8606        }
 8607        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8608
 8609        if self.edit_prediction_visible_in_cursor_popover(true) {
 8610            return None;
 8611        }
 8612
 8613        match &active_edit_prediction.completion {
 8614            EditPrediction::MoveWithin { target, .. } => {
 8615                let target_display_point = target.to_display_point(editor_snapshot);
 8616
 8617                if self.edit_prediction_requires_modifier() {
 8618                    if !self.edit_prediction_preview_is_active() {
 8619                        return None;
 8620                    }
 8621
 8622                    self.render_edit_prediction_modifier_jump_popover(
 8623                        text_bounds,
 8624                        content_origin,
 8625                        visible_row_range,
 8626                        line_layouts,
 8627                        line_height,
 8628                        scroll_pixel_position,
 8629                        newest_selection_head,
 8630                        target_display_point,
 8631                        window,
 8632                        cx,
 8633                    )
 8634                } else {
 8635                    self.render_edit_prediction_eager_jump_popover(
 8636                        text_bounds,
 8637                        content_origin,
 8638                        editor_snapshot,
 8639                        visible_row_range,
 8640                        scroll_top,
 8641                        scroll_bottom,
 8642                        line_height,
 8643                        scroll_pixel_position,
 8644                        target_display_point,
 8645                        editor_width,
 8646                        window,
 8647                        cx,
 8648                    )
 8649                }
 8650            }
 8651            EditPrediction::Edit {
 8652                display_mode: EditDisplayMode::Inline,
 8653                ..
 8654            } => None,
 8655            EditPrediction::Edit {
 8656                display_mode: EditDisplayMode::TabAccept,
 8657                edits,
 8658                ..
 8659            } => {
 8660                let range = &edits.first()?.0;
 8661                let target_display_point = range.end.to_display_point(editor_snapshot);
 8662
 8663                self.render_edit_prediction_end_of_line_popover(
 8664                    "Accept",
 8665                    editor_snapshot,
 8666                    visible_row_range,
 8667                    target_display_point,
 8668                    line_height,
 8669                    scroll_pixel_position,
 8670                    content_origin,
 8671                    editor_width,
 8672                    window,
 8673                    cx,
 8674                )
 8675            }
 8676            EditPrediction::Edit {
 8677                edits,
 8678                edit_preview,
 8679                display_mode: EditDisplayMode::DiffPopover,
 8680                snapshot,
 8681            } => self.render_edit_prediction_diff_popover(
 8682                text_bounds,
 8683                content_origin,
 8684                right_margin,
 8685                editor_snapshot,
 8686                visible_row_range,
 8687                line_layouts,
 8688                line_height,
 8689                scroll_position,
 8690                scroll_pixel_position,
 8691                newest_selection_head,
 8692                editor_width,
 8693                style,
 8694                edits,
 8695                edit_preview,
 8696                snapshot,
 8697                window,
 8698                cx,
 8699            ),
 8700            EditPrediction::MoveOutside { snapshot, .. } => {
 8701                let file_name = snapshot
 8702                    .file()
 8703                    .map(|file| file.file_name(cx))
 8704                    .unwrap_or("untitled");
 8705                let mut element = self
 8706                    .render_edit_prediction_line_popover(
 8707                        format!("Jump to {file_name}"),
 8708                        Some(IconName::ZedPredict),
 8709                        window,
 8710                        cx,
 8711                    )
 8712                    .into_any();
 8713
 8714                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8715                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8716                let origin_y = text_bounds.size.height - size.height - px(30.);
 8717                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8718                element.prepaint_at(origin, window, cx);
 8719
 8720                Some((element, origin))
 8721            }
 8722        }
 8723    }
 8724
 8725    fn render_edit_prediction_modifier_jump_popover(
 8726        &mut self,
 8727        text_bounds: &Bounds<Pixels>,
 8728        content_origin: gpui::Point<Pixels>,
 8729        visible_row_range: Range<DisplayRow>,
 8730        line_layouts: &[LineWithInvisibles],
 8731        line_height: Pixels,
 8732        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8733        newest_selection_head: Option<DisplayPoint>,
 8734        target_display_point: DisplayPoint,
 8735        window: &mut Window,
 8736        cx: &mut App,
 8737    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8738        let scrolled_content_origin =
 8739            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8740
 8741        const SCROLL_PADDING_Y: Pixels = px(12.);
 8742
 8743        if target_display_point.row() < visible_row_range.start {
 8744            return self.render_edit_prediction_scroll_popover(
 8745                |_| SCROLL_PADDING_Y,
 8746                IconName::ArrowUp,
 8747                visible_row_range,
 8748                line_layouts,
 8749                newest_selection_head,
 8750                scrolled_content_origin,
 8751                window,
 8752                cx,
 8753            );
 8754        } else if target_display_point.row() >= visible_row_range.end {
 8755            return self.render_edit_prediction_scroll_popover(
 8756                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8757                IconName::ArrowDown,
 8758                visible_row_range,
 8759                line_layouts,
 8760                newest_selection_head,
 8761                scrolled_content_origin,
 8762                window,
 8763                cx,
 8764            );
 8765        }
 8766
 8767        const POLE_WIDTH: Pixels = px(2.);
 8768
 8769        let line_layout =
 8770            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8771        let target_column = target_display_point.column() as usize;
 8772
 8773        let target_x = line_layout.x_for_index(target_column);
 8774        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8775            - scroll_pixel_position.y;
 8776
 8777        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8778
 8779        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8780        border_color.l += 0.001;
 8781
 8782        let mut element = v_flex()
 8783            .items_end()
 8784            .when(flag_on_right, |el| el.items_start())
 8785            .child(if flag_on_right {
 8786                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8787                    .rounded_bl(px(0.))
 8788                    .rounded_tl(px(0.))
 8789                    .border_l_2()
 8790                    .border_color(border_color)
 8791            } else {
 8792                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8793                    .rounded_br(px(0.))
 8794                    .rounded_tr(px(0.))
 8795                    .border_r_2()
 8796                    .border_color(border_color)
 8797            })
 8798            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8799            .into_any();
 8800
 8801        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8802
 8803        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8804            - point(
 8805                if flag_on_right {
 8806                    POLE_WIDTH
 8807                } else {
 8808                    size.width - POLE_WIDTH
 8809                },
 8810                size.height - line_height,
 8811            );
 8812
 8813        origin.x = origin.x.max(content_origin.x);
 8814
 8815        element.prepaint_at(origin, window, cx);
 8816
 8817        Some((element, origin))
 8818    }
 8819
 8820    fn render_edit_prediction_scroll_popover(
 8821        &mut self,
 8822        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8823        scroll_icon: IconName,
 8824        visible_row_range: Range<DisplayRow>,
 8825        line_layouts: &[LineWithInvisibles],
 8826        newest_selection_head: Option<DisplayPoint>,
 8827        scrolled_content_origin: gpui::Point<Pixels>,
 8828        window: &mut Window,
 8829        cx: &mut App,
 8830    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8831        let mut element = self
 8832            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8833            .into_any();
 8834
 8835        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8836
 8837        let cursor = newest_selection_head?;
 8838        let cursor_row_layout =
 8839            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8840        let cursor_column = cursor.column() as usize;
 8841
 8842        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8843
 8844        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8845
 8846        element.prepaint_at(origin, window, cx);
 8847        Some((element, origin))
 8848    }
 8849
 8850    fn render_edit_prediction_eager_jump_popover(
 8851        &mut self,
 8852        text_bounds: &Bounds<Pixels>,
 8853        content_origin: gpui::Point<Pixels>,
 8854        editor_snapshot: &EditorSnapshot,
 8855        visible_row_range: Range<DisplayRow>,
 8856        scroll_top: ScrollOffset,
 8857        scroll_bottom: ScrollOffset,
 8858        line_height: Pixels,
 8859        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8860        target_display_point: DisplayPoint,
 8861        editor_width: Pixels,
 8862        window: &mut Window,
 8863        cx: &mut App,
 8864    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8865        if target_display_point.row().as_f64() < scroll_top {
 8866            let mut element = self
 8867                .render_edit_prediction_line_popover(
 8868                    "Jump to Edit",
 8869                    Some(IconName::ArrowUp),
 8870                    window,
 8871                    cx,
 8872                )
 8873                .into_any();
 8874
 8875            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8876            let offset = point(
 8877                (text_bounds.size.width - size.width) / 2.,
 8878                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8879            );
 8880
 8881            let origin = text_bounds.origin + offset;
 8882            element.prepaint_at(origin, window, cx);
 8883            Some((element, origin))
 8884        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 8885            let mut element = self
 8886                .render_edit_prediction_line_popover(
 8887                    "Jump to Edit",
 8888                    Some(IconName::ArrowDown),
 8889                    window,
 8890                    cx,
 8891                )
 8892                .into_any();
 8893
 8894            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8895            let offset = point(
 8896                (text_bounds.size.width - size.width) / 2.,
 8897                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8898            );
 8899
 8900            let origin = text_bounds.origin + offset;
 8901            element.prepaint_at(origin, window, cx);
 8902            Some((element, origin))
 8903        } else {
 8904            self.render_edit_prediction_end_of_line_popover(
 8905                "Jump to Edit",
 8906                editor_snapshot,
 8907                visible_row_range,
 8908                target_display_point,
 8909                line_height,
 8910                scroll_pixel_position,
 8911                content_origin,
 8912                editor_width,
 8913                window,
 8914                cx,
 8915            )
 8916        }
 8917    }
 8918
 8919    fn render_edit_prediction_end_of_line_popover(
 8920        self: &mut Editor,
 8921        label: &'static str,
 8922        editor_snapshot: &EditorSnapshot,
 8923        visible_row_range: Range<DisplayRow>,
 8924        target_display_point: DisplayPoint,
 8925        line_height: Pixels,
 8926        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8927        content_origin: gpui::Point<Pixels>,
 8928        editor_width: Pixels,
 8929        window: &mut Window,
 8930        cx: &mut App,
 8931    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8932        let target_line_end = DisplayPoint::new(
 8933            target_display_point.row(),
 8934            editor_snapshot.line_len(target_display_point.row()),
 8935        );
 8936
 8937        let mut element = self
 8938            .render_edit_prediction_line_popover(label, None, window, cx)
 8939            .into_any();
 8940
 8941        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8942
 8943        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8944
 8945        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 8946        let mut origin = start_point
 8947            + line_origin
 8948            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8949        origin.x = origin.x.max(content_origin.x);
 8950
 8951        let max_x = content_origin.x + editor_width - size.width;
 8952
 8953        if origin.x > max_x {
 8954            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8955
 8956            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8957                origin.y += offset;
 8958                IconName::ArrowUp
 8959            } else {
 8960                origin.y -= offset;
 8961                IconName::ArrowDown
 8962            };
 8963
 8964            element = self
 8965                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 8966                .into_any();
 8967
 8968            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8969
 8970            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8971        }
 8972
 8973        element.prepaint_at(origin, window, cx);
 8974        Some((element, origin))
 8975    }
 8976
 8977    fn render_edit_prediction_diff_popover(
 8978        self: &Editor,
 8979        text_bounds: &Bounds<Pixels>,
 8980        content_origin: gpui::Point<Pixels>,
 8981        right_margin: Pixels,
 8982        editor_snapshot: &EditorSnapshot,
 8983        visible_row_range: Range<DisplayRow>,
 8984        line_layouts: &[LineWithInvisibles],
 8985        line_height: Pixels,
 8986        scroll_position: gpui::Point<ScrollOffset>,
 8987        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8988        newest_selection_head: Option<DisplayPoint>,
 8989        editor_width: Pixels,
 8990        style: &EditorStyle,
 8991        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 8992        edit_preview: &Option<language::EditPreview>,
 8993        snapshot: &language::BufferSnapshot,
 8994        window: &mut Window,
 8995        cx: &mut App,
 8996    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8997        let edit_start = edits
 8998            .first()
 8999            .unwrap()
 9000            .0
 9001            .start
 9002            .to_display_point(editor_snapshot);
 9003        let edit_end = edits
 9004            .last()
 9005            .unwrap()
 9006            .0
 9007            .end
 9008            .to_display_point(editor_snapshot);
 9009
 9010        let is_visible = visible_row_range.contains(&edit_start.row())
 9011            || visible_row_range.contains(&edit_end.row());
 9012        if !is_visible {
 9013            return None;
 9014        }
 9015
 9016        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9017            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9018        } else {
 9019            // Fallback for providers without edit_preview
 9020            crate::edit_prediction_fallback_text(edits, cx)
 9021        };
 9022
 9023        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9024        let line_count = highlighted_edits.text.lines().count();
 9025
 9026        const BORDER_WIDTH: Pixels = px(1.);
 9027
 9028        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9029        let has_keybind = keybind.is_some();
 9030
 9031        let mut element = h_flex()
 9032            .items_start()
 9033            .child(
 9034                h_flex()
 9035                    .bg(cx.theme().colors().editor_background)
 9036                    .border(BORDER_WIDTH)
 9037                    .shadow_xs()
 9038                    .border_color(cx.theme().colors().border)
 9039                    .rounded_l_lg()
 9040                    .when(line_count > 1, |el| el.rounded_br_lg())
 9041                    .pr_1()
 9042                    .child(styled_text),
 9043            )
 9044            .child(
 9045                h_flex()
 9046                    .h(line_height + BORDER_WIDTH * 2.)
 9047                    .px_1p5()
 9048                    .gap_1()
 9049                    // Workaround: For some reason, there's a gap if we don't do this
 9050                    .ml(-BORDER_WIDTH)
 9051                    .shadow(vec![gpui::BoxShadow {
 9052                        color: gpui::black().opacity(0.05),
 9053                        offset: point(px(1.), px(1.)),
 9054                        blur_radius: px(2.),
 9055                        spread_radius: px(0.),
 9056                    }])
 9057                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9058                    .border(BORDER_WIDTH)
 9059                    .border_color(cx.theme().colors().border)
 9060                    .rounded_r_lg()
 9061                    .id("edit_prediction_diff_popover_keybind")
 9062                    .when(!has_keybind, |el| {
 9063                        let status_colors = cx.theme().status();
 9064
 9065                        el.bg(status_colors.error_background)
 9066                            .border_color(status_colors.error.opacity(0.6))
 9067                            .child(Icon::new(IconName::Info).color(Color::Error))
 9068                            .cursor_default()
 9069                            .hoverable_tooltip(move |_window, cx| {
 9070                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9071                            })
 9072                    })
 9073                    .children(keybind),
 9074            )
 9075            .into_any();
 9076
 9077        let longest_row =
 9078            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9079        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9080            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9081        } else {
 9082            layout_line(
 9083                longest_row,
 9084                editor_snapshot,
 9085                style,
 9086                editor_width,
 9087                |_| false,
 9088                window,
 9089                cx,
 9090            )
 9091            .width
 9092        };
 9093
 9094        let viewport_bounds =
 9095            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9096                right: -right_margin,
 9097                ..Default::default()
 9098            });
 9099
 9100        let x_after_longest = Pixels::from(
 9101            ScrollPixelOffset::from(
 9102                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9103            ) - scroll_pixel_position.x,
 9104        );
 9105
 9106        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9107
 9108        // Fully visible if it can be displayed within the window (allow overlapping other
 9109        // panes). However, this is only allowed if the popover starts within text_bounds.
 9110        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9111            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9112
 9113        let mut origin = if can_position_to_the_right {
 9114            point(
 9115                x_after_longest,
 9116                text_bounds.origin.y
 9117                    + Pixels::from(
 9118                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9119                            - scroll_pixel_position.y,
 9120                    ),
 9121            )
 9122        } else {
 9123            let cursor_row = newest_selection_head.map(|head| head.row());
 9124            let above_edit = edit_start
 9125                .row()
 9126                .0
 9127                .checked_sub(line_count as u32)
 9128                .map(DisplayRow);
 9129            let below_edit = Some(edit_end.row() + 1);
 9130            let above_cursor =
 9131                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9132            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9133
 9134            // Place the edit popover adjacent to the edit if there is a location
 9135            // available that is onscreen and does not obscure the cursor. Otherwise,
 9136            // place it adjacent to the cursor.
 9137            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9138                .into_iter()
 9139                .flatten()
 9140                .find(|&start_row| {
 9141                    let end_row = start_row + line_count as u32;
 9142                    visible_row_range.contains(&start_row)
 9143                        && visible_row_range.contains(&end_row)
 9144                        && cursor_row
 9145                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9146                })?;
 9147
 9148            content_origin
 9149                + point(
 9150                    Pixels::from(-scroll_pixel_position.x),
 9151                    Pixels::from(
 9152                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9153                    ),
 9154                )
 9155        };
 9156
 9157        origin.x -= BORDER_WIDTH;
 9158
 9159        window.defer_draw(element, origin, 1);
 9160
 9161        // Do not return an element, since it will already be drawn due to defer_draw.
 9162        None
 9163    }
 9164
 9165    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9166        px(30.)
 9167    }
 9168
 9169    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9170        if self.read_only(cx) {
 9171            cx.theme().players().read_only()
 9172        } else {
 9173            self.style.as_ref().unwrap().local_player
 9174        }
 9175    }
 9176
 9177    fn render_edit_prediction_accept_keybind(
 9178        &self,
 9179        window: &mut Window,
 9180        cx: &mut App,
 9181    ) -> Option<AnyElement> {
 9182        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9183        let accept_keystroke = accept_binding.keystroke()?;
 9184
 9185        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9186
 9187        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9188            Color::Accent
 9189        } else {
 9190            Color::Muted
 9191        };
 9192
 9193        h_flex()
 9194            .px_0p5()
 9195            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9196            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9197            .text_size(TextSize::XSmall.rems(cx))
 9198            .child(h_flex().children(ui::render_modifiers(
 9199                accept_keystroke.modifiers(),
 9200                PlatformStyle::platform(),
 9201                Some(modifiers_color),
 9202                Some(IconSize::XSmall.rems().into()),
 9203                true,
 9204            )))
 9205            .when(is_platform_style_mac, |parent| {
 9206                parent.child(accept_keystroke.key().to_string())
 9207            })
 9208            .when(!is_platform_style_mac, |parent| {
 9209                parent.child(
 9210                    Key::new(
 9211                        util::capitalize(accept_keystroke.key()),
 9212                        Some(Color::Default),
 9213                    )
 9214                    .size(Some(IconSize::XSmall.rems().into())),
 9215                )
 9216            })
 9217            .into_any()
 9218            .into()
 9219    }
 9220
 9221    fn render_edit_prediction_line_popover(
 9222        &self,
 9223        label: impl Into<SharedString>,
 9224        icon: Option<IconName>,
 9225        window: &mut Window,
 9226        cx: &mut App,
 9227    ) -> Stateful<Div> {
 9228        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9229
 9230        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9231        let has_keybind = keybind.is_some();
 9232
 9233        h_flex()
 9234            .id("ep-line-popover")
 9235            .py_0p5()
 9236            .pl_1()
 9237            .pr(padding_right)
 9238            .gap_1()
 9239            .rounded_md()
 9240            .border_1()
 9241            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9242            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9243            .shadow_xs()
 9244            .when(!has_keybind, |el| {
 9245                let status_colors = cx.theme().status();
 9246
 9247                el.bg(status_colors.error_background)
 9248                    .border_color(status_colors.error.opacity(0.6))
 9249                    .pl_2()
 9250                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9251                    .cursor_default()
 9252                    .hoverable_tooltip(move |_window, cx| {
 9253                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9254                    })
 9255            })
 9256            .children(keybind)
 9257            .child(
 9258                Label::new(label)
 9259                    .size(LabelSize::Small)
 9260                    .when(!has_keybind, |el| {
 9261                        el.color(cx.theme().status().error.into()).strikethrough()
 9262                    }),
 9263            )
 9264            .when(!has_keybind, |el| {
 9265                el.child(
 9266                    h_flex().ml_1().child(
 9267                        Icon::new(IconName::Info)
 9268                            .size(IconSize::Small)
 9269                            .color(cx.theme().status().error.into()),
 9270                    ),
 9271                )
 9272            })
 9273            .when_some(icon, |element, icon| {
 9274                element.child(
 9275                    div()
 9276                        .mt(px(1.5))
 9277                        .child(Icon::new(icon).size(IconSize::Small)),
 9278                )
 9279            })
 9280    }
 9281
 9282    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9283        let accent_color = cx.theme().colors().text_accent;
 9284        let editor_bg_color = cx.theme().colors().editor_background;
 9285        editor_bg_color.blend(accent_color.opacity(0.1))
 9286    }
 9287
 9288    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9289        let accent_color = cx.theme().colors().text_accent;
 9290        let editor_bg_color = cx.theme().colors().editor_background;
 9291        editor_bg_color.blend(accent_color.opacity(0.6))
 9292    }
 9293    fn get_prediction_provider_icon_name(
 9294        provider: &Option<RegisteredEditPredictionProvider>,
 9295    ) -> IconName {
 9296        match provider {
 9297            Some(provider) => match provider.provider.name() {
 9298                "copilot" => IconName::Copilot,
 9299                "supermaven" => IconName::Supermaven,
 9300                _ => IconName::ZedPredict,
 9301            },
 9302            None => IconName::ZedPredict,
 9303        }
 9304    }
 9305
 9306    fn render_edit_prediction_cursor_popover(
 9307        &self,
 9308        min_width: Pixels,
 9309        max_width: Pixels,
 9310        cursor_point: Point,
 9311        style: &EditorStyle,
 9312        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9313        _window: &Window,
 9314        cx: &mut Context<Editor>,
 9315    ) -> Option<AnyElement> {
 9316        let provider = self.edit_prediction_provider.as_ref()?;
 9317        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9318
 9319        let is_refreshing = provider.provider.is_refreshing(cx);
 9320
 9321        fn pending_completion_container(icon: IconName) -> Div {
 9322            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9323        }
 9324
 9325        let completion = match &self.active_edit_prediction {
 9326            Some(prediction) => {
 9327                if !self.has_visible_completions_menu() {
 9328                    const RADIUS: Pixels = px(6.);
 9329                    const BORDER_WIDTH: Pixels = px(1.);
 9330
 9331                    return Some(
 9332                        h_flex()
 9333                            .elevation_2(cx)
 9334                            .border(BORDER_WIDTH)
 9335                            .border_color(cx.theme().colors().border)
 9336                            .when(accept_keystroke.is_none(), |el| {
 9337                                el.border_color(cx.theme().status().error)
 9338                            })
 9339                            .rounded(RADIUS)
 9340                            .rounded_tl(px(0.))
 9341                            .overflow_hidden()
 9342                            .child(div().px_1p5().child(match &prediction.completion {
 9343                                EditPrediction::MoveWithin { target, snapshot } => {
 9344                                    use text::ToPoint as _;
 9345                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9346                                    {
 9347                                        Icon::new(IconName::ZedPredictDown)
 9348                                    } else {
 9349                                        Icon::new(IconName::ZedPredictUp)
 9350                                    }
 9351                                }
 9352                                EditPrediction::MoveOutside { .. } => {
 9353                                    // TODO [zeta2] custom icon for external jump?
 9354                                    Icon::new(provider_icon)
 9355                                }
 9356                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9357                            }))
 9358                            .child(
 9359                                h_flex()
 9360                                    .gap_1()
 9361                                    .py_1()
 9362                                    .px_2()
 9363                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9364                                    .border_l_1()
 9365                                    .border_color(cx.theme().colors().border)
 9366                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9367                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9368                                        el.child(
 9369                                            Label::new("Hold")
 9370                                                .size(LabelSize::Small)
 9371                                                .when(accept_keystroke.is_none(), |el| {
 9372                                                    el.strikethrough()
 9373                                                })
 9374                                                .line_height_style(LineHeightStyle::UiLabel),
 9375                                        )
 9376                                    })
 9377                                    .id("edit_prediction_cursor_popover_keybind")
 9378                                    .when(accept_keystroke.is_none(), |el| {
 9379                                        let status_colors = cx.theme().status();
 9380
 9381                                        el.bg(status_colors.error_background)
 9382                                            .border_color(status_colors.error.opacity(0.6))
 9383                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9384                                            .cursor_default()
 9385                                            .hoverable_tooltip(move |_window, cx| {
 9386                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9387                                                    .into()
 9388                                            })
 9389                                    })
 9390                                    .when_some(
 9391                                        accept_keystroke.as_ref(),
 9392                                        |el, accept_keystroke| {
 9393                                            el.child(h_flex().children(ui::render_modifiers(
 9394                                                accept_keystroke.modifiers(),
 9395                                                PlatformStyle::platform(),
 9396                                                Some(Color::Default),
 9397                                                Some(IconSize::XSmall.rems().into()),
 9398                                                false,
 9399                                            )))
 9400                                        },
 9401                                    ),
 9402                            )
 9403                            .into_any(),
 9404                    );
 9405                }
 9406
 9407                self.render_edit_prediction_cursor_popover_preview(
 9408                    prediction,
 9409                    cursor_point,
 9410                    style,
 9411                    cx,
 9412                )?
 9413            }
 9414
 9415            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9416                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9417                    stale_completion,
 9418                    cursor_point,
 9419                    style,
 9420                    cx,
 9421                )?,
 9422
 9423                None => pending_completion_container(provider_icon)
 9424                    .child(Label::new("...").size(LabelSize::Small)),
 9425            },
 9426
 9427            None => pending_completion_container(provider_icon)
 9428                .child(Label::new("...").size(LabelSize::Small)),
 9429        };
 9430
 9431        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9432            completion
 9433                .with_animation(
 9434                    "loading-completion",
 9435                    Animation::new(Duration::from_secs(2))
 9436                        .repeat()
 9437                        .with_easing(pulsating_between(0.4, 0.8)),
 9438                    |label, delta| label.opacity(delta),
 9439                )
 9440                .into_any_element()
 9441        } else {
 9442            completion.into_any_element()
 9443        };
 9444
 9445        let has_completion = self.active_edit_prediction.is_some();
 9446
 9447        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9448        Some(
 9449            h_flex()
 9450                .min_w(min_width)
 9451                .max_w(max_width)
 9452                .flex_1()
 9453                .elevation_2(cx)
 9454                .border_color(cx.theme().colors().border)
 9455                .child(
 9456                    div()
 9457                        .flex_1()
 9458                        .py_1()
 9459                        .px_2()
 9460                        .overflow_hidden()
 9461                        .child(completion),
 9462                )
 9463                .when_some(accept_keystroke, |el, accept_keystroke| {
 9464                    if !accept_keystroke.modifiers().modified() {
 9465                        return el;
 9466                    }
 9467
 9468                    el.child(
 9469                        h_flex()
 9470                            .h_full()
 9471                            .border_l_1()
 9472                            .rounded_r_lg()
 9473                            .border_color(cx.theme().colors().border)
 9474                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9475                            .gap_1()
 9476                            .py_1()
 9477                            .px_2()
 9478                            .child(
 9479                                h_flex()
 9480                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9481                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9482                                    .child(h_flex().children(ui::render_modifiers(
 9483                                        accept_keystroke.modifiers(),
 9484                                        PlatformStyle::platform(),
 9485                                        Some(if !has_completion {
 9486                                            Color::Muted
 9487                                        } else {
 9488                                            Color::Default
 9489                                        }),
 9490                                        None,
 9491                                        false,
 9492                                    ))),
 9493                            )
 9494                            .child(Label::new("Preview").into_any_element())
 9495                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9496                    )
 9497                })
 9498                .into_any(),
 9499        )
 9500    }
 9501
 9502    fn render_edit_prediction_cursor_popover_preview(
 9503        &self,
 9504        completion: &EditPredictionState,
 9505        cursor_point: Point,
 9506        style: &EditorStyle,
 9507        cx: &mut Context<Editor>,
 9508    ) -> Option<Div> {
 9509        use text::ToPoint as _;
 9510
 9511        fn render_relative_row_jump(
 9512            prefix: impl Into<String>,
 9513            current_row: u32,
 9514            target_row: u32,
 9515        ) -> Div {
 9516            let (row_diff, arrow) = if target_row < current_row {
 9517                (current_row - target_row, IconName::ArrowUp)
 9518            } else {
 9519                (target_row - current_row, IconName::ArrowDown)
 9520            };
 9521
 9522            h_flex()
 9523                .child(
 9524                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9525                        .color(Color::Muted)
 9526                        .size(LabelSize::Small),
 9527                )
 9528                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9529        }
 9530
 9531        let supports_jump = self
 9532            .edit_prediction_provider
 9533            .as_ref()
 9534            .map(|provider| provider.provider.supports_jump_to_edit())
 9535            .unwrap_or(true);
 9536
 9537        match &completion.completion {
 9538            EditPrediction::MoveWithin {
 9539                target, snapshot, ..
 9540            } => {
 9541                if !supports_jump {
 9542                    return None;
 9543                }
 9544
 9545                Some(
 9546                    h_flex()
 9547                        .px_2()
 9548                        .gap_2()
 9549                        .flex_1()
 9550                        .child(
 9551                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9552                                Icon::new(IconName::ZedPredictDown)
 9553                            } else {
 9554                                Icon::new(IconName::ZedPredictUp)
 9555                            },
 9556                        )
 9557                        .child(Label::new("Jump to Edit")),
 9558                )
 9559            }
 9560            EditPrediction::MoveOutside { snapshot, .. } => {
 9561                let file_name = snapshot
 9562                    .file()
 9563                    .map(|file| file.file_name(cx))
 9564                    .unwrap_or("untitled");
 9565                Some(
 9566                    h_flex()
 9567                        .px_2()
 9568                        .gap_2()
 9569                        .flex_1()
 9570                        .child(Icon::new(IconName::ZedPredict))
 9571                        .child(Label::new(format!("Jump to {file_name}"))),
 9572                )
 9573            }
 9574            EditPrediction::Edit {
 9575                edits,
 9576                edit_preview,
 9577                snapshot,
 9578                display_mode: _,
 9579            } => {
 9580                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9581
 9582                let (highlighted_edits, has_more_lines) =
 9583                    if let Some(edit_preview) = edit_preview.as_ref() {
 9584                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9585                            .first_line_preview()
 9586                    } else {
 9587                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9588                    };
 9589
 9590                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9591                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9592
 9593                let preview = h_flex()
 9594                    .gap_1()
 9595                    .min_w_16()
 9596                    .child(styled_text)
 9597                    .when(has_more_lines, |parent| parent.child(""));
 9598
 9599                let left = if supports_jump && first_edit_row != cursor_point.row {
 9600                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9601                        .into_any_element()
 9602                } else {
 9603                    let icon_name =
 9604                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9605                    Icon::new(icon_name).into_any_element()
 9606                };
 9607
 9608                Some(
 9609                    h_flex()
 9610                        .h_full()
 9611                        .flex_1()
 9612                        .gap_2()
 9613                        .pr_1()
 9614                        .overflow_x_hidden()
 9615                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9616                        .child(left)
 9617                        .child(preview),
 9618                )
 9619            }
 9620        }
 9621    }
 9622
 9623    pub fn render_context_menu(
 9624        &self,
 9625        style: &EditorStyle,
 9626        max_height_in_lines: u32,
 9627        window: &mut Window,
 9628        cx: &mut Context<Editor>,
 9629    ) -> Option<AnyElement> {
 9630        let menu = self.context_menu.borrow();
 9631        let menu = menu.as_ref()?;
 9632        if !menu.visible() {
 9633            return None;
 9634        };
 9635        Some(menu.render(style, max_height_in_lines, window, cx))
 9636    }
 9637
 9638    fn render_context_menu_aside(
 9639        &mut self,
 9640        max_size: Size<Pixels>,
 9641        window: &mut Window,
 9642        cx: &mut Context<Editor>,
 9643    ) -> Option<AnyElement> {
 9644        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9645            if menu.visible() {
 9646                menu.render_aside(max_size, window, cx)
 9647            } else {
 9648                None
 9649            }
 9650        })
 9651    }
 9652
 9653    fn hide_context_menu(
 9654        &mut self,
 9655        window: &mut Window,
 9656        cx: &mut Context<Self>,
 9657    ) -> Option<CodeContextMenu> {
 9658        cx.notify();
 9659        self.completion_tasks.clear();
 9660        let context_menu = self.context_menu.borrow_mut().take();
 9661        self.stale_edit_prediction_in_menu.take();
 9662        self.update_visible_edit_prediction(window, cx);
 9663        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9664            && let Some(completion_provider) = &self.completion_provider
 9665        {
 9666            completion_provider.selection_changed(None, window, cx);
 9667        }
 9668        context_menu
 9669    }
 9670
 9671    fn show_snippet_choices(
 9672        &mut self,
 9673        choices: &Vec<String>,
 9674        selection: Range<Anchor>,
 9675        cx: &mut Context<Self>,
 9676    ) {
 9677        let Some((_, buffer, _)) = self
 9678            .buffer()
 9679            .read(cx)
 9680            .excerpt_containing(selection.start, cx)
 9681        else {
 9682            return;
 9683        };
 9684        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9685        else {
 9686            return;
 9687        };
 9688        if buffer != end_buffer {
 9689            log::error!("expected anchor range to have matching buffer IDs");
 9690            return;
 9691        }
 9692
 9693        let id = post_inc(&mut self.next_completion_id);
 9694        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9695        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9696            CompletionsMenu::new_snippet_choices(
 9697                id,
 9698                true,
 9699                choices,
 9700                selection,
 9701                buffer,
 9702                snippet_sort_order,
 9703            ),
 9704        ));
 9705    }
 9706
 9707    pub fn insert_snippet(
 9708        &mut self,
 9709        insertion_ranges: &[Range<usize>],
 9710        snippet: Snippet,
 9711        window: &mut Window,
 9712        cx: &mut Context<Self>,
 9713    ) -> Result<()> {
 9714        struct Tabstop<T> {
 9715            is_end_tabstop: bool,
 9716            ranges: Vec<Range<T>>,
 9717            choices: Option<Vec<String>>,
 9718        }
 9719
 9720        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9721            let snippet_text: Arc<str> = snippet.text.clone().into();
 9722            let edits = insertion_ranges
 9723                .iter()
 9724                .cloned()
 9725                .map(|range| (range, snippet_text.clone()));
 9726            let autoindent_mode = AutoindentMode::Block {
 9727                original_indent_columns: Vec::new(),
 9728            };
 9729            buffer.edit(edits, Some(autoindent_mode), cx);
 9730
 9731            let snapshot = &*buffer.read(cx);
 9732            let snippet = &snippet;
 9733            snippet
 9734                .tabstops
 9735                .iter()
 9736                .map(|tabstop| {
 9737                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9738                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9739                    });
 9740                    let mut tabstop_ranges = tabstop
 9741                        .ranges
 9742                        .iter()
 9743                        .flat_map(|tabstop_range| {
 9744                            let mut delta = 0_isize;
 9745                            insertion_ranges.iter().map(move |insertion_range| {
 9746                                let insertion_start = insertion_range.start as isize + delta;
 9747                                delta +=
 9748                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9749
 9750                                let start = ((insertion_start + tabstop_range.start) as usize)
 9751                                    .min(snapshot.len());
 9752                                let end = ((insertion_start + tabstop_range.end) as usize)
 9753                                    .min(snapshot.len());
 9754                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9755                            })
 9756                        })
 9757                        .collect::<Vec<_>>();
 9758                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9759
 9760                    Tabstop {
 9761                        is_end_tabstop,
 9762                        ranges: tabstop_ranges,
 9763                        choices: tabstop.choices.clone(),
 9764                    }
 9765                })
 9766                .collect::<Vec<_>>()
 9767        });
 9768        if let Some(tabstop) = tabstops.first() {
 9769            self.change_selections(Default::default(), window, cx, |s| {
 9770                // Reverse order so that the first range is the newest created selection.
 9771                // Completions will use it and autoscroll will prioritize it.
 9772                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9773            });
 9774
 9775            if let Some(choices) = &tabstop.choices
 9776                && let Some(selection) = tabstop.ranges.first()
 9777            {
 9778                self.show_snippet_choices(choices, selection.clone(), cx)
 9779            }
 9780
 9781            // If we're already at the last tabstop and it's at the end of the snippet,
 9782            // we're done, we don't need to keep the state around.
 9783            if !tabstop.is_end_tabstop {
 9784                let choices = tabstops
 9785                    .iter()
 9786                    .map(|tabstop| tabstop.choices.clone())
 9787                    .collect();
 9788
 9789                let ranges = tabstops
 9790                    .into_iter()
 9791                    .map(|tabstop| tabstop.ranges)
 9792                    .collect::<Vec<_>>();
 9793
 9794                self.snippet_stack.push(SnippetState {
 9795                    active_index: 0,
 9796                    ranges,
 9797                    choices,
 9798                });
 9799            }
 9800
 9801            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9802            if self.autoclose_regions.is_empty() {
 9803                let snapshot = self.buffer.read(cx).snapshot(cx);
 9804                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
 9805                    let selection_head = selection.head();
 9806                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9807                        continue;
 9808                    };
 9809
 9810                    let mut bracket_pair = None;
 9811                    let max_lookup_length = scope
 9812                        .brackets()
 9813                        .map(|(pair, _)| {
 9814                            pair.start
 9815                                .as_str()
 9816                                .chars()
 9817                                .count()
 9818                                .max(pair.end.as_str().chars().count())
 9819                        })
 9820                        .max();
 9821                    if let Some(max_lookup_length) = max_lookup_length {
 9822                        let next_text = snapshot
 9823                            .chars_at(selection_head)
 9824                            .take(max_lookup_length)
 9825                            .collect::<String>();
 9826                        let prev_text = snapshot
 9827                            .reversed_chars_at(selection_head)
 9828                            .take(max_lookup_length)
 9829                            .collect::<String>();
 9830
 9831                        for (pair, enabled) in scope.brackets() {
 9832                            if enabled
 9833                                && pair.close
 9834                                && prev_text.starts_with(pair.start.as_str())
 9835                                && next_text.starts_with(pair.end.as_str())
 9836                            {
 9837                                bracket_pair = Some(pair.clone());
 9838                                break;
 9839                            }
 9840                        }
 9841                    }
 9842
 9843                    if let Some(pair) = bracket_pair {
 9844                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9845                        let autoclose_enabled =
 9846                            self.use_autoclose && snapshot_settings.use_autoclose;
 9847                        if autoclose_enabled {
 9848                            let start = snapshot.anchor_after(selection_head);
 9849                            let end = snapshot.anchor_after(selection_head);
 9850                            self.autoclose_regions.push(AutocloseRegion {
 9851                                selection_id: selection.id,
 9852                                range: start..end,
 9853                                pair,
 9854                            });
 9855                        }
 9856                    }
 9857                }
 9858            }
 9859        }
 9860        Ok(())
 9861    }
 9862
 9863    pub fn move_to_next_snippet_tabstop(
 9864        &mut self,
 9865        window: &mut Window,
 9866        cx: &mut Context<Self>,
 9867    ) -> bool {
 9868        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9869    }
 9870
 9871    pub fn move_to_prev_snippet_tabstop(
 9872        &mut self,
 9873        window: &mut Window,
 9874        cx: &mut Context<Self>,
 9875    ) -> bool {
 9876        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9877    }
 9878
 9879    pub fn move_to_snippet_tabstop(
 9880        &mut self,
 9881        bias: Bias,
 9882        window: &mut Window,
 9883        cx: &mut Context<Self>,
 9884    ) -> bool {
 9885        if let Some(mut snippet) = self.snippet_stack.pop() {
 9886            match bias {
 9887                Bias::Left => {
 9888                    if snippet.active_index > 0 {
 9889                        snippet.active_index -= 1;
 9890                    } else {
 9891                        self.snippet_stack.push(snippet);
 9892                        return false;
 9893                    }
 9894                }
 9895                Bias::Right => {
 9896                    if snippet.active_index + 1 < snippet.ranges.len() {
 9897                        snippet.active_index += 1;
 9898                    } else {
 9899                        self.snippet_stack.push(snippet);
 9900                        return false;
 9901                    }
 9902                }
 9903            }
 9904            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9905                self.change_selections(Default::default(), window, cx, |s| {
 9906                    // Reverse order so that the first range is the newest created selection.
 9907                    // Completions will use it and autoscroll will prioritize it.
 9908                    s.select_ranges(current_ranges.iter().rev().cloned())
 9909                });
 9910
 9911                if let Some(choices) = &snippet.choices[snippet.active_index]
 9912                    && let Some(selection) = current_ranges.first()
 9913                {
 9914                    self.show_snippet_choices(choices, selection.clone(), cx);
 9915                }
 9916
 9917                // If snippet state is not at the last tabstop, push it back on the stack
 9918                if snippet.active_index + 1 < snippet.ranges.len() {
 9919                    self.snippet_stack.push(snippet);
 9920                }
 9921                return true;
 9922            }
 9923        }
 9924
 9925        false
 9926    }
 9927
 9928    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9929        self.transact(window, cx, |this, window, cx| {
 9930            this.select_all(&SelectAll, window, cx);
 9931            this.insert("", window, cx);
 9932        });
 9933    }
 9934
 9935    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9936        if self.read_only(cx) {
 9937            return;
 9938        }
 9939        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9940        self.transact(window, cx, |this, window, cx| {
 9941            this.select_autoclose_pair(window, cx);
 9942
 9943            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9944
 9945            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9946            if !this.linked_edit_ranges.is_empty() {
 9947                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
 9948                let snapshot = this.buffer.read(cx).snapshot(cx);
 9949
 9950                for selection in selections.iter() {
 9951                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9952                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9953                    if selection_start.buffer_id != selection_end.buffer_id {
 9954                        continue;
 9955                    }
 9956                    if let Some(ranges) =
 9957                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9958                    {
 9959                        for (buffer, entries) in ranges {
 9960                            linked_ranges.entry(buffer).or_default().extend(entries);
 9961                        }
 9962                    }
 9963                }
 9964            }
 9965
 9966            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
 9967            for selection in &mut selections {
 9968                if selection.is_empty() {
 9969                    let old_head = selection.head();
 9970                    let mut new_head =
 9971                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9972                            .to_point(&display_map);
 9973                    if let Some((buffer, line_buffer_range)) = display_map
 9974                        .buffer_snapshot()
 9975                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9976                    {
 9977                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9978                        let indent_len = match indent_size.kind {
 9979                            IndentKind::Space => {
 9980                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9981                            }
 9982                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9983                        };
 9984                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9985                            let indent_len = indent_len.get();
 9986                            new_head = cmp::min(
 9987                                new_head,
 9988                                MultiBufferPoint::new(
 9989                                    old_head.row,
 9990                                    ((old_head.column - 1) / indent_len) * indent_len,
 9991                                ),
 9992                            );
 9993                        }
 9994                    }
 9995
 9996                    selection.set_head(new_head, SelectionGoal::None);
 9997                }
 9998            }
 9999
10000            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10001            this.insert("", window, cx);
10002            let empty_str: Arc<str> = Arc::from("");
10003            for (buffer, edits) in linked_ranges {
10004                let snapshot = buffer.read(cx).snapshot();
10005                use text::ToPoint as TP;
10006
10007                let edits = edits
10008                    .into_iter()
10009                    .map(|range| {
10010                        let end_point = TP::to_point(&range.end, &snapshot);
10011                        let mut start_point = TP::to_point(&range.start, &snapshot);
10012
10013                        if end_point == start_point {
10014                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10015                                .saturating_sub(1);
10016                            start_point =
10017                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10018                        };
10019
10020                        (start_point..end_point, empty_str.clone())
10021                    })
10022                    .sorted_by_key(|(range, _)| range.start)
10023                    .collect::<Vec<_>>();
10024                buffer.update(cx, |this, cx| {
10025                    this.edit(edits, None, cx);
10026                })
10027            }
10028            this.refresh_edit_prediction(true, false, window, cx);
10029            refresh_linked_ranges(this, window, cx);
10030        });
10031    }
10032
10033    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10034        if self.read_only(cx) {
10035            return;
10036        }
10037        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10038        self.transact(window, cx, |this, window, cx| {
10039            this.change_selections(Default::default(), window, cx, |s| {
10040                s.move_with(|map, selection| {
10041                    if selection.is_empty() {
10042                        let cursor = movement::right(map, selection.head());
10043                        selection.end = cursor;
10044                        selection.reversed = true;
10045                        selection.goal = SelectionGoal::None;
10046                    }
10047                })
10048            });
10049            this.insert("", window, cx);
10050            this.refresh_edit_prediction(true, false, window, cx);
10051        });
10052    }
10053
10054    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10055        if self.mode.is_single_line() {
10056            cx.propagate();
10057            return;
10058        }
10059
10060        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10061        if self.move_to_prev_snippet_tabstop(window, cx) {
10062            return;
10063        }
10064        self.outdent(&Outdent, window, cx);
10065    }
10066
10067    pub fn next_snippet_tabstop(
10068        &mut self,
10069        _: &NextSnippetTabstop,
10070        window: &mut Window,
10071        cx: &mut Context<Self>,
10072    ) {
10073        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10074            cx.propagate();
10075            return;
10076        }
10077
10078        if self.move_to_next_snippet_tabstop(window, cx) {
10079            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10080            return;
10081        }
10082        cx.propagate();
10083    }
10084
10085    pub fn previous_snippet_tabstop(
10086        &mut self,
10087        _: &PreviousSnippetTabstop,
10088        window: &mut Window,
10089        cx: &mut Context<Self>,
10090    ) {
10091        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10092            cx.propagate();
10093            return;
10094        }
10095
10096        if self.move_to_prev_snippet_tabstop(window, cx) {
10097            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10098            return;
10099        }
10100        cx.propagate();
10101    }
10102
10103    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10104        if self.mode.is_single_line() {
10105            cx.propagate();
10106            return;
10107        }
10108
10109        if self.move_to_next_snippet_tabstop(window, cx) {
10110            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10111            return;
10112        }
10113        if self.read_only(cx) {
10114            return;
10115        }
10116        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10117        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10118        let buffer = self.buffer.read(cx);
10119        let snapshot = buffer.snapshot(cx);
10120        let rows_iter = selections.iter().map(|s| s.head().row);
10121        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10122
10123        let has_some_cursor_in_whitespace = selections
10124            .iter()
10125            .filter(|selection| selection.is_empty())
10126            .any(|selection| {
10127                let cursor = selection.head();
10128                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10129                cursor.column < current_indent.len
10130            });
10131
10132        let mut edits = Vec::new();
10133        let mut prev_edited_row = 0;
10134        let mut row_delta = 0;
10135        for selection in &mut selections {
10136            if selection.start.row != prev_edited_row {
10137                row_delta = 0;
10138            }
10139            prev_edited_row = selection.end.row;
10140
10141            // If the selection is non-empty, then increase the indentation of the selected lines.
10142            if !selection.is_empty() {
10143                row_delta =
10144                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10145                continue;
10146            }
10147
10148            let cursor = selection.head();
10149            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10150            if let Some(suggested_indent) =
10151                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10152            {
10153                // Don't do anything if already at suggested indent
10154                // and there is any other cursor which is not
10155                if has_some_cursor_in_whitespace
10156                    && cursor.column == current_indent.len
10157                    && current_indent.len == suggested_indent.len
10158                {
10159                    continue;
10160                }
10161
10162                // Adjust line and move cursor to suggested indent
10163                // if cursor is not at suggested indent
10164                if cursor.column < suggested_indent.len
10165                    && cursor.column <= current_indent.len
10166                    && current_indent.len <= suggested_indent.len
10167                {
10168                    selection.start = Point::new(cursor.row, suggested_indent.len);
10169                    selection.end = selection.start;
10170                    if row_delta == 0 {
10171                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10172                            cursor.row,
10173                            current_indent,
10174                            suggested_indent,
10175                        ));
10176                        row_delta = suggested_indent.len - current_indent.len;
10177                    }
10178                    continue;
10179                }
10180
10181                // If current indent is more than suggested indent
10182                // only move cursor to current indent and skip indent
10183                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10184                    selection.start = Point::new(cursor.row, current_indent.len);
10185                    selection.end = selection.start;
10186                    continue;
10187                }
10188            }
10189
10190            // Otherwise, insert a hard or soft tab.
10191            let settings = buffer.language_settings_at(cursor, cx);
10192            let tab_size = if settings.hard_tabs {
10193                IndentSize::tab()
10194            } else {
10195                let tab_size = settings.tab_size.get();
10196                let indent_remainder = snapshot
10197                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10198                    .flat_map(str::chars)
10199                    .fold(row_delta % tab_size, |counter: u32, c| {
10200                        if c == '\t' {
10201                            0
10202                        } else {
10203                            (counter + 1) % tab_size
10204                        }
10205                    });
10206
10207                let chars_to_next_tab_stop = tab_size - indent_remainder;
10208                IndentSize::spaces(chars_to_next_tab_stop)
10209            };
10210            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10211            selection.end = selection.start;
10212            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10213            row_delta += tab_size.len;
10214        }
10215
10216        self.transact(window, cx, |this, window, cx| {
10217            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10218            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10219            this.refresh_edit_prediction(true, false, window, cx);
10220        });
10221    }
10222
10223    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10224        if self.read_only(cx) {
10225            return;
10226        }
10227        if self.mode.is_single_line() {
10228            cx.propagate();
10229            return;
10230        }
10231
10232        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10233        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10234        let mut prev_edited_row = 0;
10235        let mut row_delta = 0;
10236        let mut edits = Vec::new();
10237        let buffer = self.buffer.read(cx);
10238        let snapshot = buffer.snapshot(cx);
10239        for selection in &mut selections {
10240            if selection.start.row != prev_edited_row {
10241                row_delta = 0;
10242            }
10243            prev_edited_row = selection.end.row;
10244
10245            row_delta =
10246                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10247        }
10248
10249        self.transact(window, cx, |this, window, cx| {
10250            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10251            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10252        });
10253    }
10254
10255    fn indent_selection(
10256        buffer: &MultiBuffer,
10257        snapshot: &MultiBufferSnapshot,
10258        selection: &mut Selection<Point>,
10259        edits: &mut Vec<(Range<Point>, String)>,
10260        delta_for_start_row: u32,
10261        cx: &App,
10262    ) -> u32 {
10263        let settings = buffer.language_settings_at(selection.start, cx);
10264        let tab_size = settings.tab_size.get();
10265        let indent_kind = if settings.hard_tabs {
10266            IndentKind::Tab
10267        } else {
10268            IndentKind::Space
10269        };
10270        let mut start_row = selection.start.row;
10271        let mut end_row = selection.end.row + 1;
10272
10273        // If a selection ends at the beginning of a line, don't indent
10274        // that last line.
10275        if selection.end.column == 0 && selection.end.row > selection.start.row {
10276            end_row -= 1;
10277        }
10278
10279        // Avoid re-indenting a row that has already been indented by a
10280        // previous selection, but still update this selection's column
10281        // to reflect that indentation.
10282        if delta_for_start_row > 0 {
10283            start_row += 1;
10284            selection.start.column += delta_for_start_row;
10285            if selection.end.row == selection.start.row {
10286                selection.end.column += delta_for_start_row;
10287            }
10288        }
10289
10290        let mut delta_for_end_row = 0;
10291        let has_multiple_rows = start_row + 1 != end_row;
10292        for row in start_row..end_row {
10293            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10294            let indent_delta = match (current_indent.kind, indent_kind) {
10295                (IndentKind::Space, IndentKind::Space) => {
10296                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10297                    IndentSize::spaces(columns_to_next_tab_stop)
10298                }
10299                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10300                (_, IndentKind::Tab) => IndentSize::tab(),
10301            };
10302
10303            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10304                0
10305            } else {
10306                selection.start.column
10307            };
10308            let row_start = Point::new(row, start);
10309            edits.push((
10310                row_start..row_start,
10311                indent_delta.chars().collect::<String>(),
10312            ));
10313
10314            // Update this selection's endpoints to reflect the indentation.
10315            if row == selection.start.row {
10316                selection.start.column += indent_delta.len;
10317            }
10318            if row == selection.end.row {
10319                selection.end.column += indent_delta.len;
10320                delta_for_end_row = indent_delta.len;
10321            }
10322        }
10323
10324        if selection.start.row == selection.end.row {
10325            delta_for_start_row + delta_for_end_row
10326        } else {
10327            delta_for_end_row
10328        }
10329    }
10330
10331    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10332        if self.read_only(cx) {
10333            return;
10334        }
10335        if self.mode.is_single_line() {
10336            cx.propagate();
10337            return;
10338        }
10339
10340        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10341        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10342        let selections = self.selections.all::<Point>(&display_map);
10343        let mut deletion_ranges = Vec::new();
10344        let mut last_outdent = None;
10345        {
10346            let buffer = self.buffer.read(cx);
10347            let snapshot = buffer.snapshot(cx);
10348            for selection in &selections {
10349                let settings = buffer.language_settings_at(selection.start, cx);
10350                let tab_size = settings.tab_size.get();
10351                let mut rows = selection.spanned_rows(false, &display_map);
10352
10353                // Avoid re-outdenting a row that has already been outdented by a
10354                // previous selection.
10355                if let Some(last_row) = last_outdent
10356                    && last_row == rows.start
10357                {
10358                    rows.start = rows.start.next_row();
10359                }
10360                let has_multiple_rows = rows.len() > 1;
10361                for row in rows.iter_rows() {
10362                    let indent_size = snapshot.indent_size_for_line(row);
10363                    if indent_size.len > 0 {
10364                        let deletion_len = match indent_size.kind {
10365                            IndentKind::Space => {
10366                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10367                                if columns_to_prev_tab_stop == 0 {
10368                                    tab_size
10369                                } else {
10370                                    columns_to_prev_tab_stop
10371                                }
10372                            }
10373                            IndentKind::Tab => 1,
10374                        };
10375                        let start = if has_multiple_rows
10376                            || deletion_len > selection.start.column
10377                            || indent_size.len < selection.start.column
10378                        {
10379                            0
10380                        } else {
10381                            selection.start.column - deletion_len
10382                        };
10383                        deletion_ranges.push(
10384                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10385                        );
10386                        last_outdent = Some(row);
10387                    }
10388                }
10389            }
10390        }
10391
10392        self.transact(window, cx, |this, window, cx| {
10393            this.buffer.update(cx, |buffer, cx| {
10394                let empty_str: Arc<str> = Arc::default();
10395                buffer.edit(
10396                    deletion_ranges
10397                        .into_iter()
10398                        .map(|range| (range, empty_str.clone())),
10399                    None,
10400                    cx,
10401                );
10402            });
10403            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10404            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10405        });
10406    }
10407
10408    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10409        if self.read_only(cx) {
10410            return;
10411        }
10412        if self.mode.is_single_line() {
10413            cx.propagate();
10414            return;
10415        }
10416
10417        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10418        let selections = self
10419            .selections
10420            .all::<usize>(&self.display_snapshot(cx))
10421            .into_iter()
10422            .map(|s| s.range());
10423
10424        self.transact(window, cx, |this, window, cx| {
10425            this.buffer.update(cx, |buffer, cx| {
10426                buffer.autoindent_ranges(selections, cx);
10427            });
10428            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10429            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10430        });
10431    }
10432
10433    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10434        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10435        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10436        let selections = self.selections.all::<Point>(&display_map);
10437
10438        let mut new_cursors = Vec::new();
10439        let mut edit_ranges = Vec::new();
10440        let mut selections = selections.iter().peekable();
10441        while let Some(selection) = selections.next() {
10442            let mut rows = selection.spanned_rows(false, &display_map);
10443
10444            // Accumulate contiguous regions of rows that we want to delete.
10445            while let Some(next_selection) = selections.peek() {
10446                let next_rows = next_selection.spanned_rows(false, &display_map);
10447                if next_rows.start <= rows.end {
10448                    rows.end = next_rows.end;
10449                    selections.next().unwrap();
10450                } else {
10451                    break;
10452                }
10453            }
10454
10455            let buffer = display_map.buffer_snapshot();
10456            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10457            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10458                // If there's a line after the range, delete the \n from the end of the row range
10459                (
10460                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10461                    rows.end,
10462                )
10463            } else {
10464                // If there isn't a line after the range, delete the \n from the line before the
10465                // start of the row range
10466                edit_start = edit_start.saturating_sub(1);
10467                (buffer.len(), rows.start.previous_row())
10468            };
10469
10470            let text_layout_details = self.text_layout_details(window);
10471            let x = display_map.x_for_display_point(
10472                selection.head().to_display_point(&display_map),
10473                &text_layout_details,
10474            );
10475            let row = Point::new(target_row.0, 0)
10476                .to_display_point(&display_map)
10477                .row();
10478            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10479
10480            new_cursors.push((
10481                selection.id,
10482                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10483                SelectionGoal::None,
10484            ));
10485            edit_ranges.push(edit_start..edit_end);
10486        }
10487
10488        self.transact(window, cx, |this, window, cx| {
10489            let buffer = this.buffer.update(cx, |buffer, cx| {
10490                let empty_str: Arc<str> = Arc::default();
10491                buffer.edit(
10492                    edit_ranges
10493                        .into_iter()
10494                        .map(|range| (range, empty_str.clone())),
10495                    None,
10496                    cx,
10497                );
10498                buffer.snapshot(cx)
10499            });
10500            let new_selections = new_cursors
10501                .into_iter()
10502                .map(|(id, cursor, goal)| {
10503                    let cursor = cursor.to_point(&buffer);
10504                    Selection {
10505                        id,
10506                        start: cursor,
10507                        end: cursor,
10508                        reversed: false,
10509                        goal,
10510                    }
10511                })
10512                .collect();
10513
10514            this.change_selections(Default::default(), window, cx, |s| {
10515                s.select(new_selections);
10516            });
10517        });
10518    }
10519
10520    pub fn join_lines_impl(
10521        &mut self,
10522        insert_whitespace: bool,
10523        window: &mut Window,
10524        cx: &mut Context<Self>,
10525    ) {
10526        if self.read_only(cx) {
10527            return;
10528        }
10529        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10530        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10531            let start = MultiBufferRow(selection.start.row);
10532            // Treat single line selections as if they include the next line. Otherwise this action
10533            // would do nothing for single line selections individual cursors.
10534            let end = if selection.start.row == selection.end.row {
10535                MultiBufferRow(selection.start.row + 1)
10536            } else {
10537                MultiBufferRow(selection.end.row)
10538            };
10539
10540            if let Some(last_row_range) = row_ranges.last_mut()
10541                && start <= last_row_range.end
10542            {
10543                last_row_range.end = end;
10544                continue;
10545            }
10546            row_ranges.push(start..end);
10547        }
10548
10549        let snapshot = self.buffer.read(cx).snapshot(cx);
10550        let mut cursor_positions = Vec::new();
10551        for row_range in &row_ranges {
10552            let anchor = snapshot.anchor_before(Point::new(
10553                row_range.end.previous_row().0,
10554                snapshot.line_len(row_range.end.previous_row()),
10555            ));
10556            cursor_positions.push(anchor..anchor);
10557        }
10558
10559        self.transact(window, cx, |this, window, cx| {
10560            for row_range in row_ranges.into_iter().rev() {
10561                for row in row_range.iter_rows().rev() {
10562                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10563                    let next_line_row = row.next_row();
10564                    let indent = snapshot.indent_size_for_line(next_line_row);
10565                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10566
10567                    let replace =
10568                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10569                            " "
10570                        } else {
10571                            ""
10572                        };
10573
10574                    this.buffer.update(cx, |buffer, cx| {
10575                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10576                    });
10577                }
10578            }
10579
10580            this.change_selections(Default::default(), window, cx, |s| {
10581                s.select_anchor_ranges(cursor_positions)
10582            });
10583        });
10584    }
10585
10586    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10587        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10588        self.join_lines_impl(true, window, cx);
10589    }
10590
10591    pub fn sort_lines_case_sensitive(
10592        &mut self,
10593        _: &SortLinesCaseSensitive,
10594        window: &mut Window,
10595        cx: &mut Context<Self>,
10596    ) {
10597        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10598    }
10599
10600    pub fn sort_lines_by_length(
10601        &mut self,
10602        _: &SortLinesByLength,
10603        window: &mut Window,
10604        cx: &mut Context<Self>,
10605    ) {
10606        self.manipulate_immutable_lines(window, cx, |lines| {
10607            lines.sort_by_key(|&line| line.chars().count())
10608        })
10609    }
10610
10611    pub fn sort_lines_case_insensitive(
10612        &mut self,
10613        _: &SortLinesCaseInsensitive,
10614        window: &mut Window,
10615        cx: &mut Context<Self>,
10616    ) {
10617        self.manipulate_immutable_lines(window, cx, |lines| {
10618            lines.sort_by_key(|line| line.to_lowercase())
10619        })
10620    }
10621
10622    pub fn unique_lines_case_insensitive(
10623        &mut self,
10624        _: &UniqueLinesCaseInsensitive,
10625        window: &mut Window,
10626        cx: &mut Context<Self>,
10627    ) {
10628        self.manipulate_immutable_lines(window, cx, |lines| {
10629            let mut seen = HashSet::default();
10630            lines.retain(|line| seen.insert(line.to_lowercase()));
10631        })
10632    }
10633
10634    pub fn unique_lines_case_sensitive(
10635        &mut self,
10636        _: &UniqueLinesCaseSensitive,
10637        window: &mut Window,
10638        cx: &mut Context<Self>,
10639    ) {
10640        self.manipulate_immutable_lines(window, cx, |lines| {
10641            let mut seen = HashSet::default();
10642            lines.retain(|line| seen.insert(*line));
10643        })
10644    }
10645
10646    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10647        let snapshot = self.buffer.read(cx).snapshot(cx);
10648        for selection in self.selections.disjoint_anchors_arc().iter() {
10649            if snapshot
10650                .language_at(selection.start)
10651                .and_then(|lang| lang.config().wrap_characters.as_ref())
10652                .is_some()
10653            {
10654                return true;
10655            }
10656        }
10657        false
10658    }
10659
10660    fn wrap_selections_in_tag(
10661        &mut self,
10662        _: &WrapSelectionsInTag,
10663        window: &mut Window,
10664        cx: &mut Context<Self>,
10665    ) {
10666        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10667
10668        let snapshot = self.buffer.read(cx).snapshot(cx);
10669
10670        let mut edits = Vec::new();
10671        let mut boundaries = Vec::new();
10672
10673        for selection in self
10674            .selections
10675            .all_adjusted(&self.display_snapshot(cx))
10676            .iter()
10677        {
10678            let Some(wrap_config) = snapshot
10679                .language_at(selection.start)
10680                .and_then(|lang| lang.config().wrap_characters.clone())
10681            else {
10682                continue;
10683            };
10684
10685            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10686            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10687
10688            let start_before = snapshot.anchor_before(selection.start);
10689            let end_after = snapshot.anchor_after(selection.end);
10690
10691            edits.push((start_before..start_before, open_tag));
10692            edits.push((end_after..end_after, close_tag));
10693
10694            boundaries.push((
10695                start_before,
10696                end_after,
10697                wrap_config.start_prefix.len(),
10698                wrap_config.end_suffix.len(),
10699            ));
10700        }
10701
10702        if edits.is_empty() {
10703            return;
10704        }
10705
10706        self.transact(window, cx, |this, window, cx| {
10707            let buffer = this.buffer.update(cx, |buffer, cx| {
10708                buffer.edit(edits, None, cx);
10709                buffer.snapshot(cx)
10710            });
10711
10712            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10713            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10714                boundaries.into_iter()
10715            {
10716                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10717                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10718                new_selections.push(open_offset..open_offset);
10719                new_selections.push(close_offset..close_offset);
10720            }
10721
10722            this.change_selections(Default::default(), window, cx, |s| {
10723                s.select_ranges(new_selections);
10724            });
10725
10726            this.request_autoscroll(Autoscroll::fit(), cx);
10727        });
10728    }
10729
10730    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10731        let Some(project) = self.project.clone() else {
10732            return;
10733        };
10734        self.reload(project, window, cx)
10735            .detach_and_notify_err(window, cx);
10736    }
10737
10738    pub fn restore_file(
10739        &mut self,
10740        _: &::git::RestoreFile,
10741        window: &mut Window,
10742        cx: &mut Context<Self>,
10743    ) {
10744        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10745        let mut buffer_ids = HashSet::default();
10746        let snapshot = self.buffer().read(cx).snapshot(cx);
10747        for selection in self.selections.all::<usize>(&self.display_snapshot(cx)) {
10748            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10749        }
10750
10751        let buffer = self.buffer().read(cx);
10752        let ranges = buffer_ids
10753            .into_iter()
10754            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10755            .collect::<Vec<_>>();
10756
10757        self.restore_hunks_in_ranges(ranges, window, cx);
10758    }
10759
10760    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10761        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10762        let selections = self
10763            .selections
10764            .all(&self.display_snapshot(cx))
10765            .into_iter()
10766            .map(|s| s.range())
10767            .collect();
10768        self.restore_hunks_in_ranges(selections, window, cx);
10769    }
10770
10771    pub fn restore_hunks_in_ranges(
10772        &mut self,
10773        ranges: Vec<Range<Point>>,
10774        window: &mut Window,
10775        cx: &mut Context<Editor>,
10776    ) {
10777        let mut revert_changes = HashMap::default();
10778        let chunk_by = self
10779            .snapshot(window, cx)
10780            .hunks_for_ranges(ranges)
10781            .into_iter()
10782            .chunk_by(|hunk| hunk.buffer_id);
10783        for (buffer_id, hunks) in &chunk_by {
10784            let hunks = hunks.collect::<Vec<_>>();
10785            for hunk in &hunks {
10786                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10787            }
10788            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10789        }
10790        drop(chunk_by);
10791        if !revert_changes.is_empty() {
10792            self.transact(window, cx, |editor, window, cx| {
10793                editor.restore(revert_changes, window, cx);
10794            });
10795        }
10796    }
10797
10798    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
10799        if let Some(status) = self
10800            .addons
10801            .iter()
10802            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
10803        {
10804            return Some(status);
10805        }
10806        self.project
10807            .as_ref()?
10808            .read(cx)
10809            .status_for_buffer_id(buffer_id, cx)
10810    }
10811
10812    pub fn open_active_item_in_terminal(
10813        &mut self,
10814        _: &OpenInTerminal,
10815        window: &mut Window,
10816        cx: &mut Context<Self>,
10817    ) {
10818        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10819            let project_path = buffer.read(cx).project_path(cx)?;
10820            let project = self.project()?.read(cx);
10821            let entry = project.entry_for_path(&project_path, cx)?;
10822            let parent = match &entry.canonical_path {
10823                Some(canonical_path) => canonical_path.to_path_buf(),
10824                None => project.absolute_path(&project_path, cx)?,
10825            }
10826            .parent()?
10827            .to_path_buf();
10828            Some(parent)
10829        }) {
10830            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10831        }
10832    }
10833
10834    fn set_breakpoint_context_menu(
10835        &mut self,
10836        display_row: DisplayRow,
10837        position: Option<Anchor>,
10838        clicked_point: gpui::Point<Pixels>,
10839        window: &mut Window,
10840        cx: &mut Context<Self>,
10841    ) {
10842        let source = self
10843            .buffer
10844            .read(cx)
10845            .snapshot(cx)
10846            .anchor_before(Point::new(display_row.0, 0u32));
10847
10848        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10849
10850        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10851            self,
10852            source,
10853            clicked_point,
10854            context_menu,
10855            window,
10856            cx,
10857        );
10858    }
10859
10860    fn add_edit_breakpoint_block(
10861        &mut self,
10862        anchor: Anchor,
10863        breakpoint: &Breakpoint,
10864        edit_action: BreakpointPromptEditAction,
10865        window: &mut Window,
10866        cx: &mut Context<Self>,
10867    ) {
10868        let weak_editor = cx.weak_entity();
10869        let bp_prompt = cx.new(|cx| {
10870            BreakpointPromptEditor::new(
10871                weak_editor,
10872                anchor,
10873                breakpoint.clone(),
10874                edit_action,
10875                window,
10876                cx,
10877            )
10878        });
10879
10880        let height = bp_prompt.update(cx, |this, cx| {
10881            this.prompt
10882                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10883        });
10884        let cloned_prompt = bp_prompt.clone();
10885        let blocks = vec![BlockProperties {
10886            style: BlockStyle::Sticky,
10887            placement: BlockPlacement::Above(anchor),
10888            height: Some(height),
10889            render: Arc::new(move |cx| {
10890                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10891                cloned_prompt.clone().into_any_element()
10892            }),
10893            priority: 0,
10894        }];
10895
10896        let focus_handle = bp_prompt.focus_handle(cx);
10897        window.focus(&focus_handle);
10898
10899        let block_ids = self.insert_blocks(blocks, None, cx);
10900        bp_prompt.update(cx, |prompt, _| {
10901            prompt.add_block_ids(block_ids);
10902        });
10903    }
10904
10905    pub(crate) fn breakpoint_at_row(
10906        &self,
10907        row: u32,
10908        window: &mut Window,
10909        cx: &mut Context<Self>,
10910    ) -> Option<(Anchor, Breakpoint)> {
10911        let snapshot = self.snapshot(window, cx);
10912        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
10913
10914        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10915    }
10916
10917    pub(crate) fn breakpoint_at_anchor(
10918        &self,
10919        breakpoint_position: Anchor,
10920        snapshot: &EditorSnapshot,
10921        cx: &mut Context<Self>,
10922    ) -> Option<(Anchor, Breakpoint)> {
10923        let buffer = self
10924            .buffer
10925            .read(cx)
10926            .buffer_for_anchor(breakpoint_position, cx)?;
10927
10928        let enclosing_excerpt = breakpoint_position.excerpt_id;
10929        let buffer_snapshot = buffer.read(cx).snapshot();
10930
10931        let row = buffer_snapshot
10932            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10933            .row;
10934
10935        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
10936        let anchor_end = snapshot
10937            .buffer_snapshot()
10938            .anchor_after(Point::new(row, line_len));
10939
10940        self.breakpoint_store
10941            .as_ref()?
10942            .read_with(cx, |breakpoint_store, cx| {
10943                breakpoint_store
10944                    .breakpoints(
10945                        &buffer,
10946                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10947                        &buffer_snapshot,
10948                        cx,
10949                    )
10950                    .next()
10951                    .and_then(|(bp, _)| {
10952                        let breakpoint_row = buffer_snapshot
10953                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10954                            .row;
10955
10956                        if breakpoint_row == row {
10957                            snapshot
10958                                .buffer_snapshot()
10959                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10960                                .map(|position| (position, bp.bp.clone()))
10961                        } else {
10962                            None
10963                        }
10964                    })
10965            })
10966    }
10967
10968    pub fn edit_log_breakpoint(
10969        &mut self,
10970        _: &EditLogBreakpoint,
10971        window: &mut Window,
10972        cx: &mut Context<Self>,
10973    ) {
10974        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10975            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10976                message: None,
10977                state: BreakpointState::Enabled,
10978                condition: None,
10979                hit_condition: None,
10980            });
10981
10982            self.add_edit_breakpoint_block(
10983                anchor,
10984                &breakpoint,
10985                BreakpointPromptEditAction::Log,
10986                window,
10987                cx,
10988            );
10989        }
10990    }
10991
10992    fn breakpoints_at_cursors(
10993        &self,
10994        window: &mut Window,
10995        cx: &mut Context<Self>,
10996    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10997        let snapshot = self.snapshot(window, cx);
10998        let cursors = self
10999            .selections
11000            .disjoint_anchors_arc()
11001            .iter()
11002            .map(|selection| {
11003                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11004
11005                let breakpoint_position = self
11006                    .breakpoint_at_row(cursor_position.row, window, cx)
11007                    .map(|bp| bp.0)
11008                    .unwrap_or_else(|| {
11009                        snapshot
11010                            .display_snapshot
11011                            .buffer_snapshot()
11012                            .anchor_after(Point::new(cursor_position.row, 0))
11013                    });
11014
11015                let breakpoint = self
11016                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11017                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11018
11019                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11020            })
11021            // 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.
11022            .collect::<HashMap<Anchor, _>>();
11023
11024        cursors.into_iter().collect()
11025    }
11026
11027    pub fn enable_breakpoint(
11028        &mut self,
11029        _: &crate::actions::EnableBreakpoint,
11030        window: &mut Window,
11031        cx: &mut Context<Self>,
11032    ) {
11033        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11034            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11035                continue;
11036            };
11037            self.edit_breakpoint_at_anchor(
11038                anchor,
11039                breakpoint,
11040                BreakpointEditAction::InvertState,
11041                cx,
11042            );
11043        }
11044    }
11045
11046    pub fn disable_breakpoint(
11047        &mut self,
11048        _: &crate::actions::DisableBreakpoint,
11049        window: &mut Window,
11050        cx: &mut Context<Self>,
11051    ) {
11052        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11053            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11054                continue;
11055            };
11056            self.edit_breakpoint_at_anchor(
11057                anchor,
11058                breakpoint,
11059                BreakpointEditAction::InvertState,
11060                cx,
11061            );
11062        }
11063    }
11064
11065    pub fn toggle_breakpoint(
11066        &mut self,
11067        _: &crate::actions::ToggleBreakpoint,
11068        window: &mut Window,
11069        cx: &mut Context<Self>,
11070    ) {
11071        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11072            if let Some(breakpoint) = breakpoint {
11073                self.edit_breakpoint_at_anchor(
11074                    anchor,
11075                    breakpoint,
11076                    BreakpointEditAction::Toggle,
11077                    cx,
11078                );
11079            } else {
11080                self.edit_breakpoint_at_anchor(
11081                    anchor,
11082                    Breakpoint::new_standard(),
11083                    BreakpointEditAction::Toggle,
11084                    cx,
11085                );
11086            }
11087        }
11088    }
11089
11090    pub fn edit_breakpoint_at_anchor(
11091        &mut self,
11092        breakpoint_position: Anchor,
11093        breakpoint: Breakpoint,
11094        edit_action: BreakpointEditAction,
11095        cx: &mut Context<Self>,
11096    ) {
11097        let Some(breakpoint_store) = &self.breakpoint_store else {
11098            return;
11099        };
11100
11101        let Some(buffer) = self
11102            .buffer
11103            .read(cx)
11104            .buffer_for_anchor(breakpoint_position, cx)
11105        else {
11106            return;
11107        };
11108
11109        breakpoint_store.update(cx, |breakpoint_store, cx| {
11110            breakpoint_store.toggle_breakpoint(
11111                buffer,
11112                BreakpointWithPosition {
11113                    position: breakpoint_position.text_anchor,
11114                    bp: breakpoint,
11115                },
11116                edit_action,
11117                cx,
11118            );
11119        });
11120
11121        cx.notify();
11122    }
11123
11124    #[cfg(any(test, feature = "test-support"))]
11125    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11126        self.breakpoint_store.clone()
11127    }
11128
11129    pub fn prepare_restore_change(
11130        &self,
11131        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11132        hunk: &MultiBufferDiffHunk,
11133        cx: &mut App,
11134    ) -> Option<()> {
11135        if hunk.is_created_file() {
11136            return None;
11137        }
11138        let buffer = self.buffer.read(cx);
11139        let diff = buffer.diff_for(hunk.buffer_id)?;
11140        let buffer = buffer.buffer(hunk.buffer_id)?;
11141        let buffer = buffer.read(cx);
11142        let original_text = diff
11143            .read(cx)
11144            .base_text()
11145            .as_rope()
11146            .slice(hunk.diff_base_byte_range.clone());
11147        let buffer_snapshot = buffer.snapshot();
11148        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11149        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11150            probe
11151                .0
11152                .start
11153                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11154                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11155        }) {
11156            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11157            Some(())
11158        } else {
11159            None
11160        }
11161    }
11162
11163    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11164        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11165    }
11166
11167    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11168        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11169    }
11170
11171    fn manipulate_lines<M>(
11172        &mut self,
11173        window: &mut Window,
11174        cx: &mut Context<Self>,
11175        mut manipulate: M,
11176    ) where
11177        M: FnMut(&str) -> LineManipulationResult,
11178    {
11179        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11180
11181        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11182        let buffer = self.buffer.read(cx).snapshot(cx);
11183
11184        let mut edits = Vec::new();
11185
11186        let selections = self.selections.all::<Point>(&display_map);
11187        let mut selections = selections.iter().peekable();
11188        let mut contiguous_row_selections = Vec::new();
11189        let mut new_selections = Vec::new();
11190        let mut added_lines = 0;
11191        let mut removed_lines = 0;
11192
11193        while let Some(selection) = selections.next() {
11194            let (start_row, end_row) = consume_contiguous_rows(
11195                &mut contiguous_row_selections,
11196                selection,
11197                &display_map,
11198                &mut selections,
11199            );
11200
11201            let start_point = Point::new(start_row.0, 0);
11202            let end_point = Point::new(
11203                end_row.previous_row().0,
11204                buffer.line_len(end_row.previous_row()),
11205            );
11206            let text = buffer
11207                .text_for_range(start_point..end_point)
11208                .collect::<String>();
11209
11210            let LineManipulationResult {
11211                new_text,
11212                line_count_before,
11213                line_count_after,
11214            } = manipulate(&text);
11215
11216            edits.push((start_point..end_point, new_text));
11217
11218            // Selections must change based on added and removed line count
11219            let start_row =
11220                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11221            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11222            new_selections.push(Selection {
11223                id: selection.id,
11224                start: start_row,
11225                end: end_row,
11226                goal: SelectionGoal::None,
11227                reversed: selection.reversed,
11228            });
11229
11230            if line_count_after > line_count_before {
11231                added_lines += line_count_after - line_count_before;
11232            } else if line_count_before > line_count_after {
11233                removed_lines += line_count_before - line_count_after;
11234            }
11235        }
11236
11237        self.transact(window, cx, |this, window, cx| {
11238            let buffer = this.buffer.update(cx, |buffer, cx| {
11239                buffer.edit(edits, None, cx);
11240                buffer.snapshot(cx)
11241            });
11242
11243            // Recalculate offsets on newly edited buffer
11244            let new_selections = new_selections
11245                .iter()
11246                .map(|s| {
11247                    let start_point = Point::new(s.start.0, 0);
11248                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11249                    Selection {
11250                        id: s.id,
11251                        start: buffer.point_to_offset(start_point),
11252                        end: buffer.point_to_offset(end_point),
11253                        goal: s.goal,
11254                        reversed: s.reversed,
11255                    }
11256                })
11257                .collect();
11258
11259            this.change_selections(Default::default(), window, cx, |s| {
11260                s.select(new_selections);
11261            });
11262
11263            this.request_autoscroll(Autoscroll::fit(), cx);
11264        });
11265    }
11266
11267    fn manipulate_immutable_lines<Fn>(
11268        &mut self,
11269        window: &mut Window,
11270        cx: &mut Context<Self>,
11271        mut callback: Fn,
11272    ) where
11273        Fn: FnMut(&mut Vec<&str>),
11274    {
11275        self.manipulate_lines(window, cx, |text| {
11276            let mut lines: Vec<&str> = text.split('\n').collect();
11277            let line_count_before = lines.len();
11278
11279            callback(&mut lines);
11280
11281            LineManipulationResult {
11282                new_text: lines.join("\n"),
11283                line_count_before,
11284                line_count_after: lines.len(),
11285            }
11286        });
11287    }
11288
11289    fn manipulate_mutable_lines<Fn>(
11290        &mut self,
11291        window: &mut Window,
11292        cx: &mut Context<Self>,
11293        mut callback: Fn,
11294    ) where
11295        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11296    {
11297        self.manipulate_lines(window, cx, |text| {
11298            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11299            let line_count_before = lines.len();
11300
11301            callback(&mut lines);
11302
11303            LineManipulationResult {
11304                new_text: lines.join("\n"),
11305                line_count_before,
11306                line_count_after: lines.len(),
11307            }
11308        });
11309    }
11310
11311    pub fn convert_indentation_to_spaces(
11312        &mut self,
11313        _: &ConvertIndentationToSpaces,
11314        window: &mut Window,
11315        cx: &mut Context<Self>,
11316    ) {
11317        let settings = self.buffer.read(cx).language_settings(cx);
11318        let tab_size = settings.tab_size.get() as usize;
11319
11320        self.manipulate_mutable_lines(window, cx, |lines| {
11321            // Allocates a reasonably sized scratch buffer once for the whole loop
11322            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11323            // Avoids recomputing spaces that could be inserted many times
11324            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11325                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11326                .collect();
11327
11328            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11329                let mut chars = line.as_ref().chars();
11330                let mut col = 0;
11331                let mut changed = false;
11332
11333                for ch in chars.by_ref() {
11334                    match ch {
11335                        ' ' => {
11336                            reindented_line.push(' ');
11337                            col += 1;
11338                        }
11339                        '\t' => {
11340                            // \t are converted to spaces depending on the current column
11341                            let spaces_len = tab_size - (col % tab_size);
11342                            reindented_line.extend(&space_cache[spaces_len - 1]);
11343                            col += spaces_len;
11344                            changed = true;
11345                        }
11346                        _ => {
11347                            // If we dont append before break, the character is consumed
11348                            reindented_line.push(ch);
11349                            break;
11350                        }
11351                    }
11352                }
11353
11354                if !changed {
11355                    reindented_line.clear();
11356                    continue;
11357                }
11358                // Append the rest of the line and replace old reference with new one
11359                reindented_line.extend(chars);
11360                *line = Cow::Owned(reindented_line.clone());
11361                reindented_line.clear();
11362            }
11363        });
11364    }
11365
11366    pub fn convert_indentation_to_tabs(
11367        &mut self,
11368        _: &ConvertIndentationToTabs,
11369        window: &mut Window,
11370        cx: &mut Context<Self>,
11371    ) {
11372        let settings = self.buffer.read(cx).language_settings(cx);
11373        let tab_size = settings.tab_size.get() as usize;
11374
11375        self.manipulate_mutable_lines(window, cx, |lines| {
11376            // Allocates a reasonably sized buffer once for the whole loop
11377            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11378            // Avoids recomputing spaces that could be inserted many times
11379            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11380                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11381                .collect();
11382
11383            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11384                let mut chars = line.chars();
11385                let mut spaces_count = 0;
11386                let mut first_non_indent_char = None;
11387                let mut changed = false;
11388
11389                for ch in chars.by_ref() {
11390                    match ch {
11391                        ' ' => {
11392                            // Keep track of spaces. Append \t when we reach tab_size
11393                            spaces_count += 1;
11394                            changed = true;
11395                            if spaces_count == tab_size {
11396                                reindented_line.push('\t');
11397                                spaces_count = 0;
11398                            }
11399                        }
11400                        '\t' => {
11401                            reindented_line.push('\t');
11402                            spaces_count = 0;
11403                        }
11404                        _ => {
11405                            // Dont append it yet, we might have remaining spaces
11406                            first_non_indent_char = Some(ch);
11407                            break;
11408                        }
11409                    }
11410                }
11411
11412                if !changed {
11413                    reindented_line.clear();
11414                    continue;
11415                }
11416                // Remaining spaces that didn't make a full tab stop
11417                if spaces_count > 0 {
11418                    reindented_line.extend(&space_cache[spaces_count - 1]);
11419                }
11420                // If we consume an extra character that was not indentation, add it back
11421                if let Some(extra_char) = first_non_indent_char {
11422                    reindented_line.push(extra_char);
11423                }
11424                // Append the rest of the line and replace old reference with new one
11425                reindented_line.extend(chars);
11426                *line = Cow::Owned(reindented_line.clone());
11427                reindented_line.clear();
11428            }
11429        });
11430    }
11431
11432    pub fn convert_to_upper_case(
11433        &mut self,
11434        _: &ConvertToUpperCase,
11435        window: &mut Window,
11436        cx: &mut Context<Self>,
11437    ) {
11438        self.manipulate_text(window, cx, |text| text.to_uppercase())
11439    }
11440
11441    pub fn convert_to_lower_case(
11442        &mut self,
11443        _: &ConvertToLowerCase,
11444        window: &mut Window,
11445        cx: &mut Context<Self>,
11446    ) {
11447        self.manipulate_text(window, cx, |text| text.to_lowercase())
11448    }
11449
11450    pub fn convert_to_title_case(
11451        &mut self,
11452        _: &ConvertToTitleCase,
11453        window: &mut Window,
11454        cx: &mut Context<Self>,
11455    ) {
11456        self.manipulate_text(window, cx, |text| {
11457            text.split('\n')
11458                .map(|line| line.to_case(Case::Title))
11459                .join("\n")
11460        })
11461    }
11462
11463    pub fn convert_to_snake_case(
11464        &mut self,
11465        _: &ConvertToSnakeCase,
11466        window: &mut Window,
11467        cx: &mut Context<Self>,
11468    ) {
11469        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11470    }
11471
11472    pub fn convert_to_kebab_case(
11473        &mut self,
11474        _: &ConvertToKebabCase,
11475        window: &mut Window,
11476        cx: &mut Context<Self>,
11477    ) {
11478        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11479    }
11480
11481    pub fn convert_to_upper_camel_case(
11482        &mut self,
11483        _: &ConvertToUpperCamelCase,
11484        window: &mut Window,
11485        cx: &mut Context<Self>,
11486    ) {
11487        self.manipulate_text(window, cx, |text| {
11488            text.split('\n')
11489                .map(|line| line.to_case(Case::UpperCamel))
11490                .join("\n")
11491        })
11492    }
11493
11494    pub fn convert_to_lower_camel_case(
11495        &mut self,
11496        _: &ConvertToLowerCamelCase,
11497        window: &mut Window,
11498        cx: &mut Context<Self>,
11499    ) {
11500        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11501    }
11502
11503    pub fn convert_to_opposite_case(
11504        &mut self,
11505        _: &ConvertToOppositeCase,
11506        window: &mut Window,
11507        cx: &mut Context<Self>,
11508    ) {
11509        self.manipulate_text(window, cx, |text| {
11510            text.chars()
11511                .fold(String::with_capacity(text.len()), |mut t, c| {
11512                    if c.is_uppercase() {
11513                        t.extend(c.to_lowercase());
11514                    } else {
11515                        t.extend(c.to_uppercase());
11516                    }
11517                    t
11518                })
11519        })
11520    }
11521
11522    pub fn convert_to_sentence_case(
11523        &mut self,
11524        _: &ConvertToSentenceCase,
11525        window: &mut Window,
11526        cx: &mut Context<Self>,
11527    ) {
11528        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11529    }
11530
11531    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11532        self.manipulate_text(window, cx, |text| {
11533            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11534            if has_upper_case_characters {
11535                text.to_lowercase()
11536            } else {
11537                text.to_uppercase()
11538            }
11539        })
11540    }
11541
11542    pub fn convert_to_rot13(
11543        &mut self,
11544        _: &ConvertToRot13,
11545        window: &mut Window,
11546        cx: &mut Context<Self>,
11547    ) {
11548        self.manipulate_text(window, cx, |text| {
11549            text.chars()
11550                .map(|c| match c {
11551                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11552                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11553                    _ => c,
11554                })
11555                .collect()
11556        })
11557    }
11558
11559    pub fn convert_to_rot47(
11560        &mut self,
11561        _: &ConvertToRot47,
11562        window: &mut Window,
11563        cx: &mut Context<Self>,
11564    ) {
11565        self.manipulate_text(window, cx, |text| {
11566            text.chars()
11567                .map(|c| {
11568                    let code_point = c as u32;
11569                    if code_point >= 33 && code_point <= 126 {
11570                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11571                    }
11572                    c
11573                })
11574                .collect()
11575        })
11576    }
11577
11578    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11579    where
11580        Fn: FnMut(&str) -> String,
11581    {
11582        let buffer = self.buffer.read(cx).snapshot(cx);
11583
11584        let mut new_selections = Vec::new();
11585        let mut edits = Vec::new();
11586        let mut selection_adjustment = 0i32;
11587
11588        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
11589            let selection_is_empty = selection.is_empty();
11590
11591            let (start, end) = if selection_is_empty {
11592                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11593                (word_range.start, word_range.end)
11594            } else {
11595                (
11596                    buffer.point_to_offset(selection.start),
11597                    buffer.point_to_offset(selection.end),
11598                )
11599            };
11600
11601            let text = buffer.text_for_range(start..end).collect::<String>();
11602            let old_length = text.len() as i32;
11603            let text = callback(&text);
11604
11605            new_selections.push(Selection {
11606                start: (start as i32 - selection_adjustment) as usize,
11607                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11608                goal: SelectionGoal::None,
11609                id: selection.id,
11610                reversed: selection.reversed,
11611            });
11612
11613            selection_adjustment += old_length - text.len() as i32;
11614
11615            edits.push((start..end, text));
11616        }
11617
11618        self.transact(window, cx, |this, window, cx| {
11619            this.buffer.update(cx, |buffer, cx| {
11620                buffer.edit(edits, None, cx);
11621            });
11622
11623            this.change_selections(Default::default(), window, cx, |s| {
11624                s.select(new_selections);
11625            });
11626
11627            this.request_autoscroll(Autoscroll::fit(), cx);
11628        });
11629    }
11630
11631    pub fn move_selection_on_drop(
11632        &mut self,
11633        selection: &Selection<Anchor>,
11634        target: DisplayPoint,
11635        is_cut: bool,
11636        window: &mut Window,
11637        cx: &mut Context<Self>,
11638    ) {
11639        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11640        let buffer = display_map.buffer_snapshot();
11641        let mut edits = Vec::new();
11642        let insert_point = display_map
11643            .clip_point(target, Bias::Left)
11644            .to_point(&display_map);
11645        let text = buffer
11646            .text_for_range(selection.start..selection.end)
11647            .collect::<String>();
11648        if is_cut {
11649            edits.push(((selection.start..selection.end), String::new()));
11650        }
11651        let insert_anchor = buffer.anchor_before(insert_point);
11652        edits.push(((insert_anchor..insert_anchor), text));
11653        let last_edit_start = insert_anchor.bias_left(buffer);
11654        let last_edit_end = insert_anchor.bias_right(buffer);
11655        self.transact(window, cx, |this, window, cx| {
11656            this.buffer.update(cx, |buffer, cx| {
11657                buffer.edit(edits, None, cx);
11658            });
11659            this.change_selections(Default::default(), window, cx, |s| {
11660                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11661            });
11662        });
11663    }
11664
11665    pub fn clear_selection_drag_state(&mut self) {
11666        self.selection_drag_state = SelectionDragState::None;
11667    }
11668
11669    pub fn duplicate(
11670        &mut self,
11671        upwards: bool,
11672        whole_lines: bool,
11673        window: &mut Window,
11674        cx: &mut Context<Self>,
11675    ) {
11676        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11677
11678        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11679        let buffer = display_map.buffer_snapshot();
11680        let selections = self.selections.all::<Point>(&display_map);
11681
11682        let mut edits = Vec::new();
11683        let mut selections_iter = selections.iter().peekable();
11684        while let Some(selection) = selections_iter.next() {
11685            let mut rows = selection.spanned_rows(false, &display_map);
11686            // duplicate line-wise
11687            if whole_lines || selection.start == selection.end {
11688                // Avoid duplicating the same lines twice.
11689                while let Some(next_selection) = selections_iter.peek() {
11690                    let next_rows = next_selection.spanned_rows(false, &display_map);
11691                    if next_rows.start < rows.end {
11692                        rows.end = next_rows.end;
11693                        selections_iter.next().unwrap();
11694                    } else {
11695                        break;
11696                    }
11697                }
11698
11699                // Copy the text from the selected row region and splice it either at the start
11700                // or end of the region.
11701                let start = Point::new(rows.start.0, 0);
11702                let end = Point::new(
11703                    rows.end.previous_row().0,
11704                    buffer.line_len(rows.end.previous_row()),
11705                );
11706
11707                let mut text = buffer.text_for_range(start..end).collect::<String>();
11708
11709                let insert_location = if upwards {
11710                    // When duplicating upward, we need to insert before the current line.
11711                    // If we're on the last line and it doesn't end with a newline,
11712                    // we need to add a newline before the duplicated content.
11713                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11714                        && buffer.max_point().column > 0
11715                        && !text.ends_with('\n');
11716
11717                    if needs_leading_newline {
11718                        text.insert(0, '\n');
11719                        end
11720                    } else {
11721                        text.push('\n');
11722                        Point::new(rows.start.0, 0)
11723                    }
11724                } else {
11725                    text.push('\n');
11726                    start
11727                };
11728                edits.push((insert_location..insert_location, text));
11729            } else {
11730                // duplicate character-wise
11731                let start = selection.start;
11732                let end = selection.end;
11733                let text = buffer.text_for_range(start..end).collect::<String>();
11734                edits.push((selection.end..selection.end, text));
11735            }
11736        }
11737
11738        self.transact(window, cx, |this, window, cx| {
11739            this.buffer.update(cx, |buffer, cx| {
11740                buffer.edit(edits, None, cx);
11741            });
11742
11743            // When duplicating upward with whole lines, move the cursor to the duplicated line
11744            if upwards && whole_lines {
11745                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
11746
11747                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11748                    let mut new_ranges = Vec::new();
11749                    let selections = s.all::<Point>(&display_map);
11750                    let mut selections_iter = selections.iter().peekable();
11751
11752                    while let Some(first_selection) = selections_iter.next() {
11753                        // Group contiguous selections together to find the total row span
11754                        let mut group_selections = vec![first_selection];
11755                        let mut rows = first_selection.spanned_rows(false, &display_map);
11756
11757                        while let Some(next_selection) = selections_iter.peek() {
11758                            let next_rows = next_selection.spanned_rows(false, &display_map);
11759                            if next_rows.start < rows.end {
11760                                rows.end = next_rows.end;
11761                                group_selections.push(selections_iter.next().unwrap());
11762                            } else {
11763                                break;
11764                            }
11765                        }
11766
11767                        let row_count = rows.end.0 - rows.start.0;
11768
11769                        // Move all selections in this group up by the total number of duplicated rows
11770                        for selection in group_selections {
11771                            let new_start = Point::new(
11772                                selection.start.row.saturating_sub(row_count),
11773                                selection.start.column,
11774                            );
11775
11776                            let new_end = Point::new(
11777                                selection.end.row.saturating_sub(row_count),
11778                                selection.end.column,
11779                            );
11780
11781                            new_ranges.push(new_start..new_end);
11782                        }
11783                    }
11784
11785                    s.select_ranges(new_ranges);
11786                });
11787            }
11788
11789            this.request_autoscroll(Autoscroll::fit(), cx);
11790        });
11791    }
11792
11793    pub fn duplicate_line_up(
11794        &mut self,
11795        _: &DuplicateLineUp,
11796        window: &mut Window,
11797        cx: &mut Context<Self>,
11798    ) {
11799        self.duplicate(true, true, window, cx);
11800    }
11801
11802    pub fn duplicate_line_down(
11803        &mut self,
11804        _: &DuplicateLineDown,
11805        window: &mut Window,
11806        cx: &mut Context<Self>,
11807    ) {
11808        self.duplicate(false, true, window, cx);
11809    }
11810
11811    pub fn duplicate_selection(
11812        &mut self,
11813        _: &DuplicateSelection,
11814        window: &mut Window,
11815        cx: &mut Context<Self>,
11816    ) {
11817        self.duplicate(false, false, window, cx);
11818    }
11819
11820    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11821        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11822        if self.mode.is_single_line() {
11823            cx.propagate();
11824            return;
11825        }
11826
11827        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11828        let buffer = self.buffer.read(cx).snapshot(cx);
11829
11830        let mut edits = Vec::new();
11831        let mut unfold_ranges = Vec::new();
11832        let mut refold_creases = Vec::new();
11833
11834        let selections = self.selections.all::<Point>(&display_map);
11835        let mut selections = selections.iter().peekable();
11836        let mut contiguous_row_selections = Vec::new();
11837        let mut new_selections = Vec::new();
11838
11839        while let Some(selection) = selections.next() {
11840            // Find all the selections that span a contiguous row range
11841            let (start_row, end_row) = consume_contiguous_rows(
11842                &mut contiguous_row_selections,
11843                selection,
11844                &display_map,
11845                &mut selections,
11846            );
11847
11848            // Move the text spanned by the row range to be before the line preceding the row range
11849            if start_row.0 > 0 {
11850                let range_to_move = Point::new(
11851                    start_row.previous_row().0,
11852                    buffer.line_len(start_row.previous_row()),
11853                )
11854                    ..Point::new(
11855                        end_row.previous_row().0,
11856                        buffer.line_len(end_row.previous_row()),
11857                    );
11858                let insertion_point = display_map
11859                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11860                    .0;
11861
11862                // Don't move lines across excerpts
11863                if buffer
11864                    .excerpt_containing(insertion_point..range_to_move.end)
11865                    .is_some()
11866                {
11867                    let text = buffer
11868                        .text_for_range(range_to_move.clone())
11869                        .flat_map(|s| s.chars())
11870                        .skip(1)
11871                        .chain(['\n'])
11872                        .collect::<String>();
11873
11874                    edits.push((
11875                        buffer.anchor_after(range_to_move.start)
11876                            ..buffer.anchor_before(range_to_move.end),
11877                        String::new(),
11878                    ));
11879                    let insertion_anchor = buffer.anchor_after(insertion_point);
11880                    edits.push((insertion_anchor..insertion_anchor, text));
11881
11882                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11883
11884                    // Move selections up
11885                    new_selections.extend(contiguous_row_selections.drain(..).map(
11886                        |mut selection| {
11887                            selection.start.row -= row_delta;
11888                            selection.end.row -= row_delta;
11889                            selection
11890                        },
11891                    ));
11892
11893                    // Move folds up
11894                    unfold_ranges.push(range_to_move.clone());
11895                    for fold in display_map.folds_in_range(
11896                        buffer.anchor_before(range_to_move.start)
11897                            ..buffer.anchor_after(range_to_move.end),
11898                    ) {
11899                        let mut start = fold.range.start.to_point(&buffer);
11900                        let mut end = fold.range.end.to_point(&buffer);
11901                        start.row -= row_delta;
11902                        end.row -= row_delta;
11903                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11904                    }
11905                }
11906            }
11907
11908            // If we didn't move line(s), preserve the existing selections
11909            new_selections.append(&mut contiguous_row_selections);
11910        }
11911
11912        self.transact(window, cx, |this, window, cx| {
11913            this.unfold_ranges(&unfold_ranges, true, true, cx);
11914            this.buffer.update(cx, |buffer, cx| {
11915                for (range, text) in edits {
11916                    buffer.edit([(range, text)], None, cx);
11917                }
11918            });
11919            this.fold_creases(refold_creases, true, window, cx);
11920            this.change_selections(Default::default(), window, cx, |s| {
11921                s.select(new_selections);
11922            })
11923        });
11924    }
11925
11926    pub fn move_line_down(
11927        &mut self,
11928        _: &MoveLineDown,
11929        window: &mut Window,
11930        cx: &mut Context<Self>,
11931    ) {
11932        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11933        if self.mode.is_single_line() {
11934            cx.propagate();
11935            return;
11936        }
11937
11938        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11939        let buffer = self.buffer.read(cx).snapshot(cx);
11940
11941        let mut edits = Vec::new();
11942        let mut unfold_ranges = Vec::new();
11943        let mut refold_creases = Vec::new();
11944
11945        let selections = self.selections.all::<Point>(&display_map);
11946        let mut selections = selections.iter().peekable();
11947        let mut contiguous_row_selections = Vec::new();
11948        let mut new_selections = Vec::new();
11949
11950        while let Some(selection) = selections.next() {
11951            // Find all the selections that span a contiguous row range
11952            let (start_row, end_row) = consume_contiguous_rows(
11953                &mut contiguous_row_selections,
11954                selection,
11955                &display_map,
11956                &mut selections,
11957            );
11958
11959            // Move the text spanned by the row range to be after the last line of the row range
11960            if end_row.0 <= buffer.max_point().row {
11961                let range_to_move =
11962                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11963                let insertion_point = display_map
11964                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11965                    .0;
11966
11967                // Don't move lines across excerpt boundaries
11968                if buffer
11969                    .excerpt_containing(range_to_move.start..insertion_point)
11970                    .is_some()
11971                {
11972                    let mut text = String::from("\n");
11973                    text.extend(buffer.text_for_range(range_to_move.clone()));
11974                    text.pop(); // Drop trailing newline
11975                    edits.push((
11976                        buffer.anchor_after(range_to_move.start)
11977                            ..buffer.anchor_before(range_to_move.end),
11978                        String::new(),
11979                    ));
11980                    let insertion_anchor = buffer.anchor_after(insertion_point);
11981                    edits.push((insertion_anchor..insertion_anchor, text));
11982
11983                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11984
11985                    // Move selections down
11986                    new_selections.extend(contiguous_row_selections.drain(..).map(
11987                        |mut selection| {
11988                            selection.start.row += row_delta;
11989                            selection.end.row += row_delta;
11990                            selection
11991                        },
11992                    ));
11993
11994                    // Move folds down
11995                    unfold_ranges.push(range_to_move.clone());
11996                    for fold in display_map.folds_in_range(
11997                        buffer.anchor_before(range_to_move.start)
11998                            ..buffer.anchor_after(range_to_move.end),
11999                    ) {
12000                        let mut start = fold.range.start.to_point(&buffer);
12001                        let mut end = fold.range.end.to_point(&buffer);
12002                        start.row += row_delta;
12003                        end.row += row_delta;
12004                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12005                    }
12006                }
12007            }
12008
12009            // If we didn't move line(s), preserve the existing selections
12010            new_selections.append(&mut contiguous_row_selections);
12011        }
12012
12013        self.transact(window, cx, |this, window, cx| {
12014            this.unfold_ranges(&unfold_ranges, true, true, cx);
12015            this.buffer.update(cx, |buffer, cx| {
12016                for (range, text) in edits {
12017                    buffer.edit([(range, text)], None, cx);
12018                }
12019            });
12020            this.fold_creases(refold_creases, true, window, cx);
12021            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12022        });
12023    }
12024
12025    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12026        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12027        let text_layout_details = &self.text_layout_details(window);
12028        self.transact(window, cx, |this, window, cx| {
12029            let edits = this.change_selections(Default::default(), window, cx, |s| {
12030                let mut edits: Vec<(Range<usize>, String)> = Default::default();
12031                s.move_with(|display_map, selection| {
12032                    if !selection.is_empty() {
12033                        return;
12034                    }
12035
12036                    let mut head = selection.head();
12037                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12038                    if head.column() == display_map.line_len(head.row()) {
12039                        transpose_offset = display_map
12040                            .buffer_snapshot()
12041                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12042                    }
12043
12044                    if transpose_offset == 0 {
12045                        return;
12046                    }
12047
12048                    *head.column_mut() += 1;
12049                    head = display_map.clip_point(head, Bias::Right);
12050                    let goal = SelectionGoal::HorizontalPosition(
12051                        display_map
12052                            .x_for_display_point(head, text_layout_details)
12053                            .into(),
12054                    );
12055                    selection.collapse_to(head, goal);
12056
12057                    let transpose_start = display_map
12058                        .buffer_snapshot()
12059                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12060                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12061                        let transpose_end = display_map
12062                            .buffer_snapshot()
12063                            .clip_offset(transpose_offset + 1, Bias::Right);
12064                        if let Some(ch) = display_map
12065                            .buffer_snapshot()
12066                            .chars_at(transpose_start)
12067                            .next()
12068                        {
12069                            edits.push((transpose_start..transpose_offset, String::new()));
12070                            edits.push((transpose_end..transpose_end, ch.to_string()));
12071                        }
12072                    }
12073                });
12074                edits
12075            });
12076            this.buffer
12077                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12078            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12079            this.change_selections(Default::default(), window, cx, |s| {
12080                s.select(selections);
12081            });
12082        });
12083    }
12084
12085    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12086        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12087        if self.mode.is_single_line() {
12088            cx.propagate();
12089            return;
12090        }
12091
12092        self.rewrap_impl(RewrapOptions::default(), cx)
12093    }
12094
12095    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12096        let buffer = self.buffer.read(cx).snapshot(cx);
12097        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12098
12099        #[derive(Clone, Debug, PartialEq)]
12100        enum CommentFormat {
12101            /// single line comment, with prefix for line
12102            Line(String),
12103            /// single line within a block comment, with prefix for line
12104            BlockLine(String),
12105            /// a single line of a block comment that includes the initial delimiter
12106            BlockCommentWithStart(BlockCommentConfig),
12107            /// a single line of a block comment that includes the ending delimiter
12108            BlockCommentWithEnd(BlockCommentConfig),
12109        }
12110
12111        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12112        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12113            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12114                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12115                .peekable();
12116
12117            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12118                row
12119            } else {
12120                return Vec::new();
12121            };
12122
12123            let language_settings = buffer.language_settings_at(selection.head(), cx);
12124            let language_scope = buffer.language_scope_at(selection.head());
12125
12126            let indent_and_prefix_for_row =
12127                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12128                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12129                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12130                        &language_scope
12131                    {
12132                        let indent_end = Point::new(row, indent.len);
12133                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12134                        let line_text_after_indent = buffer
12135                            .text_for_range(indent_end..line_end)
12136                            .collect::<String>();
12137
12138                        let is_within_comment_override = buffer
12139                            .language_scope_at(indent_end)
12140                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12141                        let comment_delimiters = if is_within_comment_override {
12142                            // we are within a comment syntax node, but we don't
12143                            // yet know what kind of comment: block, doc or line
12144                            match (
12145                                language_scope.documentation_comment(),
12146                                language_scope.block_comment(),
12147                            ) {
12148                                (Some(config), _) | (_, Some(config))
12149                                    if buffer.contains_str_at(indent_end, &config.start) =>
12150                                {
12151                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12152                                }
12153                                (Some(config), _) | (_, Some(config))
12154                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12155                                {
12156                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12157                                }
12158                                (Some(config), _) | (_, Some(config))
12159                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12160                                {
12161                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12162                                }
12163                                (_, _) => language_scope
12164                                    .line_comment_prefixes()
12165                                    .iter()
12166                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12167                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12168                            }
12169                        } else {
12170                            // we not in an overridden comment node, but we may
12171                            // be within a non-overridden line comment node
12172                            language_scope
12173                                .line_comment_prefixes()
12174                                .iter()
12175                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12176                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12177                        };
12178
12179                        let rewrap_prefix = language_scope
12180                            .rewrap_prefixes()
12181                            .iter()
12182                            .find_map(|prefix_regex| {
12183                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12184                                    if mat.start() == 0 {
12185                                        Some(mat.as_str().to_string())
12186                                    } else {
12187                                        None
12188                                    }
12189                                })
12190                            })
12191                            .flatten();
12192                        (comment_delimiters, rewrap_prefix)
12193                    } else {
12194                        (None, None)
12195                    };
12196                    (indent, comment_prefix, rewrap_prefix)
12197                };
12198
12199            let mut ranges = Vec::new();
12200            let from_empty_selection = selection.is_empty();
12201
12202            let mut current_range_start = first_row;
12203            let mut prev_row = first_row;
12204            let (
12205                mut current_range_indent,
12206                mut current_range_comment_delimiters,
12207                mut current_range_rewrap_prefix,
12208            ) = indent_and_prefix_for_row(first_row);
12209
12210            for row in non_blank_rows_iter.skip(1) {
12211                let has_paragraph_break = row > prev_row + 1;
12212
12213                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12214                    indent_and_prefix_for_row(row);
12215
12216                let has_indent_change = row_indent != current_range_indent;
12217                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12218
12219                let has_boundary_change = has_comment_change
12220                    || row_rewrap_prefix.is_some()
12221                    || (has_indent_change && current_range_comment_delimiters.is_some());
12222
12223                if has_paragraph_break || has_boundary_change {
12224                    ranges.push((
12225                        language_settings.clone(),
12226                        Point::new(current_range_start, 0)
12227                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12228                        current_range_indent,
12229                        current_range_comment_delimiters.clone(),
12230                        current_range_rewrap_prefix.clone(),
12231                        from_empty_selection,
12232                    ));
12233                    current_range_start = row;
12234                    current_range_indent = row_indent;
12235                    current_range_comment_delimiters = row_comment_delimiters;
12236                    current_range_rewrap_prefix = row_rewrap_prefix;
12237                }
12238                prev_row = row;
12239            }
12240
12241            ranges.push((
12242                language_settings.clone(),
12243                Point::new(current_range_start, 0)
12244                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12245                current_range_indent,
12246                current_range_comment_delimiters,
12247                current_range_rewrap_prefix,
12248                from_empty_selection,
12249            ));
12250
12251            ranges
12252        });
12253
12254        let mut edits = Vec::new();
12255        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12256
12257        for (
12258            language_settings,
12259            wrap_range,
12260            mut indent_size,
12261            comment_prefix,
12262            rewrap_prefix,
12263            from_empty_selection,
12264        ) in wrap_ranges
12265        {
12266            let mut start_row = wrap_range.start.row;
12267            let mut end_row = wrap_range.end.row;
12268
12269            // Skip selections that overlap with a range that has already been rewrapped.
12270            let selection_range = start_row..end_row;
12271            if rewrapped_row_ranges
12272                .iter()
12273                .any(|range| range.overlaps(&selection_range))
12274            {
12275                continue;
12276            }
12277
12278            let tab_size = language_settings.tab_size;
12279
12280            let (line_prefix, inside_comment) = match &comment_prefix {
12281                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12282                    (Some(prefix.as_str()), true)
12283                }
12284                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12285                    (Some(prefix.as_ref()), true)
12286                }
12287                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12288                    start: _,
12289                    end: _,
12290                    prefix,
12291                    tab_size,
12292                })) => {
12293                    indent_size.len += tab_size;
12294                    (Some(prefix.as_ref()), true)
12295                }
12296                None => (None, false),
12297            };
12298            let indent_prefix = indent_size.chars().collect::<String>();
12299            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12300
12301            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12302                RewrapBehavior::InComments => inside_comment,
12303                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12304                RewrapBehavior::Anywhere => true,
12305            };
12306
12307            let should_rewrap = options.override_language_settings
12308                || allow_rewrap_based_on_language
12309                || self.hard_wrap.is_some();
12310            if !should_rewrap {
12311                continue;
12312            }
12313
12314            if from_empty_selection {
12315                'expand_upwards: while start_row > 0 {
12316                    let prev_row = start_row - 1;
12317                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12318                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12319                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12320                    {
12321                        start_row = prev_row;
12322                    } else {
12323                        break 'expand_upwards;
12324                    }
12325                }
12326
12327                'expand_downwards: while end_row < buffer.max_point().row {
12328                    let next_row = end_row + 1;
12329                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12330                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12331                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12332                    {
12333                        end_row = next_row;
12334                    } else {
12335                        break 'expand_downwards;
12336                    }
12337                }
12338            }
12339
12340            let start = Point::new(start_row, 0);
12341            let start_offset = ToOffset::to_offset(&start, &buffer);
12342            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12343            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12344            let mut first_line_delimiter = None;
12345            let mut last_line_delimiter = None;
12346            let Some(lines_without_prefixes) = selection_text
12347                .lines()
12348                .enumerate()
12349                .map(|(ix, line)| {
12350                    let line_trimmed = line.trim_start();
12351                    if rewrap_prefix.is_some() && ix > 0 {
12352                        Ok(line_trimmed)
12353                    } else if let Some(
12354                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12355                            start,
12356                            prefix,
12357                            end,
12358                            tab_size,
12359                        })
12360                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12361                            start,
12362                            prefix,
12363                            end,
12364                            tab_size,
12365                        }),
12366                    ) = &comment_prefix
12367                    {
12368                        let line_trimmed = line_trimmed
12369                            .strip_prefix(start.as_ref())
12370                            .map(|s| {
12371                                let mut indent_size = indent_size;
12372                                indent_size.len -= tab_size;
12373                                let indent_prefix: String = indent_size.chars().collect();
12374                                first_line_delimiter = Some((indent_prefix, start));
12375                                s.trim_start()
12376                            })
12377                            .unwrap_or(line_trimmed);
12378                        let line_trimmed = line_trimmed
12379                            .strip_suffix(end.as_ref())
12380                            .map(|s| {
12381                                last_line_delimiter = Some(end);
12382                                s.trim_end()
12383                            })
12384                            .unwrap_or(line_trimmed);
12385                        let line_trimmed = line_trimmed
12386                            .strip_prefix(prefix.as_ref())
12387                            .unwrap_or(line_trimmed);
12388                        Ok(line_trimmed)
12389                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12390                        line_trimmed.strip_prefix(prefix).with_context(|| {
12391                            format!("line did not start with prefix {prefix:?}: {line:?}")
12392                        })
12393                    } else {
12394                        line_trimmed
12395                            .strip_prefix(&line_prefix.trim_start())
12396                            .with_context(|| {
12397                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12398                            })
12399                    }
12400                })
12401                .collect::<Result<Vec<_>, _>>()
12402                .log_err()
12403            else {
12404                continue;
12405            };
12406
12407            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12408                buffer
12409                    .language_settings_at(Point::new(start_row, 0), cx)
12410                    .preferred_line_length as usize
12411            });
12412
12413            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12414                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12415            } else {
12416                line_prefix.clone()
12417            };
12418
12419            let wrapped_text = {
12420                let mut wrapped_text = wrap_with_prefix(
12421                    line_prefix,
12422                    subsequent_lines_prefix,
12423                    lines_without_prefixes.join("\n"),
12424                    wrap_column,
12425                    tab_size,
12426                    options.preserve_existing_whitespace,
12427                );
12428
12429                if let Some((indent, delimiter)) = first_line_delimiter {
12430                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12431                }
12432                if let Some(last_line) = last_line_delimiter {
12433                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12434                }
12435
12436                wrapped_text
12437            };
12438
12439            // TODO: should always use char-based diff while still supporting cursor behavior that
12440            // matches vim.
12441            let mut diff_options = DiffOptions::default();
12442            if options.override_language_settings {
12443                diff_options.max_word_diff_len = 0;
12444                diff_options.max_word_diff_line_count = 0;
12445            } else {
12446                diff_options.max_word_diff_len = usize::MAX;
12447                diff_options.max_word_diff_line_count = usize::MAX;
12448            }
12449
12450            for (old_range, new_text) in
12451                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12452            {
12453                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12454                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12455                edits.push((edit_start..edit_end, new_text));
12456            }
12457
12458            rewrapped_row_ranges.push(start_row..=end_row);
12459        }
12460
12461        self.buffer
12462            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12463    }
12464
12465    pub fn cut_common(
12466        &mut self,
12467        cut_no_selection_line: bool,
12468        window: &mut Window,
12469        cx: &mut Context<Self>,
12470    ) -> ClipboardItem {
12471        let mut text = String::new();
12472        let buffer = self.buffer.read(cx).snapshot(cx);
12473        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12474        let mut clipboard_selections = Vec::with_capacity(selections.len());
12475        {
12476            let max_point = buffer.max_point();
12477            let mut is_first = true;
12478            for selection in &mut selections {
12479                let is_entire_line =
12480                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12481                if is_entire_line {
12482                    selection.start = Point::new(selection.start.row, 0);
12483                    if !selection.is_empty() && selection.end.column == 0 {
12484                        selection.end = cmp::min(max_point, selection.end);
12485                    } else {
12486                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12487                    }
12488                    selection.goal = SelectionGoal::None;
12489                }
12490                if is_first {
12491                    is_first = false;
12492                } else {
12493                    text += "\n";
12494                }
12495                let mut len = 0;
12496                for chunk in buffer.text_for_range(selection.start..selection.end) {
12497                    text.push_str(chunk);
12498                    len += chunk.len();
12499                }
12500                clipboard_selections.push(ClipboardSelection {
12501                    len,
12502                    is_entire_line,
12503                    first_line_indent: buffer
12504                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12505                        .len,
12506                });
12507            }
12508        }
12509
12510        self.transact(window, cx, |this, window, cx| {
12511            this.change_selections(Default::default(), window, cx, |s| {
12512                s.select(selections);
12513            });
12514            this.insert("", window, cx);
12515        });
12516        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12517    }
12518
12519    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12520        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12521        let item = self.cut_common(true, window, cx);
12522        cx.write_to_clipboard(item);
12523    }
12524
12525    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12526        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12527        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12528            s.move_with(|snapshot, sel| {
12529                if sel.is_empty() {
12530                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12531                }
12532                if sel.is_empty() {
12533                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12534                }
12535            });
12536        });
12537        let item = self.cut_common(false, window, cx);
12538        cx.set_global(KillRing(item))
12539    }
12540
12541    pub fn kill_ring_yank(
12542        &mut self,
12543        _: &KillRingYank,
12544        window: &mut Window,
12545        cx: &mut Context<Self>,
12546    ) {
12547        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12548        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12549            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12550                (kill_ring.text().to_string(), kill_ring.metadata_json())
12551            } else {
12552                return;
12553            }
12554        } else {
12555            return;
12556        };
12557        self.do_paste(&text, metadata, false, window, cx);
12558    }
12559
12560    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12561        self.do_copy(true, cx);
12562    }
12563
12564    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12565        self.do_copy(false, cx);
12566    }
12567
12568    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12569        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12570        let buffer = self.buffer.read(cx).read(cx);
12571        let mut text = String::new();
12572
12573        let mut clipboard_selections = Vec::with_capacity(selections.len());
12574        {
12575            let max_point = buffer.max_point();
12576            let mut is_first = true;
12577            for selection in &selections {
12578                let mut start = selection.start;
12579                let mut end = selection.end;
12580                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12581                let mut add_trailing_newline = false;
12582                if is_entire_line {
12583                    start = Point::new(start.row, 0);
12584                    let next_line_start = Point::new(end.row + 1, 0);
12585                    if next_line_start <= max_point {
12586                        end = next_line_start;
12587                    } else {
12588                        // We're on the last line without a trailing newline.
12589                        // Copy to the end of the line and add a newline afterwards.
12590                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12591                        add_trailing_newline = true;
12592                    }
12593                }
12594
12595                let mut trimmed_selections = Vec::new();
12596                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12597                    let row = MultiBufferRow(start.row);
12598                    let first_indent = buffer.indent_size_for_line(row);
12599                    if first_indent.len == 0 || start.column > first_indent.len {
12600                        trimmed_selections.push(start..end);
12601                    } else {
12602                        trimmed_selections.push(
12603                            Point::new(row.0, first_indent.len)
12604                                ..Point::new(row.0, buffer.line_len(row)),
12605                        );
12606                        for row in start.row + 1..=end.row {
12607                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12608                            if row == end.row {
12609                                line_len = end.column;
12610                            }
12611                            if line_len == 0 {
12612                                trimmed_selections
12613                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12614                                continue;
12615                            }
12616                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12617                            if row_indent_size.len >= first_indent.len {
12618                                trimmed_selections.push(
12619                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12620                                );
12621                            } else {
12622                                trimmed_selections.clear();
12623                                trimmed_selections.push(start..end);
12624                                break;
12625                            }
12626                        }
12627                    }
12628                } else {
12629                    trimmed_selections.push(start..end);
12630                }
12631
12632                for trimmed_range in trimmed_selections {
12633                    if is_first {
12634                        is_first = false;
12635                    } else {
12636                        text += "\n";
12637                    }
12638                    let mut len = 0;
12639                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12640                        text.push_str(chunk);
12641                        len += chunk.len();
12642                    }
12643                    if add_trailing_newline {
12644                        text.push('\n');
12645                        len += 1;
12646                    }
12647                    clipboard_selections.push(ClipboardSelection {
12648                        len,
12649                        is_entire_line,
12650                        first_line_indent: buffer
12651                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12652                            .len,
12653                    });
12654                }
12655            }
12656        }
12657
12658        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12659            text,
12660            clipboard_selections,
12661        ));
12662    }
12663
12664    pub fn do_paste(
12665        &mut self,
12666        text: &String,
12667        clipboard_selections: Option<Vec<ClipboardSelection>>,
12668        handle_entire_lines: bool,
12669        window: &mut Window,
12670        cx: &mut Context<Self>,
12671    ) {
12672        if self.read_only(cx) {
12673            return;
12674        }
12675
12676        let clipboard_text = Cow::Borrowed(text.as_str());
12677
12678        self.transact(window, cx, |this, window, cx| {
12679            let had_active_edit_prediction = this.has_active_edit_prediction();
12680            let display_map = this.display_snapshot(cx);
12681            let old_selections = this.selections.all::<usize>(&display_map);
12682            let cursor_offset = this.selections.last::<usize>(&display_map).head();
12683
12684            if let Some(mut clipboard_selections) = clipboard_selections {
12685                let all_selections_were_entire_line =
12686                    clipboard_selections.iter().all(|s| s.is_entire_line);
12687                let first_selection_indent_column =
12688                    clipboard_selections.first().map(|s| s.first_line_indent);
12689                if clipboard_selections.len() != old_selections.len() {
12690                    clipboard_selections.drain(..);
12691                }
12692                let mut auto_indent_on_paste = true;
12693
12694                this.buffer.update(cx, |buffer, cx| {
12695                    let snapshot = buffer.read(cx);
12696                    auto_indent_on_paste = snapshot
12697                        .language_settings_at(cursor_offset, cx)
12698                        .auto_indent_on_paste;
12699
12700                    let mut start_offset = 0;
12701                    let mut edits = Vec::new();
12702                    let mut original_indent_columns = Vec::new();
12703                    for (ix, selection) in old_selections.iter().enumerate() {
12704                        let to_insert;
12705                        let entire_line;
12706                        let original_indent_column;
12707                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12708                            let end_offset = start_offset + clipboard_selection.len;
12709                            to_insert = &clipboard_text[start_offset..end_offset];
12710                            entire_line = clipboard_selection.is_entire_line;
12711                            start_offset = end_offset + 1;
12712                            original_indent_column = Some(clipboard_selection.first_line_indent);
12713                        } else {
12714                            to_insert = &*clipboard_text;
12715                            entire_line = all_selections_were_entire_line;
12716                            original_indent_column = first_selection_indent_column
12717                        }
12718
12719                        let (range, to_insert) =
12720                            if selection.is_empty() && handle_entire_lines && entire_line {
12721                                // If the corresponding selection was empty when this slice of the
12722                                // clipboard text was written, then the entire line containing the
12723                                // selection was copied. If this selection is also currently empty,
12724                                // then paste the line before the current line of the buffer.
12725                                let column = selection.start.to_point(&snapshot).column as usize;
12726                                let line_start = selection.start - column;
12727                                (line_start..line_start, Cow::Borrowed(to_insert))
12728                            } else {
12729                                let language = snapshot.language_at(selection.head());
12730                                let range = selection.range();
12731                                if let Some(language) = language
12732                                    && language.name() == "Markdown".into()
12733                                {
12734                                    edit_for_markdown_paste(
12735                                        &snapshot,
12736                                        range,
12737                                        to_insert,
12738                                        url::Url::parse(to_insert).ok(),
12739                                    )
12740                                } else {
12741                                    (range, Cow::Borrowed(to_insert))
12742                                }
12743                            };
12744
12745                        edits.push((range, to_insert));
12746                        original_indent_columns.push(original_indent_column);
12747                    }
12748                    drop(snapshot);
12749
12750                    buffer.edit(
12751                        edits,
12752                        if auto_indent_on_paste {
12753                            Some(AutoindentMode::Block {
12754                                original_indent_columns,
12755                            })
12756                        } else {
12757                            None
12758                        },
12759                        cx,
12760                    );
12761                });
12762
12763                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12764                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12765            } else {
12766                let url = url::Url::parse(&clipboard_text).ok();
12767
12768                let auto_indent_mode = if !clipboard_text.is_empty() {
12769                    Some(AutoindentMode::Block {
12770                        original_indent_columns: Vec::new(),
12771                    })
12772                } else {
12773                    None
12774                };
12775
12776                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12777                    let snapshot = buffer.snapshot(cx);
12778
12779                    let anchors = old_selections
12780                        .iter()
12781                        .map(|s| {
12782                            let anchor = snapshot.anchor_after(s.head());
12783                            s.map(|_| anchor)
12784                        })
12785                        .collect::<Vec<_>>();
12786
12787                    let mut edits = Vec::new();
12788
12789                    for selection in old_selections.iter() {
12790                        let language = snapshot.language_at(selection.head());
12791                        let range = selection.range();
12792
12793                        let (edit_range, edit_text) = if let Some(language) = language
12794                            && language.name() == "Markdown".into()
12795                        {
12796                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12797                        } else {
12798                            (range, clipboard_text.clone())
12799                        };
12800
12801                        edits.push((edit_range, edit_text));
12802                    }
12803
12804                    drop(snapshot);
12805                    buffer.edit(edits, auto_indent_mode, cx);
12806
12807                    anchors
12808                });
12809
12810                this.change_selections(Default::default(), window, cx, |s| {
12811                    s.select_anchors(selection_anchors);
12812                });
12813            }
12814
12815            let trigger_in_words =
12816                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12817
12818            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12819        });
12820    }
12821
12822    pub fn diff_clipboard_with_selection(
12823        &mut self,
12824        _: &DiffClipboardWithSelection,
12825        window: &mut Window,
12826        cx: &mut Context<Self>,
12827    ) {
12828        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
12829
12830        if selections.is_empty() {
12831            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12832            return;
12833        };
12834
12835        let clipboard_text = match cx.read_from_clipboard() {
12836            Some(item) => match item.entries().first() {
12837                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12838                _ => None,
12839            },
12840            None => None,
12841        };
12842
12843        let Some(clipboard_text) = clipboard_text else {
12844            log::warn!("Clipboard doesn't contain text.");
12845            return;
12846        };
12847
12848        window.dispatch_action(
12849            Box::new(DiffClipboardWithSelectionData {
12850                clipboard_text,
12851                editor: cx.entity(),
12852            }),
12853            cx,
12854        );
12855    }
12856
12857    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12858        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12859        if let Some(item) = cx.read_from_clipboard() {
12860            let entries = item.entries();
12861
12862            match entries.first() {
12863                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12864                // of all the pasted entries.
12865                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12866                    .do_paste(
12867                        clipboard_string.text(),
12868                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12869                        true,
12870                        window,
12871                        cx,
12872                    ),
12873                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12874            }
12875        }
12876    }
12877
12878    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12879        if self.read_only(cx) {
12880            return;
12881        }
12882
12883        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12884
12885        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12886            if let Some((selections, _)) =
12887                self.selection_history.transaction(transaction_id).cloned()
12888            {
12889                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12890                    s.select_anchors(selections.to_vec());
12891                });
12892            } else {
12893                log::error!(
12894                    "No entry in selection_history found for undo. \
12895                     This may correspond to a bug where undo does not update the selection. \
12896                     If this is occurring, please add details to \
12897                     https://github.com/zed-industries/zed/issues/22692"
12898                );
12899            }
12900            self.request_autoscroll(Autoscroll::fit(), cx);
12901            self.unmark_text(window, cx);
12902            self.refresh_edit_prediction(true, false, window, cx);
12903            cx.emit(EditorEvent::Edited { transaction_id });
12904            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12905        }
12906    }
12907
12908    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12909        if self.read_only(cx) {
12910            return;
12911        }
12912
12913        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12914
12915        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12916            if let Some((_, Some(selections))) =
12917                self.selection_history.transaction(transaction_id).cloned()
12918            {
12919                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12920                    s.select_anchors(selections.to_vec());
12921                });
12922            } else {
12923                log::error!(
12924                    "No entry in selection_history found for redo. \
12925                     This may correspond to a bug where undo does not update the selection. \
12926                     If this is occurring, please add details to \
12927                     https://github.com/zed-industries/zed/issues/22692"
12928                );
12929            }
12930            self.request_autoscroll(Autoscroll::fit(), cx);
12931            self.unmark_text(window, cx);
12932            self.refresh_edit_prediction(true, false, window, cx);
12933            cx.emit(EditorEvent::Edited { transaction_id });
12934        }
12935    }
12936
12937    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12938        self.buffer
12939            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12940    }
12941
12942    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12943        self.buffer
12944            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12945    }
12946
12947    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12948        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12949        self.change_selections(Default::default(), window, cx, |s| {
12950            s.move_with(|map, selection| {
12951                let cursor = if selection.is_empty() {
12952                    movement::left(map, selection.start)
12953                } else {
12954                    selection.start
12955                };
12956                selection.collapse_to(cursor, SelectionGoal::None);
12957            });
12958        })
12959    }
12960
12961    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12962        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12963        self.change_selections(Default::default(), window, cx, |s| {
12964            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12965        })
12966    }
12967
12968    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12969        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12970        self.change_selections(Default::default(), window, cx, |s| {
12971            s.move_with(|map, selection| {
12972                let cursor = if selection.is_empty() {
12973                    movement::right(map, selection.end)
12974                } else {
12975                    selection.end
12976                };
12977                selection.collapse_to(cursor, SelectionGoal::None)
12978            });
12979        })
12980    }
12981
12982    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12983        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12984        self.change_selections(Default::default(), window, cx, |s| {
12985            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12986        });
12987    }
12988
12989    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12990        if self.take_rename(true, window, cx).is_some() {
12991            return;
12992        }
12993
12994        if self.mode.is_single_line() {
12995            cx.propagate();
12996            return;
12997        }
12998
12999        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13000
13001        let text_layout_details = &self.text_layout_details(window);
13002        let selection_count = self.selections.count();
13003        let first_selection = self.selections.first_anchor();
13004
13005        self.change_selections(Default::default(), window, cx, |s| {
13006            s.move_with(|map, selection| {
13007                if !selection.is_empty() {
13008                    selection.goal = SelectionGoal::None;
13009                }
13010                let (cursor, goal) = movement::up(
13011                    map,
13012                    selection.start,
13013                    selection.goal,
13014                    false,
13015                    text_layout_details,
13016                );
13017                selection.collapse_to(cursor, goal);
13018            });
13019        });
13020
13021        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13022        {
13023            cx.propagate();
13024        }
13025    }
13026
13027    pub fn move_up_by_lines(
13028        &mut self,
13029        action: &MoveUpByLines,
13030        window: &mut Window,
13031        cx: &mut Context<Self>,
13032    ) {
13033        if self.take_rename(true, window, cx).is_some() {
13034            return;
13035        }
13036
13037        if self.mode.is_single_line() {
13038            cx.propagate();
13039            return;
13040        }
13041
13042        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13043
13044        let text_layout_details = &self.text_layout_details(window);
13045
13046        self.change_selections(Default::default(), window, cx, |s| {
13047            s.move_with(|map, selection| {
13048                if !selection.is_empty() {
13049                    selection.goal = SelectionGoal::None;
13050                }
13051                let (cursor, goal) = movement::up_by_rows(
13052                    map,
13053                    selection.start,
13054                    action.lines,
13055                    selection.goal,
13056                    false,
13057                    text_layout_details,
13058                );
13059                selection.collapse_to(cursor, goal);
13060            });
13061        })
13062    }
13063
13064    pub fn move_down_by_lines(
13065        &mut self,
13066        action: &MoveDownByLines,
13067        window: &mut Window,
13068        cx: &mut Context<Self>,
13069    ) {
13070        if self.take_rename(true, window, cx).is_some() {
13071            return;
13072        }
13073
13074        if self.mode.is_single_line() {
13075            cx.propagate();
13076            return;
13077        }
13078
13079        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13080
13081        let text_layout_details = &self.text_layout_details(window);
13082
13083        self.change_selections(Default::default(), window, cx, |s| {
13084            s.move_with(|map, selection| {
13085                if !selection.is_empty() {
13086                    selection.goal = SelectionGoal::None;
13087                }
13088                let (cursor, goal) = movement::down_by_rows(
13089                    map,
13090                    selection.start,
13091                    action.lines,
13092                    selection.goal,
13093                    false,
13094                    text_layout_details,
13095                );
13096                selection.collapse_to(cursor, goal);
13097            });
13098        })
13099    }
13100
13101    pub fn select_down_by_lines(
13102        &mut self,
13103        action: &SelectDownByLines,
13104        window: &mut Window,
13105        cx: &mut Context<Self>,
13106    ) {
13107        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13108        let text_layout_details = &self.text_layout_details(window);
13109        self.change_selections(Default::default(), window, cx, |s| {
13110            s.move_heads_with(|map, head, goal| {
13111                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13112            })
13113        })
13114    }
13115
13116    pub fn select_up_by_lines(
13117        &mut self,
13118        action: &SelectUpByLines,
13119        window: &mut Window,
13120        cx: &mut Context<Self>,
13121    ) {
13122        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13123        let text_layout_details = &self.text_layout_details(window);
13124        self.change_selections(Default::default(), window, cx, |s| {
13125            s.move_heads_with(|map, head, goal| {
13126                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13127            })
13128        })
13129    }
13130
13131    pub fn select_page_up(
13132        &mut self,
13133        _: &SelectPageUp,
13134        window: &mut Window,
13135        cx: &mut Context<Self>,
13136    ) {
13137        let Some(row_count) = self.visible_row_count() else {
13138            return;
13139        };
13140
13141        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13142
13143        let text_layout_details = &self.text_layout_details(window);
13144
13145        self.change_selections(Default::default(), window, cx, |s| {
13146            s.move_heads_with(|map, head, goal| {
13147                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13148            })
13149        })
13150    }
13151
13152    pub fn move_page_up(
13153        &mut self,
13154        action: &MovePageUp,
13155        window: &mut Window,
13156        cx: &mut Context<Self>,
13157    ) {
13158        if self.take_rename(true, window, cx).is_some() {
13159            return;
13160        }
13161
13162        if self
13163            .context_menu
13164            .borrow_mut()
13165            .as_mut()
13166            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13167            .unwrap_or(false)
13168        {
13169            return;
13170        }
13171
13172        if matches!(self.mode, EditorMode::SingleLine) {
13173            cx.propagate();
13174            return;
13175        }
13176
13177        let Some(row_count) = self.visible_row_count() else {
13178            return;
13179        };
13180
13181        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13182
13183        let effects = if action.center_cursor {
13184            SelectionEffects::scroll(Autoscroll::center())
13185        } else {
13186            SelectionEffects::default()
13187        };
13188
13189        let text_layout_details = &self.text_layout_details(window);
13190
13191        self.change_selections(effects, window, cx, |s| {
13192            s.move_with(|map, selection| {
13193                if !selection.is_empty() {
13194                    selection.goal = SelectionGoal::None;
13195                }
13196                let (cursor, goal) = movement::up_by_rows(
13197                    map,
13198                    selection.end,
13199                    row_count,
13200                    selection.goal,
13201                    false,
13202                    text_layout_details,
13203                );
13204                selection.collapse_to(cursor, goal);
13205            });
13206        });
13207    }
13208
13209    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13210        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13211        let text_layout_details = &self.text_layout_details(window);
13212        self.change_selections(Default::default(), window, cx, |s| {
13213            s.move_heads_with(|map, head, goal| {
13214                movement::up(map, head, goal, false, text_layout_details)
13215            })
13216        })
13217    }
13218
13219    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13220        self.take_rename(true, window, cx);
13221
13222        if self.mode.is_single_line() {
13223            cx.propagate();
13224            return;
13225        }
13226
13227        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13228
13229        let text_layout_details = &self.text_layout_details(window);
13230        let selection_count = self.selections.count();
13231        let first_selection = self.selections.first_anchor();
13232
13233        self.change_selections(Default::default(), window, cx, |s| {
13234            s.move_with(|map, selection| {
13235                if !selection.is_empty() {
13236                    selection.goal = SelectionGoal::None;
13237                }
13238                let (cursor, goal) = movement::down(
13239                    map,
13240                    selection.end,
13241                    selection.goal,
13242                    false,
13243                    text_layout_details,
13244                );
13245                selection.collapse_to(cursor, goal);
13246            });
13247        });
13248
13249        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13250        {
13251            cx.propagate();
13252        }
13253    }
13254
13255    pub fn select_page_down(
13256        &mut self,
13257        _: &SelectPageDown,
13258        window: &mut Window,
13259        cx: &mut Context<Self>,
13260    ) {
13261        let Some(row_count) = self.visible_row_count() else {
13262            return;
13263        };
13264
13265        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13266
13267        let text_layout_details = &self.text_layout_details(window);
13268
13269        self.change_selections(Default::default(), window, cx, |s| {
13270            s.move_heads_with(|map, head, goal| {
13271                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13272            })
13273        })
13274    }
13275
13276    pub fn move_page_down(
13277        &mut self,
13278        action: &MovePageDown,
13279        window: &mut Window,
13280        cx: &mut Context<Self>,
13281    ) {
13282        if self.take_rename(true, window, cx).is_some() {
13283            return;
13284        }
13285
13286        if self
13287            .context_menu
13288            .borrow_mut()
13289            .as_mut()
13290            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13291            .unwrap_or(false)
13292        {
13293            return;
13294        }
13295
13296        if matches!(self.mode, EditorMode::SingleLine) {
13297            cx.propagate();
13298            return;
13299        }
13300
13301        let Some(row_count) = self.visible_row_count() else {
13302            return;
13303        };
13304
13305        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13306
13307        let effects = if action.center_cursor {
13308            SelectionEffects::scroll(Autoscroll::center())
13309        } else {
13310            SelectionEffects::default()
13311        };
13312
13313        let text_layout_details = &self.text_layout_details(window);
13314        self.change_selections(effects, window, cx, |s| {
13315            s.move_with(|map, selection| {
13316                if !selection.is_empty() {
13317                    selection.goal = SelectionGoal::None;
13318                }
13319                let (cursor, goal) = movement::down_by_rows(
13320                    map,
13321                    selection.end,
13322                    row_count,
13323                    selection.goal,
13324                    false,
13325                    text_layout_details,
13326                );
13327                selection.collapse_to(cursor, goal);
13328            });
13329        });
13330    }
13331
13332    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13333        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13334        let text_layout_details = &self.text_layout_details(window);
13335        self.change_selections(Default::default(), window, cx, |s| {
13336            s.move_heads_with(|map, head, goal| {
13337                movement::down(map, head, goal, false, text_layout_details)
13338            })
13339        });
13340    }
13341
13342    pub fn context_menu_first(
13343        &mut self,
13344        _: &ContextMenuFirst,
13345        window: &mut Window,
13346        cx: &mut Context<Self>,
13347    ) {
13348        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13349            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13350        }
13351    }
13352
13353    pub fn context_menu_prev(
13354        &mut self,
13355        _: &ContextMenuPrevious,
13356        window: &mut Window,
13357        cx: &mut Context<Self>,
13358    ) {
13359        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13360            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13361        }
13362    }
13363
13364    pub fn context_menu_next(
13365        &mut self,
13366        _: &ContextMenuNext,
13367        window: &mut Window,
13368        cx: &mut Context<Self>,
13369    ) {
13370        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13371            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13372        }
13373    }
13374
13375    pub fn context_menu_last(
13376        &mut self,
13377        _: &ContextMenuLast,
13378        window: &mut Window,
13379        cx: &mut Context<Self>,
13380    ) {
13381        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13382            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13383        }
13384    }
13385
13386    pub fn signature_help_prev(
13387        &mut self,
13388        _: &SignatureHelpPrevious,
13389        _: &mut Window,
13390        cx: &mut Context<Self>,
13391    ) {
13392        if let Some(popover) = self.signature_help_state.popover_mut() {
13393            if popover.current_signature == 0 {
13394                popover.current_signature = popover.signatures.len() - 1;
13395            } else {
13396                popover.current_signature -= 1;
13397            }
13398            cx.notify();
13399        }
13400    }
13401
13402    pub fn signature_help_next(
13403        &mut self,
13404        _: &SignatureHelpNext,
13405        _: &mut Window,
13406        cx: &mut Context<Self>,
13407    ) {
13408        if let Some(popover) = self.signature_help_state.popover_mut() {
13409            if popover.current_signature + 1 == popover.signatures.len() {
13410                popover.current_signature = 0;
13411            } else {
13412                popover.current_signature += 1;
13413            }
13414            cx.notify();
13415        }
13416    }
13417
13418    pub fn move_to_previous_word_start(
13419        &mut self,
13420        _: &MoveToPreviousWordStart,
13421        window: &mut Window,
13422        cx: &mut Context<Self>,
13423    ) {
13424        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13425        self.change_selections(Default::default(), window, cx, |s| {
13426            s.move_cursors_with(|map, head, _| {
13427                (
13428                    movement::previous_word_start(map, head),
13429                    SelectionGoal::None,
13430                )
13431            });
13432        })
13433    }
13434
13435    pub fn move_to_previous_subword_start(
13436        &mut self,
13437        _: &MoveToPreviousSubwordStart,
13438        window: &mut Window,
13439        cx: &mut Context<Self>,
13440    ) {
13441        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13442        self.change_selections(Default::default(), window, cx, |s| {
13443            s.move_cursors_with(|map, head, _| {
13444                (
13445                    movement::previous_subword_start(map, head),
13446                    SelectionGoal::None,
13447                )
13448            });
13449        })
13450    }
13451
13452    pub fn select_to_previous_word_start(
13453        &mut self,
13454        _: &SelectToPreviousWordStart,
13455        window: &mut Window,
13456        cx: &mut Context<Self>,
13457    ) {
13458        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13459        self.change_selections(Default::default(), window, cx, |s| {
13460            s.move_heads_with(|map, head, _| {
13461                (
13462                    movement::previous_word_start(map, head),
13463                    SelectionGoal::None,
13464                )
13465            });
13466        })
13467    }
13468
13469    pub fn select_to_previous_subword_start(
13470        &mut self,
13471        _: &SelectToPreviousSubwordStart,
13472        window: &mut Window,
13473        cx: &mut Context<Self>,
13474    ) {
13475        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13476        self.change_selections(Default::default(), window, cx, |s| {
13477            s.move_heads_with(|map, head, _| {
13478                (
13479                    movement::previous_subword_start(map, head),
13480                    SelectionGoal::None,
13481                )
13482            });
13483        })
13484    }
13485
13486    pub fn delete_to_previous_word_start(
13487        &mut self,
13488        action: &DeleteToPreviousWordStart,
13489        window: &mut Window,
13490        cx: &mut Context<Self>,
13491    ) {
13492        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13493        self.transact(window, cx, |this, window, cx| {
13494            this.select_autoclose_pair(window, cx);
13495            this.change_selections(Default::default(), window, cx, |s| {
13496                s.move_with(|map, selection| {
13497                    if selection.is_empty() {
13498                        let mut cursor = if action.ignore_newlines {
13499                            movement::previous_word_start(map, selection.head())
13500                        } else {
13501                            movement::previous_word_start_or_newline(map, selection.head())
13502                        };
13503                        cursor = movement::adjust_greedy_deletion(
13504                            map,
13505                            selection.head(),
13506                            cursor,
13507                            action.ignore_brackets,
13508                        );
13509                        selection.set_head(cursor, SelectionGoal::None);
13510                    }
13511                });
13512            });
13513            this.insert("", window, cx);
13514        });
13515    }
13516
13517    pub fn delete_to_previous_subword_start(
13518        &mut self,
13519        _: &DeleteToPreviousSubwordStart,
13520        window: &mut Window,
13521        cx: &mut Context<Self>,
13522    ) {
13523        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13524        self.transact(window, cx, |this, window, cx| {
13525            this.select_autoclose_pair(window, cx);
13526            this.change_selections(Default::default(), window, cx, |s| {
13527                s.move_with(|map, selection| {
13528                    if selection.is_empty() {
13529                        let mut cursor = movement::previous_subword_start(map, selection.head());
13530                        cursor =
13531                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13532                        selection.set_head(cursor, SelectionGoal::None);
13533                    }
13534                });
13535            });
13536            this.insert("", window, cx);
13537        });
13538    }
13539
13540    pub fn move_to_next_word_end(
13541        &mut self,
13542        _: &MoveToNextWordEnd,
13543        window: &mut Window,
13544        cx: &mut Context<Self>,
13545    ) {
13546        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13547        self.change_selections(Default::default(), window, cx, |s| {
13548            s.move_cursors_with(|map, head, _| {
13549                (movement::next_word_end(map, head), SelectionGoal::None)
13550            });
13551        })
13552    }
13553
13554    pub fn move_to_next_subword_end(
13555        &mut self,
13556        _: &MoveToNextSubwordEnd,
13557        window: &mut Window,
13558        cx: &mut Context<Self>,
13559    ) {
13560        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13561        self.change_selections(Default::default(), window, cx, |s| {
13562            s.move_cursors_with(|map, head, _| {
13563                (movement::next_subword_end(map, head), SelectionGoal::None)
13564            });
13565        })
13566    }
13567
13568    pub fn select_to_next_word_end(
13569        &mut self,
13570        _: &SelectToNextWordEnd,
13571        window: &mut Window,
13572        cx: &mut Context<Self>,
13573    ) {
13574        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13575        self.change_selections(Default::default(), window, cx, |s| {
13576            s.move_heads_with(|map, head, _| {
13577                (movement::next_word_end(map, head), SelectionGoal::None)
13578            });
13579        })
13580    }
13581
13582    pub fn select_to_next_subword_end(
13583        &mut self,
13584        _: &SelectToNextSubwordEnd,
13585        window: &mut Window,
13586        cx: &mut Context<Self>,
13587    ) {
13588        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13589        self.change_selections(Default::default(), window, cx, |s| {
13590            s.move_heads_with(|map, head, _| {
13591                (movement::next_subword_end(map, head), SelectionGoal::None)
13592            });
13593        })
13594    }
13595
13596    pub fn delete_to_next_word_end(
13597        &mut self,
13598        action: &DeleteToNextWordEnd,
13599        window: &mut Window,
13600        cx: &mut Context<Self>,
13601    ) {
13602        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13603        self.transact(window, cx, |this, window, cx| {
13604            this.change_selections(Default::default(), window, cx, |s| {
13605                s.move_with(|map, selection| {
13606                    if selection.is_empty() {
13607                        let mut cursor = if action.ignore_newlines {
13608                            movement::next_word_end(map, selection.head())
13609                        } else {
13610                            movement::next_word_end_or_newline(map, selection.head())
13611                        };
13612                        cursor = movement::adjust_greedy_deletion(
13613                            map,
13614                            selection.head(),
13615                            cursor,
13616                            action.ignore_brackets,
13617                        );
13618                        selection.set_head(cursor, SelectionGoal::None);
13619                    }
13620                });
13621            });
13622            this.insert("", window, cx);
13623        });
13624    }
13625
13626    pub fn delete_to_next_subword_end(
13627        &mut self,
13628        _: &DeleteToNextSubwordEnd,
13629        window: &mut Window,
13630        cx: &mut Context<Self>,
13631    ) {
13632        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13633        self.transact(window, cx, |this, window, cx| {
13634            this.change_selections(Default::default(), window, cx, |s| {
13635                s.move_with(|map, selection| {
13636                    if selection.is_empty() {
13637                        let mut cursor = movement::next_subword_end(map, selection.head());
13638                        cursor =
13639                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13640                        selection.set_head(cursor, SelectionGoal::None);
13641                    }
13642                });
13643            });
13644            this.insert("", window, cx);
13645        });
13646    }
13647
13648    pub fn move_to_beginning_of_line(
13649        &mut self,
13650        action: &MoveToBeginningOfLine,
13651        window: &mut Window,
13652        cx: &mut Context<Self>,
13653    ) {
13654        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13655        self.change_selections(Default::default(), window, cx, |s| {
13656            s.move_cursors_with(|map, head, _| {
13657                (
13658                    movement::indented_line_beginning(
13659                        map,
13660                        head,
13661                        action.stop_at_soft_wraps,
13662                        action.stop_at_indent,
13663                    ),
13664                    SelectionGoal::None,
13665                )
13666            });
13667        })
13668    }
13669
13670    pub fn select_to_beginning_of_line(
13671        &mut self,
13672        action: &SelectToBeginningOfLine,
13673        window: &mut Window,
13674        cx: &mut Context<Self>,
13675    ) {
13676        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13677        self.change_selections(Default::default(), window, cx, |s| {
13678            s.move_heads_with(|map, head, _| {
13679                (
13680                    movement::indented_line_beginning(
13681                        map,
13682                        head,
13683                        action.stop_at_soft_wraps,
13684                        action.stop_at_indent,
13685                    ),
13686                    SelectionGoal::None,
13687                )
13688            });
13689        });
13690    }
13691
13692    pub fn delete_to_beginning_of_line(
13693        &mut self,
13694        action: &DeleteToBeginningOfLine,
13695        window: &mut Window,
13696        cx: &mut Context<Self>,
13697    ) {
13698        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13699        self.transact(window, cx, |this, window, cx| {
13700            this.change_selections(Default::default(), window, cx, |s| {
13701                s.move_with(|_, selection| {
13702                    selection.reversed = true;
13703                });
13704            });
13705
13706            this.select_to_beginning_of_line(
13707                &SelectToBeginningOfLine {
13708                    stop_at_soft_wraps: false,
13709                    stop_at_indent: action.stop_at_indent,
13710                },
13711                window,
13712                cx,
13713            );
13714            this.backspace(&Backspace, window, cx);
13715        });
13716    }
13717
13718    pub fn move_to_end_of_line(
13719        &mut self,
13720        action: &MoveToEndOfLine,
13721        window: &mut Window,
13722        cx: &mut Context<Self>,
13723    ) {
13724        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13725        self.change_selections(Default::default(), window, cx, |s| {
13726            s.move_cursors_with(|map, head, _| {
13727                (
13728                    movement::line_end(map, head, action.stop_at_soft_wraps),
13729                    SelectionGoal::None,
13730                )
13731            });
13732        })
13733    }
13734
13735    pub fn select_to_end_of_line(
13736        &mut self,
13737        action: &SelectToEndOfLine,
13738        window: &mut Window,
13739        cx: &mut Context<Self>,
13740    ) {
13741        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13742        self.change_selections(Default::default(), window, cx, |s| {
13743            s.move_heads_with(|map, head, _| {
13744                (
13745                    movement::line_end(map, head, action.stop_at_soft_wraps),
13746                    SelectionGoal::None,
13747                )
13748            });
13749        })
13750    }
13751
13752    pub fn delete_to_end_of_line(
13753        &mut self,
13754        _: &DeleteToEndOfLine,
13755        window: &mut Window,
13756        cx: &mut Context<Self>,
13757    ) {
13758        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13759        self.transact(window, cx, |this, window, cx| {
13760            this.select_to_end_of_line(
13761                &SelectToEndOfLine {
13762                    stop_at_soft_wraps: false,
13763                },
13764                window,
13765                cx,
13766            );
13767            this.delete(&Delete, window, cx);
13768        });
13769    }
13770
13771    pub fn cut_to_end_of_line(
13772        &mut self,
13773        action: &CutToEndOfLine,
13774        window: &mut Window,
13775        cx: &mut Context<Self>,
13776    ) {
13777        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13778        self.transact(window, cx, |this, window, cx| {
13779            this.select_to_end_of_line(
13780                &SelectToEndOfLine {
13781                    stop_at_soft_wraps: false,
13782                },
13783                window,
13784                cx,
13785            );
13786            if !action.stop_at_newlines {
13787                this.change_selections(Default::default(), window, cx, |s| {
13788                    s.move_with(|_, sel| {
13789                        if sel.is_empty() {
13790                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13791                        }
13792                    });
13793                });
13794            }
13795            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13796            let item = this.cut_common(false, window, cx);
13797            cx.write_to_clipboard(item);
13798        });
13799    }
13800
13801    pub fn move_to_start_of_paragraph(
13802        &mut self,
13803        _: &MoveToStartOfParagraph,
13804        window: &mut Window,
13805        cx: &mut Context<Self>,
13806    ) {
13807        if matches!(self.mode, EditorMode::SingleLine) {
13808            cx.propagate();
13809            return;
13810        }
13811        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13812        self.change_selections(Default::default(), window, cx, |s| {
13813            s.move_with(|map, selection| {
13814                selection.collapse_to(
13815                    movement::start_of_paragraph(map, selection.head(), 1),
13816                    SelectionGoal::None,
13817                )
13818            });
13819        })
13820    }
13821
13822    pub fn move_to_end_of_paragraph(
13823        &mut self,
13824        _: &MoveToEndOfParagraph,
13825        window: &mut Window,
13826        cx: &mut Context<Self>,
13827    ) {
13828        if matches!(self.mode, EditorMode::SingleLine) {
13829            cx.propagate();
13830            return;
13831        }
13832        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13833        self.change_selections(Default::default(), window, cx, |s| {
13834            s.move_with(|map, selection| {
13835                selection.collapse_to(
13836                    movement::end_of_paragraph(map, selection.head(), 1),
13837                    SelectionGoal::None,
13838                )
13839            });
13840        })
13841    }
13842
13843    pub fn select_to_start_of_paragraph(
13844        &mut self,
13845        _: &SelectToStartOfParagraph,
13846        window: &mut Window,
13847        cx: &mut Context<Self>,
13848    ) {
13849        if matches!(self.mode, EditorMode::SingleLine) {
13850            cx.propagate();
13851            return;
13852        }
13853        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13854        self.change_selections(Default::default(), window, cx, |s| {
13855            s.move_heads_with(|map, head, _| {
13856                (
13857                    movement::start_of_paragraph(map, head, 1),
13858                    SelectionGoal::None,
13859                )
13860            });
13861        })
13862    }
13863
13864    pub fn select_to_end_of_paragraph(
13865        &mut self,
13866        _: &SelectToEndOfParagraph,
13867        window: &mut Window,
13868        cx: &mut Context<Self>,
13869    ) {
13870        if matches!(self.mode, EditorMode::SingleLine) {
13871            cx.propagate();
13872            return;
13873        }
13874        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13875        self.change_selections(Default::default(), window, cx, |s| {
13876            s.move_heads_with(|map, head, _| {
13877                (
13878                    movement::end_of_paragraph(map, head, 1),
13879                    SelectionGoal::None,
13880                )
13881            });
13882        })
13883    }
13884
13885    pub fn move_to_start_of_excerpt(
13886        &mut self,
13887        _: &MoveToStartOfExcerpt,
13888        window: &mut Window,
13889        cx: &mut Context<Self>,
13890    ) {
13891        if matches!(self.mode, EditorMode::SingleLine) {
13892            cx.propagate();
13893            return;
13894        }
13895        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13896        self.change_selections(Default::default(), window, cx, |s| {
13897            s.move_with(|map, selection| {
13898                selection.collapse_to(
13899                    movement::start_of_excerpt(
13900                        map,
13901                        selection.head(),
13902                        workspace::searchable::Direction::Prev,
13903                    ),
13904                    SelectionGoal::None,
13905                )
13906            });
13907        })
13908    }
13909
13910    pub fn move_to_start_of_next_excerpt(
13911        &mut self,
13912        _: &MoveToStartOfNextExcerpt,
13913        window: &mut Window,
13914        cx: &mut Context<Self>,
13915    ) {
13916        if matches!(self.mode, EditorMode::SingleLine) {
13917            cx.propagate();
13918            return;
13919        }
13920
13921        self.change_selections(Default::default(), window, cx, |s| {
13922            s.move_with(|map, selection| {
13923                selection.collapse_to(
13924                    movement::start_of_excerpt(
13925                        map,
13926                        selection.head(),
13927                        workspace::searchable::Direction::Next,
13928                    ),
13929                    SelectionGoal::None,
13930                )
13931            });
13932        })
13933    }
13934
13935    pub fn move_to_end_of_excerpt(
13936        &mut self,
13937        _: &MoveToEndOfExcerpt,
13938        window: &mut Window,
13939        cx: &mut Context<Self>,
13940    ) {
13941        if matches!(self.mode, EditorMode::SingleLine) {
13942            cx.propagate();
13943            return;
13944        }
13945        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13946        self.change_selections(Default::default(), window, cx, |s| {
13947            s.move_with(|map, selection| {
13948                selection.collapse_to(
13949                    movement::end_of_excerpt(
13950                        map,
13951                        selection.head(),
13952                        workspace::searchable::Direction::Next,
13953                    ),
13954                    SelectionGoal::None,
13955                )
13956            });
13957        })
13958    }
13959
13960    pub fn move_to_end_of_previous_excerpt(
13961        &mut self,
13962        _: &MoveToEndOfPreviousExcerpt,
13963        window: &mut Window,
13964        cx: &mut Context<Self>,
13965    ) {
13966        if matches!(self.mode, EditorMode::SingleLine) {
13967            cx.propagate();
13968            return;
13969        }
13970        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13971        self.change_selections(Default::default(), window, cx, |s| {
13972            s.move_with(|map, selection| {
13973                selection.collapse_to(
13974                    movement::end_of_excerpt(
13975                        map,
13976                        selection.head(),
13977                        workspace::searchable::Direction::Prev,
13978                    ),
13979                    SelectionGoal::None,
13980                )
13981            });
13982        })
13983    }
13984
13985    pub fn select_to_start_of_excerpt(
13986        &mut self,
13987        _: &SelectToStartOfExcerpt,
13988        window: &mut Window,
13989        cx: &mut Context<Self>,
13990    ) {
13991        if matches!(self.mode, EditorMode::SingleLine) {
13992            cx.propagate();
13993            return;
13994        }
13995        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13996        self.change_selections(Default::default(), window, cx, |s| {
13997            s.move_heads_with(|map, head, _| {
13998                (
13999                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14000                    SelectionGoal::None,
14001                )
14002            });
14003        })
14004    }
14005
14006    pub fn select_to_start_of_next_excerpt(
14007        &mut self,
14008        _: &SelectToStartOfNextExcerpt,
14009        window: &mut Window,
14010        cx: &mut Context<Self>,
14011    ) {
14012        if matches!(self.mode, EditorMode::SingleLine) {
14013            cx.propagate();
14014            return;
14015        }
14016        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14017        self.change_selections(Default::default(), window, cx, |s| {
14018            s.move_heads_with(|map, head, _| {
14019                (
14020                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14021                    SelectionGoal::None,
14022                )
14023            });
14024        })
14025    }
14026
14027    pub fn select_to_end_of_excerpt(
14028        &mut self,
14029        _: &SelectToEndOfExcerpt,
14030        window: &mut Window,
14031        cx: &mut Context<Self>,
14032    ) {
14033        if matches!(self.mode, EditorMode::SingleLine) {
14034            cx.propagate();
14035            return;
14036        }
14037        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14038        self.change_selections(Default::default(), window, cx, |s| {
14039            s.move_heads_with(|map, head, _| {
14040                (
14041                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14042                    SelectionGoal::None,
14043                )
14044            });
14045        })
14046    }
14047
14048    pub fn select_to_end_of_previous_excerpt(
14049        &mut self,
14050        _: &SelectToEndOfPreviousExcerpt,
14051        window: &mut Window,
14052        cx: &mut Context<Self>,
14053    ) {
14054        if matches!(self.mode, EditorMode::SingleLine) {
14055            cx.propagate();
14056            return;
14057        }
14058        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14059        self.change_selections(Default::default(), window, cx, |s| {
14060            s.move_heads_with(|map, head, _| {
14061                (
14062                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14063                    SelectionGoal::None,
14064                )
14065            });
14066        })
14067    }
14068
14069    pub fn move_to_beginning(
14070        &mut self,
14071        _: &MoveToBeginning,
14072        window: &mut Window,
14073        cx: &mut Context<Self>,
14074    ) {
14075        if matches!(self.mode, EditorMode::SingleLine) {
14076            cx.propagate();
14077            return;
14078        }
14079        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14080        self.change_selections(Default::default(), window, cx, |s| {
14081            s.select_ranges(vec![0..0]);
14082        });
14083    }
14084
14085    pub fn select_to_beginning(
14086        &mut self,
14087        _: &SelectToBeginning,
14088        window: &mut Window,
14089        cx: &mut Context<Self>,
14090    ) {
14091        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14092        selection.set_head(Point::zero(), SelectionGoal::None);
14093        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14094        self.change_selections(Default::default(), window, cx, |s| {
14095            s.select(vec![selection]);
14096        });
14097    }
14098
14099    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14100        if matches!(self.mode, EditorMode::SingleLine) {
14101            cx.propagate();
14102            return;
14103        }
14104        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14105        let cursor = self.buffer.read(cx).read(cx).len();
14106        self.change_selections(Default::default(), window, cx, |s| {
14107            s.select_ranges(vec![cursor..cursor])
14108        });
14109    }
14110
14111    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14112        self.nav_history = nav_history;
14113    }
14114
14115    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14116        self.nav_history.as_ref()
14117    }
14118
14119    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14120        self.push_to_nav_history(
14121            self.selections.newest_anchor().head(),
14122            None,
14123            false,
14124            true,
14125            cx,
14126        );
14127    }
14128
14129    fn push_to_nav_history(
14130        &mut self,
14131        cursor_anchor: Anchor,
14132        new_position: Option<Point>,
14133        is_deactivate: bool,
14134        always: bool,
14135        cx: &mut Context<Self>,
14136    ) {
14137        if let Some(nav_history) = self.nav_history.as_mut() {
14138            let buffer = self.buffer.read(cx).read(cx);
14139            let cursor_position = cursor_anchor.to_point(&buffer);
14140            let scroll_state = self.scroll_manager.anchor();
14141            let scroll_top_row = scroll_state.top_row(&buffer);
14142            drop(buffer);
14143
14144            if let Some(new_position) = new_position {
14145                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14146                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14147                    return;
14148                }
14149            }
14150
14151            nav_history.push(
14152                Some(NavigationData {
14153                    cursor_anchor,
14154                    cursor_position,
14155                    scroll_anchor: scroll_state,
14156                    scroll_top_row,
14157                }),
14158                cx,
14159            );
14160            cx.emit(EditorEvent::PushedToNavHistory {
14161                anchor: cursor_anchor,
14162                is_deactivate,
14163            })
14164        }
14165    }
14166
14167    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14168        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14169        let buffer = self.buffer.read(cx).snapshot(cx);
14170        let mut selection = self.selections.first::<usize>(&self.display_snapshot(cx));
14171        selection.set_head(buffer.len(), SelectionGoal::None);
14172        self.change_selections(Default::default(), window, cx, |s| {
14173            s.select(vec![selection]);
14174        });
14175    }
14176
14177    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14178        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14179        let end = self.buffer.read(cx).read(cx).len();
14180        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14181            s.select_ranges(vec![0..end]);
14182        });
14183    }
14184
14185    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14186        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14187        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14188        let mut selections = self.selections.all::<Point>(&display_map);
14189        let max_point = display_map.buffer_snapshot().max_point();
14190        for selection in &mut selections {
14191            let rows = selection.spanned_rows(true, &display_map);
14192            selection.start = Point::new(rows.start.0, 0);
14193            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14194            selection.reversed = false;
14195        }
14196        self.change_selections(Default::default(), window, cx, |s| {
14197            s.select(selections);
14198        });
14199    }
14200
14201    pub fn split_selection_into_lines(
14202        &mut self,
14203        action: &SplitSelectionIntoLines,
14204        window: &mut Window,
14205        cx: &mut Context<Self>,
14206    ) {
14207        let selections = self
14208            .selections
14209            .all::<Point>(&self.display_snapshot(cx))
14210            .into_iter()
14211            .map(|selection| selection.start..selection.end)
14212            .collect::<Vec<_>>();
14213        self.unfold_ranges(&selections, true, true, cx);
14214
14215        let mut new_selection_ranges = Vec::new();
14216        {
14217            let buffer = self.buffer.read(cx).read(cx);
14218            for selection in selections {
14219                for row in selection.start.row..selection.end.row {
14220                    let line_start = Point::new(row, 0);
14221                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14222
14223                    if action.keep_selections {
14224                        // Keep the selection range for each line
14225                        let selection_start = if row == selection.start.row {
14226                            selection.start
14227                        } else {
14228                            line_start
14229                        };
14230                        new_selection_ranges.push(selection_start..line_end);
14231                    } else {
14232                        // Collapse to cursor at end of line
14233                        new_selection_ranges.push(line_end..line_end);
14234                    }
14235                }
14236
14237                let is_multiline_selection = selection.start.row != selection.end.row;
14238                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14239                // so this action feels more ergonomic when paired with other selection operations
14240                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14241                if !should_skip_last {
14242                    if action.keep_selections {
14243                        if is_multiline_selection {
14244                            let line_start = Point::new(selection.end.row, 0);
14245                            new_selection_ranges.push(line_start..selection.end);
14246                        } else {
14247                            new_selection_ranges.push(selection.start..selection.end);
14248                        }
14249                    } else {
14250                        new_selection_ranges.push(selection.end..selection.end);
14251                    }
14252                }
14253            }
14254        }
14255        self.change_selections(Default::default(), window, cx, |s| {
14256            s.select_ranges(new_selection_ranges);
14257        });
14258    }
14259
14260    pub fn add_selection_above(
14261        &mut self,
14262        action: &AddSelectionAbove,
14263        window: &mut Window,
14264        cx: &mut Context<Self>,
14265    ) {
14266        self.add_selection(true, action.skip_soft_wrap, window, cx);
14267    }
14268
14269    pub fn add_selection_below(
14270        &mut self,
14271        action: &AddSelectionBelow,
14272        window: &mut Window,
14273        cx: &mut Context<Self>,
14274    ) {
14275        self.add_selection(false, action.skip_soft_wrap, window, cx);
14276    }
14277
14278    fn add_selection(
14279        &mut self,
14280        above: bool,
14281        skip_soft_wrap: bool,
14282        window: &mut Window,
14283        cx: &mut Context<Self>,
14284    ) {
14285        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14286
14287        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14288        let all_selections = self.selections.all::<Point>(&display_map);
14289        let text_layout_details = self.text_layout_details(window);
14290
14291        let (mut columnar_selections, new_selections_to_columnarize) = {
14292            if let Some(state) = self.add_selections_state.as_ref() {
14293                let columnar_selection_ids: HashSet<_> = state
14294                    .groups
14295                    .iter()
14296                    .flat_map(|group| group.stack.iter())
14297                    .copied()
14298                    .collect();
14299
14300                all_selections
14301                    .into_iter()
14302                    .partition(|s| columnar_selection_ids.contains(&s.id))
14303            } else {
14304                (Vec::new(), all_selections)
14305            }
14306        };
14307
14308        let mut state = self
14309            .add_selections_state
14310            .take()
14311            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14312
14313        for selection in new_selections_to_columnarize {
14314            let range = selection.display_range(&display_map).sorted();
14315            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14316            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14317            let positions = start_x.min(end_x)..start_x.max(end_x);
14318            let mut stack = Vec::new();
14319            for row in range.start.row().0..=range.end.row().0 {
14320                if let Some(selection) = self.selections.build_columnar_selection(
14321                    &display_map,
14322                    DisplayRow(row),
14323                    &positions,
14324                    selection.reversed,
14325                    &text_layout_details,
14326                ) {
14327                    stack.push(selection.id);
14328                    columnar_selections.push(selection);
14329                }
14330            }
14331            if !stack.is_empty() {
14332                if above {
14333                    stack.reverse();
14334                }
14335                state.groups.push(AddSelectionsGroup { above, stack });
14336            }
14337        }
14338
14339        let mut final_selections = Vec::new();
14340        let end_row = if above {
14341            DisplayRow(0)
14342        } else {
14343            display_map.max_point().row()
14344        };
14345
14346        let mut last_added_item_per_group = HashMap::default();
14347        for group in state.groups.iter_mut() {
14348            if let Some(last_id) = group.stack.last() {
14349                last_added_item_per_group.insert(*last_id, group);
14350            }
14351        }
14352
14353        for selection in columnar_selections {
14354            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14355                if above == group.above {
14356                    let range = selection.display_range(&display_map).sorted();
14357                    debug_assert_eq!(range.start.row(), range.end.row());
14358                    let mut row = range.start.row();
14359                    let positions =
14360                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14361                            Pixels::from(start)..Pixels::from(end)
14362                        } else {
14363                            let start_x =
14364                                display_map.x_for_display_point(range.start, &text_layout_details);
14365                            let end_x =
14366                                display_map.x_for_display_point(range.end, &text_layout_details);
14367                            start_x.min(end_x)..start_x.max(end_x)
14368                        };
14369
14370                    let mut maybe_new_selection = None;
14371                    let direction = if above { -1 } else { 1 };
14372
14373                    while row != end_row {
14374                        if skip_soft_wrap {
14375                            row = display_map
14376                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14377                                .row();
14378                        } else if above {
14379                            row.0 -= 1;
14380                        } else {
14381                            row.0 += 1;
14382                        }
14383
14384                        if let Some(new_selection) = self.selections.build_columnar_selection(
14385                            &display_map,
14386                            row,
14387                            &positions,
14388                            selection.reversed,
14389                            &text_layout_details,
14390                        ) {
14391                            maybe_new_selection = Some(new_selection);
14392                            break;
14393                        }
14394                    }
14395
14396                    if let Some(new_selection) = maybe_new_selection {
14397                        group.stack.push(new_selection.id);
14398                        if above {
14399                            final_selections.push(new_selection);
14400                            final_selections.push(selection);
14401                        } else {
14402                            final_selections.push(selection);
14403                            final_selections.push(new_selection);
14404                        }
14405                    } else {
14406                        final_selections.push(selection);
14407                    }
14408                } else {
14409                    group.stack.pop();
14410                }
14411            } else {
14412                final_selections.push(selection);
14413            }
14414        }
14415
14416        self.change_selections(Default::default(), window, cx, |s| {
14417            s.select(final_selections);
14418        });
14419
14420        let final_selection_ids: HashSet<_> = self
14421            .selections
14422            .all::<Point>(&display_map)
14423            .iter()
14424            .map(|s| s.id)
14425            .collect();
14426        state.groups.retain_mut(|group| {
14427            // selections might get merged above so we remove invalid items from stacks
14428            group.stack.retain(|id| final_selection_ids.contains(id));
14429
14430            // single selection in stack can be treated as initial state
14431            group.stack.len() > 1
14432        });
14433
14434        if !state.groups.is_empty() {
14435            self.add_selections_state = Some(state);
14436        }
14437    }
14438
14439    fn select_match_ranges(
14440        &mut self,
14441        range: Range<usize>,
14442        reversed: bool,
14443        replace_newest: bool,
14444        auto_scroll: Option<Autoscroll>,
14445        window: &mut Window,
14446        cx: &mut Context<Editor>,
14447    ) {
14448        self.unfold_ranges(
14449            std::slice::from_ref(&range),
14450            false,
14451            auto_scroll.is_some(),
14452            cx,
14453        );
14454        let effects = if let Some(scroll) = auto_scroll {
14455            SelectionEffects::scroll(scroll)
14456        } else {
14457            SelectionEffects::no_scroll()
14458        };
14459        self.change_selections(effects, window, cx, |s| {
14460            if replace_newest {
14461                s.delete(s.newest_anchor().id);
14462            }
14463            if reversed {
14464                s.insert_range(range.end..range.start);
14465            } else {
14466                s.insert_range(range);
14467            }
14468        });
14469    }
14470
14471    pub fn select_next_match_internal(
14472        &mut self,
14473        display_map: &DisplaySnapshot,
14474        replace_newest: bool,
14475        autoscroll: Option<Autoscroll>,
14476        window: &mut Window,
14477        cx: &mut Context<Self>,
14478    ) -> Result<()> {
14479        let buffer = display_map.buffer_snapshot();
14480        let mut selections = self.selections.all::<usize>(&display_map);
14481        if let Some(mut select_next_state) = self.select_next_state.take() {
14482            let query = &select_next_state.query;
14483            if !select_next_state.done {
14484                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14485                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14486                let mut next_selected_range = None;
14487
14488                let bytes_after_last_selection =
14489                    buffer.bytes_in_range(last_selection.end..buffer.len());
14490                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14491                let query_matches = query
14492                    .stream_find_iter(bytes_after_last_selection)
14493                    .map(|result| (last_selection.end, result))
14494                    .chain(
14495                        query
14496                            .stream_find_iter(bytes_before_first_selection)
14497                            .map(|result| (0, result)),
14498                    );
14499
14500                for (start_offset, query_match) in query_matches {
14501                    let query_match = query_match.unwrap(); // can only fail due to I/O
14502                    let offset_range =
14503                        start_offset + query_match.start()..start_offset + query_match.end();
14504
14505                    if !select_next_state.wordwise
14506                        || (!buffer.is_inside_word(offset_range.start, None)
14507                            && !buffer.is_inside_word(offset_range.end, None))
14508                    {
14509                        let idx = selections
14510                            .partition_point(|selection| selection.end <= offset_range.start);
14511                        let overlaps = selections
14512                            .get(idx)
14513                            .map_or(false, |selection| selection.start < offset_range.end);
14514
14515                        if !overlaps {
14516                            next_selected_range = Some(offset_range);
14517                            break;
14518                        }
14519                    }
14520                }
14521
14522                if let Some(next_selected_range) = next_selected_range {
14523                    self.select_match_ranges(
14524                        next_selected_range,
14525                        last_selection.reversed,
14526                        replace_newest,
14527                        autoscroll,
14528                        window,
14529                        cx,
14530                    );
14531                } else {
14532                    select_next_state.done = true;
14533                }
14534            }
14535
14536            self.select_next_state = Some(select_next_state);
14537        } else {
14538            let mut only_carets = true;
14539            let mut same_text_selected = true;
14540            let mut selected_text = None;
14541
14542            let mut selections_iter = selections.iter().peekable();
14543            while let Some(selection) = selections_iter.next() {
14544                if selection.start != selection.end {
14545                    only_carets = false;
14546                }
14547
14548                if same_text_selected {
14549                    if selected_text.is_none() {
14550                        selected_text =
14551                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14552                    }
14553
14554                    if let Some(next_selection) = selections_iter.peek() {
14555                        if next_selection.range().len() == selection.range().len() {
14556                            let next_selected_text = buffer
14557                                .text_for_range(next_selection.range())
14558                                .collect::<String>();
14559                            if Some(next_selected_text) != selected_text {
14560                                same_text_selected = false;
14561                                selected_text = None;
14562                            }
14563                        } else {
14564                            same_text_selected = false;
14565                            selected_text = None;
14566                        }
14567                    }
14568                }
14569            }
14570
14571            if only_carets {
14572                for selection in &mut selections {
14573                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14574                    selection.start = word_range.start;
14575                    selection.end = word_range.end;
14576                    selection.goal = SelectionGoal::None;
14577                    selection.reversed = false;
14578                    self.select_match_ranges(
14579                        selection.start..selection.end,
14580                        selection.reversed,
14581                        replace_newest,
14582                        autoscroll,
14583                        window,
14584                        cx,
14585                    );
14586                }
14587
14588                if selections.len() == 1 {
14589                    let selection = selections
14590                        .last()
14591                        .expect("ensured that there's only one selection");
14592                    let query = buffer
14593                        .text_for_range(selection.start..selection.end)
14594                        .collect::<String>();
14595                    let is_empty = query.is_empty();
14596                    let select_state = SelectNextState {
14597                        query: AhoCorasick::new(&[query])?,
14598                        wordwise: true,
14599                        done: is_empty,
14600                    };
14601                    self.select_next_state = Some(select_state);
14602                } else {
14603                    self.select_next_state = None;
14604                }
14605            } else if let Some(selected_text) = selected_text {
14606                self.select_next_state = Some(SelectNextState {
14607                    query: AhoCorasick::new(&[selected_text])?,
14608                    wordwise: false,
14609                    done: false,
14610                });
14611                self.select_next_match_internal(
14612                    display_map,
14613                    replace_newest,
14614                    autoscroll,
14615                    window,
14616                    cx,
14617                )?;
14618            }
14619        }
14620        Ok(())
14621    }
14622
14623    pub fn select_all_matches(
14624        &mut self,
14625        _action: &SelectAllMatches,
14626        window: &mut Window,
14627        cx: &mut Context<Self>,
14628    ) -> Result<()> {
14629        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14630
14631        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14632
14633        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14634        let Some(select_next_state) = self.select_next_state.as_mut() else {
14635            return Ok(());
14636        };
14637        if select_next_state.done {
14638            return Ok(());
14639        }
14640
14641        let mut new_selections = Vec::new();
14642
14643        let reversed = self.selections.oldest::<usize>(&display_map).reversed;
14644        let buffer = display_map.buffer_snapshot();
14645        let query_matches = select_next_state
14646            .query
14647            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14648
14649        for query_match in query_matches.into_iter() {
14650            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14651            let offset_range = if reversed {
14652                query_match.end()..query_match.start()
14653            } else {
14654                query_match.start()..query_match.end()
14655            };
14656
14657            if !select_next_state.wordwise
14658                || (!buffer.is_inside_word(offset_range.start, None)
14659                    && !buffer.is_inside_word(offset_range.end, None))
14660            {
14661                new_selections.push(offset_range.start..offset_range.end);
14662            }
14663        }
14664
14665        select_next_state.done = true;
14666
14667        if new_selections.is_empty() {
14668            log::error!("bug: new_selections is empty in select_all_matches");
14669            return Ok(());
14670        }
14671
14672        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14673        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14674            selections.select_ranges(new_selections)
14675        });
14676
14677        Ok(())
14678    }
14679
14680    pub fn select_next(
14681        &mut self,
14682        action: &SelectNext,
14683        window: &mut Window,
14684        cx: &mut Context<Self>,
14685    ) -> Result<()> {
14686        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14687        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14688        self.select_next_match_internal(
14689            &display_map,
14690            action.replace_newest,
14691            Some(Autoscroll::newest()),
14692            window,
14693            cx,
14694        )?;
14695        Ok(())
14696    }
14697
14698    pub fn select_previous(
14699        &mut self,
14700        action: &SelectPrevious,
14701        window: &mut Window,
14702        cx: &mut Context<Self>,
14703    ) -> Result<()> {
14704        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14705        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14706        let buffer = display_map.buffer_snapshot();
14707        let mut selections = self.selections.all::<usize>(&display_map);
14708        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14709            let query = &select_prev_state.query;
14710            if !select_prev_state.done {
14711                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14712                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14713                let mut next_selected_range = None;
14714                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14715                let bytes_before_last_selection =
14716                    buffer.reversed_bytes_in_range(0..last_selection.start);
14717                let bytes_after_first_selection =
14718                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14719                let query_matches = query
14720                    .stream_find_iter(bytes_before_last_selection)
14721                    .map(|result| (last_selection.start, result))
14722                    .chain(
14723                        query
14724                            .stream_find_iter(bytes_after_first_selection)
14725                            .map(|result| (buffer.len(), result)),
14726                    );
14727                for (end_offset, query_match) in query_matches {
14728                    let query_match = query_match.unwrap(); // can only fail due to I/O
14729                    let offset_range =
14730                        end_offset - query_match.end()..end_offset - query_match.start();
14731
14732                    if !select_prev_state.wordwise
14733                        || (!buffer.is_inside_word(offset_range.start, None)
14734                            && !buffer.is_inside_word(offset_range.end, None))
14735                    {
14736                        next_selected_range = Some(offset_range);
14737                        break;
14738                    }
14739                }
14740
14741                if let Some(next_selected_range) = next_selected_range {
14742                    self.select_match_ranges(
14743                        next_selected_range,
14744                        last_selection.reversed,
14745                        action.replace_newest,
14746                        Some(Autoscroll::newest()),
14747                        window,
14748                        cx,
14749                    );
14750                } else {
14751                    select_prev_state.done = true;
14752                }
14753            }
14754
14755            self.select_prev_state = Some(select_prev_state);
14756        } else {
14757            let mut only_carets = true;
14758            let mut same_text_selected = true;
14759            let mut selected_text = None;
14760
14761            let mut selections_iter = selections.iter().peekable();
14762            while let Some(selection) = selections_iter.next() {
14763                if selection.start != selection.end {
14764                    only_carets = false;
14765                }
14766
14767                if same_text_selected {
14768                    if selected_text.is_none() {
14769                        selected_text =
14770                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14771                    }
14772
14773                    if let Some(next_selection) = selections_iter.peek() {
14774                        if next_selection.range().len() == selection.range().len() {
14775                            let next_selected_text = buffer
14776                                .text_for_range(next_selection.range())
14777                                .collect::<String>();
14778                            if Some(next_selected_text) != selected_text {
14779                                same_text_selected = false;
14780                                selected_text = None;
14781                            }
14782                        } else {
14783                            same_text_selected = false;
14784                            selected_text = None;
14785                        }
14786                    }
14787                }
14788            }
14789
14790            if only_carets {
14791                for selection in &mut selections {
14792                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14793                    selection.start = word_range.start;
14794                    selection.end = word_range.end;
14795                    selection.goal = SelectionGoal::None;
14796                    selection.reversed = false;
14797                    self.select_match_ranges(
14798                        selection.start..selection.end,
14799                        selection.reversed,
14800                        action.replace_newest,
14801                        Some(Autoscroll::newest()),
14802                        window,
14803                        cx,
14804                    );
14805                }
14806                if selections.len() == 1 {
14807                    let selection = selections
14808                        .last()
14809                        .expect("ensured that there's only one selection");
14810                    let query = buffer
14811                        .text_for_range(selection.start..selection.end)
14812                        .collect::<String>();
14813                    let is_empty = query.is_empty();
14814                    let select_state = SelectNextState {
14815                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14816                        wordwise: true,
14817                        done: is_empty,
14818                    };
14819                    self.select_prev_state = Some(select_state);
14820                } else {
14821                    self.select_prev_state = None;
14822                }
14823            } else if let Some(selected_text) = selected_text {
14824                self.select_prev_state = Some(SelectNextState {
14825                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14826                    wordwise: false,
14827                    done: false,
14828                });
14829                self.select_previous(action, window, cx)?;
14830            }
14831        }
14832        Ok(())
14833    }
14834
14835    pub fn find_next_match(
14836        &mut self,
14837        _: &FindNextMatch,
14838        window: &mut Window,
14839        cx: &mut Context<Self>,
14840    ) -> Result<()> {
14841        let selections = self.selections.disjoint_anchors_arc();
14842        match selections.first() {
14843            Some(first) if selections.len() >= 2 => {
14844                self.change_selections(Default::default(), window, cx, |s| {
14845                    s.select_ranges([first.range()]);
14846                });
14847            }
14848            _ => self.select_next(
14849                &SelectNext {
14850                    replace_newest: true,
14851                },
14852                window,
14853                cx,
14854            )?,
14855        }
14856        Ok(())
14857    }
14858
14859    pub fn find_previous_match(
14860        &mut self,
14861        _: &FindPreviousMatch,
14862        window: &mut Window,
14863        cx: &mut Context<Self>,
14864    ) -> Result<()> {
14865        let selections = self.selections.disjoint_anchors_arc();
14866        match selections.last() {
14867            Some(last) if selections.len() >= 2 => {
14868                self.change_selections(Default::default(), window, cx, |s| {
14869                    s.select_ranges([last.range()]);
14870                });
14871            }
14872            _ => self.select_previous(
14873                &SelectPrevious {
14874                    replace_newest: true,
14875                },
14876                window,
14877                cx,
14878            )?,
14879        }
14880        Ok(())
14881    }
14882
14883    pub fn toggle_comments(
14884        &mut self,
14885        action: &ToggleComments,
14886        window: &mut Window,
14887        cx: &mut Context<Self>,
14888    ) {
14889        if self.read_only(cx) {
14890            return;
14891        }
14892        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14893        let text_layout_details = &self.text_layout_details(window);
14894        self.transact(window, cx, |this, window, cx| {
14895            let mut selections = this
14896                .selections
14897                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
14898            let mut edits = Vec::new();
14899            let mut selection_edit_ranges = Vec::new();
14900            let mut last_toggled_row = None;
14901            let snapshot = this.buffer.read(cx).read(cx);
14902            let empty_str: Arc<str> = Arc::default();
14903            let mut suffixes_inserted = Vec::new();
14904            let ignore_indent = action.ignore_indent;
14905
14906            fn comment_prefix_range(
14907                snapshot: &MultiBufferSnapshot,
14908                row: MultiBufferRow,
14909                comment_prefix: &str,
14910                comment_prefix_whitespace: &str,
14911                ignore_indent: bool,
14912            ) -> Range<Point> {
14913                let indent_size = if ignore_indent {
14914                    0
14915                } else {
14916                    snapshot.indent_size_for_line(row).len
14917                };
14918
14919                let start = Point::new(row.0, indent_size);
14920
14921                let mut line_bytes = snapshot
14922                    .bytes_in_range(start..snapshot.max_point())
14923                    .flatten()
14924                    .copied();
14925
14926                // If this line currently begins with the line comment prefix, then record
14927                // the range containing the prefix.
14928                if line_bytes
14929                    .by_ref()
14930                    .take(comment_prefix.len())
14931                    .eq(comment_prefix.bytes())
14932                {
14933                    // Include any whitespace that matches the comment prefix.
14934                    let matching_whitespace_len = line_bytes
14935                        .zip(comment_prefix_whitespace.bytes())
14936                        .take_while(|(a, b)| a == b)
14937                        .count() as u32;
14938                    let end = Point::new(
14939                        start.row,
14940                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14941                    );
14942                    start..end
14943                } else {
14944                    start..start
14945                }
14946            }
14947
14948            fn comment_suffix_range(
14949                snapshot: &MultiBufferSnapshot,
14950                row: MultiBufferRow,
14951                comment_suffix: &str,
14952                comment_suffix_has_leading_space: bool,
14953            ) -> Range<Point> {
14954                let end = Point::new(row.0, snapshot.line_len(row));
14955                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14956
14957                let mut line_end_bytes = snapshot
14958                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14959                    .flatten()
14960                    .copied();
14961
14962                let leading_space_len = if suffix_start_column > 0
14963                    && line_end_bytes.next() == Some(b' ')
14964                    && comment_suffix_has_leading_space
14965                {
14966                    1
14967                } else {
14968                    0
14969                };
14970
14971                // If this line currently begins with the line comment prefix, then record
14972                // the range containing the prefix.
14973                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14974                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14975                    start..end
14976                } else {
14977                    end..end
14978                }
14979            }
14980
14981            // TODO: Handle selections that cross excerpts
14982            for selection in &mut selections {
14983                let start_column = snapshot
14984                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14985                    .len;
14986                let language = if let Some(language) =
14987                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14988                {
14989                    language
14990                } else {
14991                    continue;
14992                };
14993
14994                selection_edit_ranges.clear();
14995
14996                // If multiple selections contain a given row, avoid processing that
14997                // row more than once.
14998                let mut start_row = MultiBufferRow(selection.start.row);
14999                if last_toggled_row == Some(start_row) {
15000                    start_row = start_row.next_row();
15001                }
15002                let end_row =
15003                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15004                        MultiBufferRow(selection.end.row - 1)
15005                    } else {
15006                        MultiBufferRow(selection.end.row)
15007                    };
15008                last_toggled_row = Some(end_row);
15009
15010                if start_row > end_row {
15011                    continue;
15012                }
15013
15014                // If the language has line comments, toggle those.
15015                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15016
15017                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15018                if ignore_indent {
15019                    full_comment_prefixes = full_comment_prefixes
15020                        .into_iter()
15021                        .map(|s| Arc::from(s.trim_end()))
15022                        .collect();
15023                }
15024
15025                if !full_comment_prefixes.is_empty() {
15026                    let first_prefix = full_comment_prefixes
15027                        .first()
15028                        .expect("prefixes is non-empty");
15029                    let prefix_trimmed_lengths = full_comment_prefixes
15030                        .iter()
15031                        .map(|p| p.trim_end_matches(' ').len())
15032                        .collect::<SmallVec<[usize; 4]>>();
15033
15034                    let mut all_selection_lines_are_comments = true;
15035
15036                    for row in start_row.0..=end_row.0 {
15037                        let row = MultiBufferRow(row);
15038                        if start_row < end_row && snapshot.is_line_blank(row) {
15039                            continue;
15040                        }
15041
15042                        let prefix_range = full_comment_prefixes
15043                            .iter()
15044                            .zip(prefix_trimmed_lengths.iter().copied())
15045                            .map(|(prefix, trimmed_prefix_len)| {
15046                                comment_prefix_range(
15047                                    snapshot.deref(),
15048                                    row,
15049                                    &prefix[..trimmed_prefix_len],
15050                                    &prefix[trimmed_prefix_len..],
15051                                    ignore_indent,
15052                                )
15053                            })
15054                            .max_by_key(|range| range.end.column - range.start.column)
15055                            .expect("prefixes is non-empty");
15056
15057                        if prefix_range.is_empty() {
15058                            all_selection_lines_are_comments = false;
15059                        }
15060
15061                        selection_edit_ranges.push(prefix_range);
15062                    }
15063
15064                    if all_selection_lines_are_comments {
15065                        edits.extend(
15066                            selection_edit_ranges
15067                                .iter()
15068                                .cloned()
15069                                .map(|range| (range, empty_str.clone())),
15070                        );
15071                    } else {
15072                        let min_column = selection_edit_ranges
15073                            .iter()
15074                            .map(|range| range.start.column)
15075                            .min()
15076                            .unwrap_or(0);
15077                        edits.extend(selection_edit_ranges.iter().map(|range| {
15078                            let position = Point::new(range.start.row, min_column);
15079                            (position..position, first_prefix.clone())
15080                        }));
15081                    }
15082                } else if let Some(BlockCommentConfig {
15083                    start: full_comment_prefix,
15084                    end: comment_suffix,
15085                    ..
15086                }) = language.block_comment()
15087                {
15088                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15089                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15090                    let prefix_range = comment_prefix_range(
15091                        snapshot.deref(),
15092                        start_row,
15093                        comment_prefix,
15094                        comment_prefix_whitespace,
15095                        ignore_indent,
15096                    );
15097                    let suffix_range = comment_suffix_range(
15098                        snapshot.deref(),
15099                        end_row,
15100                        comment_suffix.trim_start_matches(' '),
15101                        comment_suffix.starts_with(' '),
15102                    );
15103
15104                    if prefix_range.is_empty() || suffix_range.is_empty() {
15105                        edits.push((
15106                            prefix_range.start..prefix_range.start,
15107                            full_comment_prefix.clone(),
15108                        ));
15109                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15110                        suffixes_inserted.push((end_row, comment_suffix.len()));
15111                    } else {
15112                        edits.push((prefix_range, empty_str.clone()));
15113                        edits.push((suffix_range, empty_str.clone()));
15114                    }
15115                } else {
15116                    continue;
15117                }
15118            }
15119
15120            drop(snapshot);
15121            this.buffer.update(cx, |buffer, cx| {
15122                buffer.edit(edits, None, cx);
15123            });
15124
15125            // Adjust selections so that they end before any comment suffixes that
15126            // were inserted.
15127            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15128            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15129            let snapshot = this.buffer.read(cx).read(cx);
15130            for selection in &mut selections {
15131                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15132                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15133                        Ordering::Less => {
15134                            suffixes_inserted.next();
15135                            continue;
15136                        }
15137                        Ordering::Greater => break,
15138                        Ordering::Equal => {
15139                            if selection.end.column == snapshot.line_len(row) {
15140                                if selection.is_empty() {
15141                                    selection.start.column -= suffix_len as u32;
15142                                }
15143                                selection.end.column -= suffix_len as u32;
15144                            }
15145                            break;
15146                        }
15147                    }
15148                }
15149            }
15150
15151            drop(snapshot);
15152            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15153
15154            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15155            let selections_on_single_row = selections.windows(2).all(|selections| {
15156                selections[0].start.row == selections[1].start.row
15157                    && selections[0].end.row == selections[1].end.row
15158                    && selections[0].start.row == selections[0].end.row
15159            });
15160            let selections_selecting = selections
15161                .iter()
15162                .any(|selection| selection.start != selection.end);
15163            let advance_downwards = action.advance_downwards
15164                && selections_on_single_row
15165                && !selections_selecting
15166                && !matches!(this.mode, EditorMode::SingleLine);
15167
15168            if advance_downwards {
15169                let snapshot = this.buffer.read(cx).snapshot(cx);
15170
15171                this.change_selections(Default::default(), window, cx, |s| {
15172                    s.move_cursors_with(|display_snapshot, display_point, _| {
15173                        let mut point = display_point.to_point(display_snapshot);
15174                        point.row += 1;
15175                        point = snapshot.clip_point(point, Bias::Left);
15176                        let display_point = point.to_display_point(display_snapshot);
15177                        let goal = SelectionGoal::HorizontalPosition(
15178                            display_snapshot
15179                                .x_for_display_point(display_point, text_layout_details)
15180                                .into(),
15181                        );
15182                        (display_point, goal)
15183                    })
15184                });
15185            }
15186        });
15187    }
15188
15189    pub fn select_enclosing_symbol(
15190        &mut self,
15191        _: &SelectEnclosingSymbol,
15192        window: &mut Window,
15193        cx: &mut Context<Self>,
15194    ) {
15195        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15196
15197        let buffer = self.buffer.read(cx).snapshot(cx);
15198        let old_selections = self
15199            .selections
15200            .all::<usize>(&self.display_snapshot(cx))
15201            .into_boxed_slice();
15202
15203        fn update_selection(
15204            selection: &Selection<usize>,
15205            buffer_snap: &MultiBufferSnapshot,
15206        ) -> Option<Selection<usize>> {
15207            let cursor = selection.head();
15208            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15209            for symbol in symbols.iter().rev() {
15210                let start = symbol.range.start.to_offset(buffer_snap);
15211                let end = symbol.range.end.to_offset(buffer_snap);
15212                let new_range = start..end;
15213                if start < selection.start || end > selection.end {
15214                    return Some(Selection {
15215                        id: selection.id,
15216                        start: new_range.start,
15217                        end: new_range.end,
15218                        goal: SelectionGoal::None,
15219                        reversed: selection.reversed,
15220                    });
15221                }
15222            }
15223            None
15224        }
15225
15226        let mut selected_larger_symbol = false;
15227        let new_selections = old_selections
15228            .iter()
15229            .map(|selection| match update_selection(selection, &buffer) {
15230                Some(new_selection) => {
15231                    if new_selection.range() != selection.range() {
15232                        selected_larger_symbol = true;
15233                    }
15234                    new_selection
15235                }
15236                None => selection.clone(),
15237            })
15238            .collect::<Vec<_>>();
15239
15240        if selected_larger_symbol {
15241            self.change_selections(Default::default(), window, cx, |s| {
15242                s.select(new_selections);
15243            });
15244        }
15245    }
15246
15247    pub fn select_larger_syntax_node(
15248        &mut self,
15249        _: &SelectLargerSyntaxNode,
15250        window: &mut Window,
15251        cx: &mut Context<Self>,
15252    ) {
15253        let Some(visible_row_count) = self.visible_row_count() else {
15254            return;
15255        };
15256        let old_selections: Box<[_]> = self
15257            .selections
15258            .all::<usize>(&self.display_snapshot(cx))
15259            .into();
15260        if old_selections.is_empty() {
15261            return;
15262        }
15263
15264        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15265
15266        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15267        let buffer = self.buffer.read(cx).snapshot(cx);
15268
15269        let mut selected_larger_node = false;
15270        let mut new_selections = old_selections
15271            .iter()
15272            .map(|selection| {
15273                let old_range = selection.start..selection.end;
15274
15275                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15276                    // manually select word at selection
15277                    if ["string_content", "inline"].contains(&node.kind()) {
15278                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15279                        // ignore if word is already selected
15280                        if !word_range.is_empty() && old_range != word_range {
15281                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15282                            // only select word if start and end point belongs to same word
15283                            if word_range == last_word_range {
15284                                selected_larger_node = true;
15285                                return Selection {
15286                                    id: selection.id,
15287                                    start: word_range.start,
15288                                    end: word_range.end,
15289                                    goal: SelectionGoal::None,
15290                                    reversed: selection.reversed,
15291                                };
15292                            }
15293                        }
15294                    }
15295                }
15296
15297                let mut new_range = old_range.clone();
15298                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15299                    new_range = range;
15300                    if !node.is_named() {
15301                        continue;
15302                    }
15303                    if !display_map.intersects_fold(new_range.start)
15304                        && !display_map.intersects_fold(new_range.end)
15305                    {
15306                        break;
15307                    }
15308                }
15309
15310                selected_larger_node |= new_range != old_range;
15311                Selection {
15312                    id: selection.id,
15313                    start: new_range.start,
15314                    end: new_range.end,
15315                    goal: SelectionGoal::None,
15316                    reversed: selection.reversed,
15317                }
15318            })
15319            .collect::<Vec<_>>();
15320
15321        if !selected_larger_node {
15322            return; // don't put this call in the history
15323        }
15324
15325        // scroll based on transformation done to the last selection created by the user
15326        let (last_old, last_new) = old_selections
15327            .last()
15328            .zip(new_selections.last().cloned())
15329            .expect("old_selections isn't empty");
15330
15331        // revert selection
15332        let is_selection_reversed = {
15333            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15334            new_selections.last_mut().expect("checked above").reversed =
15335                should_newest_selection_be_reversed;
15336            should_newest_selection_be_reversed
15337        };
15338
15339        if selected_larger_node {
15340            self.select_syntax_node_history.disable_clearing = true;
15341            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15342                s.select(new_selections.clone());
15343            });
15344            self.select_syntax_node_history.disable_clearing = false;
15345        }
15346
15347        let start_row = last_new.start.to_display_point(&display_map).row().0;
15348        let end_row = last_new.end.to_display_point(&display_map).row().0;
15349        let selection_height = end_row - start_row + 1;
15350        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15351
15352        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15353        let scroll_behavior = if fits_on_the_screen {
15354            self.request_autoscroll(Autoscroll::fit(), cx);
15355            SelectSyntaxNodeScrollBehavior::FitSelection
15356        } else if is_selection_reversed {
15357            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15358            SelectSyntaxNodeScrollBehavior::CursorTop
15359        } else {
15360            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15361            SelectSyntaxNodeScrollBehavior::CursorBottom
15362        };
15363
15364        self.select_syntax_node_history.push((
15365            old_selections,
15366            scroll_behavior,
15367            is_selection_reversed,
15368        ));
15369    }
15370
15371    pub fn select_smaller_syntax_node(
15372        &mut self,
15373        _: &SelectSmallerSyntaxNode,
15374        window: &mut Window,
15375        cx: &mut Context<Self>,
15376    ) {
15377        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15378
15379        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15380            self.select_syntax_node_history.pop()
15381        {
15382            if let Some(selection) = selections.last_mut() {
15383                selection.reversed = is_selection_reversed;
15384            }
15385
15386            self.select_syntax_node_history.disable_clearing = true;
15387            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15388                s.select(selections.to_vec());
15389            });
15390            self.select_syntax_node_history.disable_clearing = false;
15391
15392            match scroll_behavior {
15393                SelectSyntaxNodeScrollBehavior::CursorTop => {
15394                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15395                }
15396                SelectSyntaxNodeScrollBehavior::FitSelection => {
15397                    self.request_autoscroll(Autoscroll::fit(), cx);
15398                }
15399                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15400                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15401                }
15402            }
15403        }
15404    }
15405
15406    pub fn unwrap_syntax_node(
15407        &mut self,
15408        _: &UnwrapSyntaxNode,
15409        window: &mut Window,
15410        cx: &mut Context<Self>,
15411    ) {
15412        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15413
15414        let buffer = self.buffer.read(cx).snapshot(cx);
15415        let selections = self
15416            .selections
15417            .all::<usize>(&self.display_snapshot(cx))
15418            .into_iter()
15419            // subtracting the offset requires sorting
15420            .sorted_by_key(|i| i.start);
15421
15422        let full_edits = selections
15423            .into_iter()
15424            .filter_map(|selection| {
15425                let child = if selection.is_empty()
15426                    && let Some((_, ancestor_range)) =
15427                        buffer.syntax_ancestor(selection.start..selection.end)
15428                {
15429                    ancestor_range
15430                } else {
15431                    selection.range()
15432                };
15433
15434                let mut parent = child.clone();
15435                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15436                    parent = ancestor_range;
15437                    if parent.start < child.start || parent.end > child.end {
15438                        break;
15439                    }
15440                }
15441
15442                if parent == child {
15443                    return None;
15444                }
15445                let text = buffer.text_for_range(child).collect::<String>();
15446                Some((selection.id, parent, text))
15447            })
15448            .collect::<Vec<_>>();
15449        if full_edits.is_empty() {
15450            return;
15451        }
15452
15453        self.transact(window, cx, |this, window, cx| {
15454            this.buffer.update(cx, |buffer, cx| {
15455                buffer.edit(
15456                    full_edits
15457                        .iter()
15458                        .map(|(_, p, t)| (p.clone(), t.clone()))
15459                        .collect::<Vec<_>>(),
15460                    None,
15461                    cx,
15462                );
15463            });
15464            this.change_selections(Default::default(), window, cx, |s| {
15465                let mut offset = 0;
15466                let mut selections = vec![];
15467                for (id, parent, text) in full_edits {
15468                    let start = parent.start - offset;
15469                    offset += parent.len() - text.len();
15470                    selections.push(Selection {
15471                        id,
15472                        start,
15473                        end: start + text.len(),
15474                        reversed: false,
15475                        goal: Default::default(),
15476                    });
15477                }
15478                s.select(selections);
15479            });
15480        });
15481    }
15482
15483    pub fn select_next_syntax_node(
15484        &mut self,
15485        _: &SelectNextSyntaxNode,
15486        window: &mut Window,
15487        cx: &mut Context<Self>,
15488    ) {
15489        let old_selections: Box<[_]> = self
15490            .selections
15491            .all::<usize>(&self.display_snapshot(cx))
15492            .into();
15493        if old_selections.is_empty() {
15494            return;
15495        }
15496
15497        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15498
15499        let buffer = self.buffer.read(cx).snapshot(cx);
15500        let mut selected_sibling = false;
15501
15502        let new_selections = old_selections
15503            .iter()
15504            .map(|selection| {
15505                let old_range = selection.start..selection.end;
15506
15507                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15508                    let new_range = node.byte_range();
15509                    selected_sibling = true;
15510                    Selection {
15511                        id: selection.id,
15512                        start: new_range.start,
15513                        end: new_range.end,
15514                        goal: SelectionGoal::None,
15515                        reversed: selection.reversed,
15516                    }
15517                } else {
15518                    selection.clone()
15519                }
15520            })
15521            .collect::<Vec<_>>();
15522
15523        if selected_sibling {
15524            self.change_selections(
15525                SelectionEffects::scroll(Autoscroll::fit()),
15526                window,
15527                cx,
15528                |s| {
15529                    s.select(new_selections);
15530                },
15531            );
15532        }
15533    }
15534
15535    pub fn select_prev_syntax_node(
15536        &mut self,
15537        _: &SelectPreviousSyntaxNode,
15538        window: &mut Window,
15539        cx: &mut Context<Self>,
15540    ) {
15541        let old_selections: Box<[_]> = self
15542            .selections
15543            .all::<usize>(&self.display_snapshot(cx))
15544            .into();
15545        if old_selections.is_empty() {
15546            return;
15547        }
15548
15549        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15550
15551        let buffer = self.buffer.read(cx).snapshot(cx);
15552        let mut selected_sibling = false;
15553
15554        let new_selections = old_selections
15555            .iter()
15556            .map(|selection| {
15557                let old_range = selection.start..selection.end;
15558
15559                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15560                    let new_range = node.byte_range();
15561                    selected_sibling = true;
15562                    Selection {
15563                        id: selection.id,
15564                        start: new_range.start,
15565                        end: new_range.end,
15566                        goal: SelectionGoal::None,
15567                        reversed: selection.reversed,
15568                    }
15569                } else {
15570                    selection.clone()
15571                }
15572            })
15573            .collect::<Vec<_>>();
15574
15575        if selected_sibling {
15576            self.change_selections(
15577                SelectionEffects::scroll(Autoscroll::fit()),
15578                window,
15579                cx,
15580                |s| {
15581                    s.select(new_selections);
15582                },
15583            );
15584        }
15585    }
15586
15587    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15588        if !EditorSettings::get_global(cx).gutter.runnables {
15589            self.clear_tasks();
15590            return Task::ready(());
15591        }
15592        let project = self.project().map(Entity::downgrade);
15593        let task_sources = self.lsp_task_sources(cx);
15594        let multi_buffer = self.buffer.downgrade();
15595        cx.spawn_in(window, async move |editor, cx| {
15596            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15597            let Some(project) = project.and_then(|p| p.upgrade()) else {
15598                return;
15599            };
15600            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15601                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15602            }) else {
15603                return;
15604            };
15605
15606            let hide_runnables = project
15607                .update(cx, |project, _| project.is_via_collab())
15608                .unwrap_or(true);
15609            if hide_runnables {
15610                return;
15611            }
15612            let new_rows =
15613                cx.background_spawn({
15614                    let snapshot = display_snapshot.clone();
15615                    async move {
15616                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15617                    }
15618                })
15619                    .await;
15620            let Ok(lsp_tasks) =
15621                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15622            else {
15623                return;
15624            };
15625            let lsp_tasks = lsp_tasks.await;
15626
15627            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15628                lsp_tasks
15629                    .into_iter()
15630                    .flat_map(|(kind, tasks)| {
15631                        tasks.into_iter().filter_map(move |(location, task)| {
15632                            Some((kind.clone(), location?, task))
15633                        })
15634                    })
15635                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15636                        let buffer = location.target.buffer;
15637                        let buffer_snapshot = buffer.read(cx).snapshot();
15638                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15639                            |(excerpt_id, snapshot, _)| {
15640                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15641                                    display_snapshot
15642                                        .buffer_snapshot()
15643                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15644                                } else {
15645                                    None
15646                                }
15647                            },
15648                        );
15649                        if let Some(offset) = offset {
15650                            let task_buffer_range =
15651                                location.target.range.to_point(&buffer_snapshot);
15652                            let context_buffer_range =
15653                                task_buffer_range.to_offset(&buffer_snapshot);
15654                            let context_range = BufferOffset(context_buffer_range.start)
15655                                ..BufferOffset(context_buffer_range.end);
15656
15657                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15658                                .or_insert_with(|| RunnableTasks {
15659                                    templates: Vec::new(),
15660                                    offset,
15661                                    column: task_buffer_range.start.column,
15662                                    extra_variables: HashMap::default(),
15663                                    context_range,
15664                                })
15665                                .templates
15666                                .push((kind, task.original_task().clone()));
15667                        }
15668
15669                        acc
15670                    })
15671            }) else {
15672                return;
15673            };
15674
15675            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15676                buffer.language_settings(cx).tasks.prefer_lsp
15677            }) else {
15678                return;
15679            };
15680
15681            let rows = Self::runnable_rows(
15682                project,
15683                display_snapshot,
15684                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15685                new_rows,
15686                cx.clone(),
15687            )
15688            .await;
15689            editor
15690                .update(cx, |editor, _| {
15691                    editor.clear_tasks();
15692                    for (key, mut value) in rows {
15693                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15694                            value.templates.extend(lsp_tasks.templates);
15695                        }
15696
15697                        editor.insert_tasks(key, value);
15698                    }
15699                    for (key, value) in lsp_tasks_by_rows {
15700                        editor.insert_tasks(key, value);
15701                    }
15702                })
15703                .ok();
15704        })
15705    }
15706    fn fetch_runnable_ranges(
15707        snapshot: &DisplaySnapshot,
15708        range: Range<Anchor>,
15709    ) -> Vec<language::RunnableRange> {
15710        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15711    }
15712
15713    fn runnable_rows(
15714        project: Entity<Project>,
15715        snapshot: DisplaySnapshot,
15716        prefer_lsp: bool,
15717        runnable_ranges: Vec<RunnableRange>,
15718        cx: AsyncWindowContext,
15719    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15720        cx.spawn(async move |cx| {
15721            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15722            for mut runnable in runnable_ranges {
15723                let Some(tasks) = cx
15724                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15725                    .ok()
15726                else {
15727                    continue;
15728                };
15729                let mut tasks = tasks.await;
15730
15731                if prefer_lsp {
15732                    tasks.retain(|(task_kind, _)| {
15733                        !matches!(task_kind, TaskSourceKind::Language { .. })
15734                    });
15735                }
15736                if tasks.is_empty() {
15737                    continue;
15738                }
15739
15740                let point = runnable
15741                    .run_range
15742                    .start
15743                    .to_point(&snapshot.buffer_snapshot());
15744                let Some(row) = snapshot
15745                    .buffer_snapshot()
15746                    .buffer_line_for_row(MultiBufferRow(point.row))
15747                    .map(|(_, range)| range.start.row)
15748                else {
15749                    continue;
15750                };
15751
15752                let context_range =
15753                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15754                runnable_rows.push((
15755                    (runnable.buffer_id, row),
15756                    RunnableTasks {
15757                        templates: tasks,
15758                        offset: snapshot
15759                            .buffer_snapshot()
15760                            .anchor_before(runnable.run_range.start),
15761                        context_range,
15762                        column: point.column,
15763                        extra_variables: runnable.extra_captures,
15764                    },
15765                ));
15766            }
15767            runnable_rows
15768        })
15769    }
15770
15771    fn templates_with_tags(
15772        project: &Entity<Project>,
15773        runnable: &mut Runnable,
15774        cx: &mut App,
15775    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15776        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15777            let (worktree_id, file) = project
15778                .buffer_for_id(runnable.buffer, cx)
15779                .and_then(|buffer| buffer.read(cx).file())
15780                .map(|file| (file.worktree_id(cx), file.clone()))
15781                .unzip();
15782
15783            (
15784                project.task_store().read(cx).task_inventory().cloned(),
15785                worktree_id,
15786                file,
15787            )
15788        });
15789
15790        let tags = mem::take(&mut runnable.tags);
15791        let language = runnable.language.clone();
15792        cx.spawn(async move |cx| {
15793            let mut templates_with_tags = Vec::new();
15794            if let Some(inventory) = inventory {
15795                for RunnableTag(tag) in tags {
15796                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15797                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15798                    }) else {
15799                        return templates_with_tags;
15800                    };
15801                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15802                        move |(_, template)| {
15803                            template.tags.iter().any(|source_tag| source_tag == &tag)
15804                        },
15805                    ));
15806                }
15807            }
15808            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15809
15810            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15811                // Strongest source wins; if we have worktree tag binding, prefer that to
15812                // global and language bindings;
15813                // if we have a global binding, prefer that to language binding.
15814                let first_mismatch = templates_with_tags
15815                    .iter()
15816                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15817                if let Some(index) = first_mismatch {
15818                    templates_with_tags.truncate(index);
15819                }
15820            }
15821
15822            templates_with_tags
15823        })
15824    }
15825
15826    pub fn move_to_enclosing_bracket(
15827        &mut self,
15828        _: &MoveToEnclosingBracket,
15829        window: &mut Window,
15830        cx: &mut Context<Self>,
15831    ) {
15832        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15833        self.change_selections(Default::default(), window, cx, |s| {
15834            s.move_offsets_with(|snapshot, selection| {
15835                let Some(enclosing_bracket_ranges) =
15836                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15837                else {
15838                    return;
15839                };
15840
15841                let mut best_length = usize::MAX;
15842                let mut best_inside = false;
15843                let mut best_in_bracket_range = false;
15844                let mut best_destination = None;
15845                for (open, close) in enclosing_bracket_ranges {
15846                    let close = close.to_inclusive();
15847                    let length = close.end() - open.start;
15848                    let inside = selection.start >= open.end && selection.end <= *close.start();
15849                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15850                        || close.contains(&selection.head());
15851
15852                    // If best is next to a bracket and current isn't, skip
15853                    if !in_bracket_range && best_in_bracket_range {
15854                        continue;
15855                    }
15856
15857                    // Prefer smaller lengths unless best is inside and current isn't
15858                    if length > best_length && (best_inside || !inside) {
15859                        continue;
15860                    }
15861
15862                    best_length = length;
15863                    best_inside = inside;
15864                    best_in_bracket_range = in_bracket_range;
15865                    best_destination = Some(
15866                        if close.contains(&selection.start) && close.contains(&selection.end) {
15867                            if inside { open.end } else { open.start }
15868                        } else if inside {
15869                            *close.start()
15870                        } else {
15871                            *close.end()
15872                        },
15873                    );
15874                }
15875
15876                if let Some(destination) = best_destination {
15877                    selection.collapse_to(destination, SelectionGoal::None);
15878                }
15879            })
15880        });
15881    }
15882
15883    pub fn undo_selection(
15884        &mut self,
15885        _: &UndoSelection,
15886        window: &mut Window,
15887        cx: &mut Context<Self>,
15888    ) {
15889        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15890        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15891            self.selection_history.mode = SelectionHistoryMode::Undoing;
15892            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15893                this.end_selection(window, cx);
15894                this.change_selections(
15895                    SelectionEffects::scroll(Autoscroll::newest()),
15896                    window,
15897                    cx,
15898                    |s| s.select_anchors(entry.selections.to_vec()),
15899                );
15900            });
15901            self.selection_history.mode = SelectionHistoryMode::Normal;
15902
15903            self.select_next_state = entry.select_next_state;
15904            self.select_prev_state = entry.select_prev_state;
15905            self.add_selections_state = entry.add_selections_state;
15906        }
15907    }
15908
15909    pub fn redo_selection(
15910        &mut self,
15911        _: &RedoSelection,
15912        window: &mut Window,
15913        cx: &mut Context<Self>,
15914    ) {
15915        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15916        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15917            self.selection_history.mode = SelectionHistoryMode::Redoing;
15918            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15919                this.end_selection(window, cx);
15920                this.change_selections(
15921                    SelectionEffects::scroll(Autoscroll::newest()),
15922                    window,
15923                    cx,
15924                    |s| s.select_anchors(entry.selections.to_vec()),
15925                );
15926            });
15927            self.selection_history.mode = SelectionHistoryMode::Normal;
15928
15929            self.select_next_state = entry.select_next_state;
15930            self.select_prev_state = entry.select_prev_state;
15931            self.add_selections_state = entry.add_selections_state;
15932        }
15933    }
15934
15935    pub fn expand_excerpts(
15936        &mut self,
15937        action: &ExpandExcerpts,
15938        _: &mut Window,
15939        cx: &mut Context<Self>,
15940    ) {
15941        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15942    }
15943
15944    pub fn expand_excerpts_down(
15945        &mut self,
15946        action: &ExpandExcerptsDown,
15947        _: &mut Window,
15948        cx: &mut Context<Self>,
15949    ) {
15950        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15951    }
15952
15953    pub fn expand_excerpts_up(
15954        &mut self,
15955        action: &ExpandExcerptsUp,
15956        _: &mut Window,
15957        cx: &mut Context<Self>,
15958    ) {
15959        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15960    }
15961
15962    pub fn expand_excerpts_for_direction(
15963        &mut self,
15964        lines: u32,
15965        direction: ExpandExcerptDirection,
15966
15967        cx: &mut Context<Self>,
15968    ) {
15969        let selections = self.selections.disjoint_anchors_arc();
15970
15971        let lines = if lines == 0 {
15972            EditorSettings::get_global(cx).expand_excerpt_lines
15973        } else {
15974            lines
15975        };
15976
15977        self.buffer.update(cx, |buffer, cx| {
15978            let snapshot = buffer.snapshot(cx);
15979            let mut excerpt_ids = selections
15980                .iter()
15981                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15982                .collect::<Vec<_>>();
15983            excerpt_ids.sort();
15984            excerpt_ids.dedup();
15985            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15986        })
15987    }
15988
15989    pub fn expand_excerpt(
15990        &mut self,
15991        excerpt: ExcerptId,
15992        direction: ExpandExcerptDirection,
15993        window: &mut Window,
15994        cx: &mut Context<Self>,
15995    ) {
15996        let current_scroll_position = self.scroll_position(cx);
15997        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15998        let mut scroll = None;
15999
16000        if direction == ExpandExcerptDirection::Down {
16001            let multi_buffer = self.buffer.read(cx);
16002            let snapshot = multi_buffer.snapshot(cx);
16003            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16004                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16005                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16006            {
16007                let buffer_snapshot = buffer.read(cx).snapshot();
16008                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16009                let last_row = buffer_snapshot.max_point().row;
16010                let lines_below = last_row.saturating_sub(excerpt_end_row);
16011                if lines_below >= lines_to_expand {
16012                    scroll = Some(
16013                        current_scroll_position
16014                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
16015                    );
16016                }
16017            }
16018        }
16019        if direction == ExpandExcerptDirection::Up
16020            && self
16021                .buffer
16022                .read(cx)
16023                .snapshot(cx)
16024                .excerpt_before(excerpt)
16025                .is_none()
16026        {
16027            scroll = Some(current_scroll_position);
16028        }
16029
16030        self.buffer.update(cx, |buffer, cx| {
16031            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16032        });
16033
16034        if let Some(new_scroll_position) = scroll {
16035            self.set_scroll_position(new_scroll_position, window, cx);
16036        }
16037    }
16038
16039    pub fn go_to_singleton_buffer_point(
16040        &mut self,
16041        point: Point,
16042        window: &mut Window,
16043        cx: &mut Context<Self>,
16044    ) {
16045        self.go_to_singleton_buffer_range(point..point, window, cx);
16046    }
16047
16048    pub fn go_to_singleton_buffer_range(
16049        &mut self,
16050        range: Range<Point>,
16051        window: &mut Window,
16052        cx: &mut Context<Self>,
16053    ) {
16054        let multibuffer = self.buffer().read(cx);
16055        let Some(buffer) = multibuffer.as_singleton() else {
16056            return;
16057        };
16058        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16059            return;
16060        };
16061        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16062            return;
16063        };
16064        self.change_selections(
16065            SelectionEffects::default().nav_history(true),
16066            window,
16067            cx,
16068            |s| s.select_anchor_ranges([start..end]),
16069        );
16070    }
16071
16072    pub fn go_to_diagnostic(
16073        &mut self,
16074        action: &GoToDiagnostic,
16075        window: &mut Window,
16076        cx: &mut Context<Self>,
16077    ) {
16078        if !self.diagnostics_enabled() {
16079            return;
16080        }
16081        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16082        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16083    }
16084
16085    pub fn go_to_prev_diagnostic(
16086        &mut self,
16087        action: &GoToPreviousDiagnostic,
16088        window: &mut Window,
16089        cx: &mut Context<Self>,
16090    ) {
16091        if !self.diagnostics_enabled() {
16092            return;
16093        }
16094        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16095        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16096    }
16097
16098    pub fn go_to_diagnostic_impl(
16099        &mut self,
16100        direction: Direction,
16101        severity: GoToDiagnosticSeverityFilter,
16102        window: &mut Window,
16103        cx: &mut Context<Self>,
16104    ) {
16105        let buffer = self.buffer.read(cx).snapshot(cx);
16106        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
16107
16108        let mut active_group_id = None;
16109        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16110            && active_group.active_range.start.to_offset(&buffer) == selection.start
16111        {
16112            active_group_id = Some(active_group.group_id);
16113        }
16114
16115        fn filtered<'a>(
16116            severity: GoToDiagnosticSeverityFilter,
16117            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
16118        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
16119            diagnostics
16120                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16121                .filter(|entry| entry.range.start != entry.range.end)
16122                .filter(|entry| !entry.diagnostic.is_unnecessary)
16123        }
16124
16125        let before = filtered(
16126            severity,
16127            buffer
16128                .diagnostics_in_range(0..selection.start)
16129                .filter(|entry| entry.range.start <= selection.start),
16130        );
16131        let after = filtered(
16132            severity,
16133            buffer
16134                .diagnostics_in_range(selection.start..buffer.len())
16135                .filter(|entry| entry.range.start >= selection.start),
16136        );
16137
16138        let mut found: Option<DiagnosticEntryRef<usize>> = None;
16139        if direction == Direction::Prev {
16140            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16141            {
16142                for diagnostic in prev_diagnostics.into_iter().rev() {
16143                    if diagnostic.range.start != selection.start
16144                        || active_group_id
16145                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16146                    {
16147                        found = Some(diagnostic);
16148                        break 'outer;
16149                    }
16150                }
16151            }
16152        } else {
16153            for diagnostic in after.chain(before) {
16154                if diagnostic.range.start != selection.start
16155                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16156                {
16157                    found = Some(diagnostic);
16158                    break;
16159                }
16160            }
16161        }
16162        let Some(next_diagnostic) = found else {
16163            return;
16164        };
16165
16166        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16167        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16168            return;
16169        };
16170        let snapshot = self.snapshot(window, cx);
16171        if snapshot.intersects_fold(next_diagnostic.range.start) {
16172            self.unfold_ranges(
16173                std::slice::from_ref(&next_diagnostic.range),
16174                true,
16175                false,
16176                cx,
16177            );
16178        }
16179        self.change_selections(Default::default(), window, cx, |s| {
16180            s.select_ranges(vec![
16181                next_diagnostic.range.start..next_diagnostic.range.start,
16182            ])
16183        });
16184        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16185        self.refresh_edit_prediction(false, true, window, cx);
16186    }
16187
16188    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16189        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16190        let snapshot = self.snapshot(window, cx);
16191        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16192        self.go_to_hunk_before_or_after_position(
16193            &snapshot,
16194            selection.head(),
16195            Direction::Next,
16196            window,
16197            cx,
16198        );
16199    }
16200
16201    pub fn go_to_hunk_before_or_after_position(
16202        &mut self,
16203        snapshot: &EditorSnapshot,
16204        position: Point,
16205        direction: Direction,
16206        window: &mut Window,
16207        cx: &mut Context<Editor>,
16208    ) {
16209        let row = if direction == Direction::Next {
16210            self.hunk_after_position(snapshot, position)
16211                .map(|hunk| hunk.row_range.start)
16212        } else {
16213            self.hunk_before_position(snapshot, position)
16214        };
16215
16216        if let Some(row) = row {
16217            let destination = Point::new(row.0, 0);
16218            let autoscroll = Autoscroll::center();
16219
16220            self.unfold_ranges(&[destination..destination], false, false, cx);
16221            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16222                s.select_ranges([destination..destination]);
16223            });
16224        }
16225    }
16226
16227    fn hunk_after_position(
16228        &mut self,
16229        snapshot: &EditorSnapshot,
16230        position: Point,
16231    ) -> Option<MultiBufferDiffHunk> {
16232        snapshot
16233            .buffer_snapshot()
16234            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16235            .find(|hunk| hunk.row_range.start.0 > position.row)
16236            .or_else(|| {
16237                snapshot
16238                    .buffer_snapshot()
16239                    .diff_hunks_in_range(Point::zero()..position)
16240                    .find(|hunk| hunk.row_range.end.0 < position.row)
16241            })
16242    }
16243
16244    fn go_to_prev_hunk(
16245        &mut self,
16246        _: &GoToPreviousHunk,
16247        window: &mut Window,
16248        cx: &mut Context<Self>,
16249    ) {
16250        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16251        let snapshot = self.snapshot(window, cx);
16252        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16253        self.go_to_hunk_before_or_after_position(
16254            &snapshot,
16255            selection.head(),
16256            Direction::Prev,
16257            window,
16258            cx,
16259        );
16260    }
16261
16262    fn hunk_before_position(
16263        &mut self,
16264        snapshot: &EditorSnapshot,
16265        position: Point,
16266    ) -> Option<MultiBufferRow> {
16267        snapshot
16268            .buffer_snapshot()
16269            .diff_hunk_before(position)
16270            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16271    }
16272
16273    fn go_to_next_change(
16274        &mut self,
16275        _: &GoToNextChange,
16276        window: &mut Window,
16277        cx: &mut Context<Self>,
16278    ) {
16279        if let Some(selections) = self
16280            .change_list
16281            .next_change(1, Direction::Next)
16282            .map(|s| s.to_vec())
16283        {
16284            self.change_selections(Default::default(), window, cx, |s| {
16285                let map = s.display_snapshot();
16286                s.select_display_ranges(selections.iter().map(|a| {
16287                    let point = a.to_display_point(&map);
16288                    point..point
16289                }))
16290            })
16291        }
16292    }
16293
16294    fn go_to_previous_change(
16295        &mut self,
16296        _: &GoToPreviousChange,
16297        window: &mut Window,
16298        cx: &mut Context<Self>,
16299    ) {
16300        if let Some(selections) = self
16301            .change_list
16302            .next_change(1, Direction::Prev)
16303            .map(|s| s.to_vec())
16304        {
16305            self.change_selections(Default::default(), window, cx, |s| {
16306                let map = s.display_snapshot();
16307                s.select_display_ranges(selections.iter().map(|a| {
16308                    let point = a.to_display_point(&map);
16309                    point..point
16310                }))
16311            })
16312        }
16313    }
16314
16315    pub fn go_to_next_document_highlight(
16316        &mut self,
16317        _: &GoToNextDocumentHighlight,
16318        window: &mut Window,
16319        cx: &mut Context<Self>,
16320    ) {
16321        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16322    }
16323
16324    pub fn go_to_prev_document_highlight(
16325        &mut self,
16326        _: &GoToPreviousDocumentHighlight,
16327        window: &mut Window,
16328        cx: &mut Context<Self>,
16329    ) {
16330        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16331    }
16332
16333    pub fn go_to_document_highlight_before_or_after_position(
16334        &mut self,
16335        direction: Direction,
16336        window: &mut Window,
16337        cx: &mut Context<Editor>,
16338    ) {
16339        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16340        let snapshot = self.snapshot(window, cx);
16341        let buffer = &snapshot.buffer_snapshot();
16342        let position = self
16343            .selections
16344            .newest::<Point>(&snapshot.display_snapshot)
16345            .head();
16346        let anchor_position = buffer.anchor_after(position);
16347
16348        // Get all document highlights (both read and write)
16349        let mut all_highlights = Vec::new();
16350
16351        if let Some((_, read_highlights)) = self
16352            .background_highlights
16353            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16354        {
16355            all_highlights.extend(read_highlights.iter());
16356        }
16357
16358        if let Some((_, write_highlights)) = self
16359            .background_highlights
16360            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16361        {
16362            all_highlights.extend(write_highlights.iter());
16363        }
16364
16365        if all_highlights.is_empty() {
16366            return;
16367        }
16368
16369        // Sort highlights by position
16370        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16371
16372        let target_highlight = match direction {
16373            Direction::Next => {
16374                // Find the first highlight after the current position
16375                all_highlights
16376                    .iter()
16377                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16378            }
16379            Direction::Prev => {
16380                // Find the last highlight before the current position
16381                all_highlights
16382                    .iter()
16383                    .rev()
16384                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16385            }
16386        };
16387
16388        if let Some(highlight) = target_highlight {
16389            let destination = highlight.start.to_point(buffer);
16390            let autoscroll = Autoscroll::center();
16391
16392            self.unfold_ranges(&[destination..destination], false, false, cx);
16393            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16394                s.select_ranges([destination..destination]);
16395            });
16396        }
16397    }
16398
16399    fn go_to_line<T: 'static>(
16400        &mut self,
16401        position: Anchor,
16402        highlight_color: Option<Hsla>,
16403        window: &mut Window,
16404        cx: &mut Context<Self>,
16405    ) {
16406        let snapshot = self.snapshot(window, cx).display_snapshot;
16407        let position = position.to_point(&snapshot.buffer_snapshot());
16408        let start = snapshot
16409            .buffer_snapshot()
16410            .clip_point(Point::new(position.row, 0), Bias::Left);
16411        let end = start + Point::new(1, 0);
16412        let start = snapshot.buffer_snapshot().anchor_before(start);
16413        let end = snapshot.buffer_snapshot().anchor_before(end);
16414
16415        self.highlight_rows::<T>(
16416            start..end,
16417            highlight_color
16418                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16419            Default::default(),
16420            cx,
16421        );
16422
16423        if self.buffer.read(cx).is_singleton() {
16424            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16425        }
16426    }
16427
16428    pub fn go_to_definition(
16429        &mut self,
16430        _: &GoToDefinition,
16431        window: &mut Window,
16432        cx: &mut Context<Self>,
16433    ) -> Task<Result<Navigated>> {
16434        let definition =
16435            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16436        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16437        cx.spawn_in(window, async move |editor, cx| {
16438            if definition.await? == Navigated::Yes {
16439                return Ok(Navigated::Yes);
16440            }
16441            match fallback_strategy {
16442                GoToDefinitionFallback::None => Ok(Navigated::No),
16443                GoToDefinitionFallback::FindAllReferences => {
16444                    match editor.update_in(cx, |editor, window, cx| {
16445                        editor.find_all_references(&FindAllReferences, window, cx)
16446                    })? {
16447                        Some(references) => references.await,
16448                        None => Ok(Navigated::No),
16449                    }
16450                }
16451            }
16452        })
16453    }
16454
16455    pub fn go_to_declaration(
16456        &mut self,
16457        _: &GoToDeclaration,
16458        window: &mut Window,
16459        cx: &mut Context<Self>,
16460    ) -> Task<Result<Navigated>> {
16461        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16462    }
16463
16464    pub fn go_to_declaration_split(
16465        &mut self,
16466        _: &GoToDeclaration,
16467        window: &mut Window,
16468        cx: &mut Context<Self>,
16469    ) -> Task<Result<Navigated>> {
16470        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16471    }
16472
16473    pub fn go_to_implementation(
16474        &mut self,
16475        _: &GoToImplementation,
16476        window: &mut Window,
16477        cx: &mut Context<Self>,
16478    ) -> Task<Result<Navigated>> {
16479        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16480    }
16481
16482    pub fn go_to_implementation_split(
16483        &mut self,
16484        _: &GoToImplementationSplit,
16485        window: &mut Window,
16486        cx: &mut Context<Self>,
16487    ) -> Task<Result<Navigated>> {
16488        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16489    }
16490
16491    pub fn go_to_type_definition(
16492        &mut self,
16493        _: &GoToTypeDefinition,
16494        window: &mut Window,
16495        cx: &mut Context<Self>,
16496    ) -> Task<Result<Navigated>> {
16497        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16498    }
16499
16500    pub fn go_to_definition_split(
16501        &mut self,
16502        _: &GoToDefinitionSplit,
16503        window: &mut Window,
16504        cx: &mut Context<Self>,
16505    ) -> Task<Result<Navigated>> {
16506        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16507    }
16508
16509    pub fn go_to_type_definition_split(
16510        &mut self,
16511        _: &GoToTypeDefinitionSplit,
16512        window: &mut Window,
16513        cx: &mut Context<Self>,
16514    ) -> Task<Result<Navigated>> {
16515        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16516    }
16517
16518    fn go_to_definition_of_kind(
16519        &mut self,
16520        kind: GotoDefinitionKind,
16521        split: bool,
16522        window: &mut Window,
16523        cx: &mut Context<Self>,
16524    ) -> Task<Result<Navigated>> {
16525        let Some(provider) = self.semantics_provider.clone() else {
16526            return Task::ready(Ok(Navigated::No));
16527        };
16528        let head = self
16529            .selections
16530            .newest::<usize>(&self.display_snapshot(cx))
16531            .head();
16532        let buffer = self.buffer.read(cx);
16533        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16534            return Task::ready(Ok(Navigated::No));
16535        };
16536        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16537            return Task::ready(Ok(Navigated::No));
16538        };
16539
16540        cx.spawn_in(window, async move |editor, cx| {
16541            let Some(definitions) = definitions.await? else {
16542                return Ok(Navigated::No);
16543            };
16544            let navigated = editor
16545                .update_in(cx, |editor, window, cx| {
16546                    editor.navigate_to_hover_links(
16547                        Some(kind),
16548                        definitions
16549                            .into_iter()
16550                            .filter(|location| {
16551                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16552                            })
16553                            .map(HoverLink::Text)
16554                            .collect::<Vec<_>>(),
16555                        split,
16556                        window,
16557                        cx,
16558                    )
16559                })?
16560                .await?;
16561            anyhow::Ok(navigated)
16562        })
16563    }
16564
16565    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16566        let selection = self.selections.newest_anchor();
16567        let head = selection.head();
16568        let tail = selection.tail();
16569
16570        let Some((buffer, start_position)) =
16571            self.buffer.read(cx).text_anchor_for_position(head, cx)
16572        else {
16573            return;
16574        };
16575
16576        let end_position = if head != tail {
16577            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16578                return;
16579            };
16580            Some(pos)
16581        } else {
16582            None
16583        };
16584
16585        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16586            let url = if let Some(end_pos) = end_position {
16587                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16588            } else {
16589                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16590            };
16591
16592            if let Some(url) = url {
16593                cx.update(|window, cx| {
16594                    if parse_zed_link(&url, cx).is_some() {
16595                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16596                    } else {
16597                        cx.open_url(&url);
16598                    }
16599                })?;
16600            }
16601
16602            anyhow::Ok(())
16603        });
16604
16605        url_finder.detach();
16606    }
16607
16608    pub fn open_selected_filename(
16609        &mut self,
16610        _: &OpenSelectedFilename,
16611        window: &mut Window,
16612        cx: &mut Context<Self>,
16613    ) {
16614        let Some(workspace) = self.workspace() else {
16615            return;
16616        };
16617
16618        let position = self.selections.newest_anchor().head();
16619
16620        let Some((buffer, buffer_position)) =
16621            self.buffer.read(cx).text_anchor_for_position(position, cx)
16622        else {
16623            return;
16624        };
16625
16626        let project = self.project.clone();
16627
16628        cx.spawn_in(window, async move |_, cx| {
16629            let result = find_file(&buffer, project, buffer_position, cx).await;
16630
16631            if let Some((_, path)) = result {
16632                workspace
16633                    .update_in(cx, |workspace, window, cx| {
16634                        workspace.open_resolved_path(path, window, cx)
16635                    })?
16636                    .await?;
16637            }
16638            anyhow::Ok(())
16639        })
16640        .detach();
16641    }
16642
16643    pub(crate) fn navigate_to_hover_links(
16644        &mut self,
16645        kind: Option<GotoDefinitionKind>,
16646        definitions: Vec<HoverLink>,
16647        split: bool,
16648        window: &mut Window,
16649        cx: &mut Context<Editor>,
16650    ) -> Task<Result<Navigated>> {
16651        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16652        let mut first_url_or_file = None;
16653        let definitions: Vec<_> = definitions
16654            .into_iter()
16655            .filter_map(|def| match def {
16656                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16657                HoverLink::InlayHint(lsp_location, server_id) => {
16658                    let computation =
16659                        self.compute_target_location(lsp_location, server_id, window, cx);
16660                    Some(cx.background_spawn(computation))
16661                }
16662                HoverLink::Url(url) => {
16663                    first_url_or_file = Some(Either::Left(url));
16664                    None
16665                }
16666                HoverLink::File(path) => {
16667                    first_url_or_file = Some(Either::Right(path));
16668                    None
16669                }
16670            })
16671            .collect();
16672
16673        let workspace = self.workspace();
16674
16675        cx.spawn_in(window, async move |editor, cx| {
16676            let locations: Vec<Location> = future::join_all(definitions)
16677                .await
16678                .into_iter()
16679                .filter_map(|location| location.transpose())
16680                .collect::<Result<_>>()
16681                .context("location tasks")?;
16682            let mut locations = cx.update(|_, cx| {
16683                locations
16684                    .into_iter()
16685                    .map(|location| {
16686                        let buffer = location.buffer.read(cx);
16687                        (location.buffer, location.range.to_point(buffer))
16688                    })
16689                    .into_group_map()
16690            })?;
16691            let mut num_locations = 0;
16692            for ranges in locations.values_mut() {
16693                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16694                ranges.dedup();
16695                num_locations += ranges.len();
16696            }
16697
16698            if num_locations > 1 {
16699                let Some(workspace) = workspace else {
16700                    return Ok(Navigated::No);
16701                };
16702
16703                let tab_kind = match kind {
16704                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16705                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16706                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16707                    Some(GotoDefinitionKind::Type) => "Types",
16708                };
16709                let title = editor
16710                    .update_in(cx, |_, _, cx| {
16711                        let target = locations
16712                            .iter()
16713                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16714                            .map(|(buffer, location)| {
16715                                buffer
16716                                    .read(cx)
16717                                    .text_for_range(location.clone())
16718                                    .collect::<String>()
16719                            })
16720                            .filter(|text| !text.contains('\n'))
16721                            .unique()
16722                            .take(3)
16723                            .join(", ");
16724                        if target.is_empty() {
16725                            tab_kind.to_owned()
16726                        } else {
16727                            format!("{tab_kind} for {target}")
16728                        }
16729                    })
16730                    .context("buffer title")?;
16731
16732                let opened = workspace
16733                    .update_in(cx, |workspace, window, cx| {
16734                        Self::open_locations_in_multibuffer(
16735                            workspace,
16736                            locations,
16737                            title,
16738                            split,
16739                            MultibufferSelectionMode::First,
16740                            window,
16741                            cx,
16742                        )
16743                    })
16744                    .is_ok();
16745
16746                anyhow::Ok(Navigated::from_bool(opened))
16747            } else if num_locations == 0 {
16748                // If there is one url or file, open it directly
16749                match first_url_or_file {
16750                    Some(Either::Left(url)) => {
16751                        cx.update(|_, cx| cx.open_url(&url))?;
16752                        Ok(Navigated::Yes)
16753                    }
16754                    Some(Either::Right(path)) => {
16755                        let Some(workspace) = workspace else {
16756                            return Ok(Navigated::No);
16757                        };
16758
16759                        workspace
16760                            .update_in(cx, |workspace, window, cx| {
16761                                workspace.open_resolved_path(path, window, cx)
16762                            })?
16763                            .await?;
16764                        Ok(Navigated::Yes)
16765                    }
16766                    None => Ok(Navigated::No),
16767                }
16768            } else {
16769                let Some(workspace) = workspace else {
16770                    return Ok(Navigated::No);
16771                };
16772
16773                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16774                let target_range = target_ranges.first().unwrap().clone();
16775
16776                editor.update_in(cx, |editor, window, cx| {
16777                    let range = target_range.to_point(target_buffer.read(cx));
16778                    let range = editor.range_for_match(&range, false);
16779                    let range = collapse_multiline_range(range);
16780
16781                    if !split
16782                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16783                    {
16784                        editor.go_to_singleton_buffer_range(range, window, cx);
16785                    } else {
16786                        let pane = workspace.read(cx).active_pane().clone();
16787                        window.defer(cx, move |window, cx| {
16788                            let target_editor: Entity<Self> =
16789                                workspace.update(cx, |workspace, cx| {
16790                                    let pane = if split {
16791                                        workspace.adjacent_pane(window, cx)
16792                                    } else {
16793                                        workspace.active_pane().clone()
16794                                    };
16795
16796                                    workspace.open_project_item(
16797                                        pane,
16798                                        target_buffer.clone(),
16799                                        true,
16800                                        true,
16801                                        window,
16802                                        cx,
16803                                    )
16804                                });
16805                            target_editor.update(cx, |target_editor, cx| {
16806                                // When selecting a definition in a different buffer, disable the nav history
16807                                // to avoid creating a history entry at the previous cursor location.
16808                                pane.update(cx, |pane, _| pane.disable_history());
16809                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16810                                pane.update(cx, |pane, _| pane.enable_history());
16811                            });
16812                        });
16813                    }
16814                    Navigated::Yes
16815                })
16816            }
16817        })
16818    }
16819
16820    fn compute_target_location(
16821        &self,
16822        lsp_location: lsp::Location,
16823        server_id: LanguageServerId,
16824        window: &mut Window,
16825        cx: &mut Context<Self>,
16826    ) -> Task<anyhow::Result<Option<Location>>> {
16827        let Some(project) = self.project.clone() else {
16828            return Task::ready(Ok(None));
16829        };
16830
16831        cx.spawn_in(window, async move |editor, cx| {
16832            let location_task = editor.update(cx, |_, cx| {
16833                project.update(cx, |project, cx| {
16834                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16835                })
16836            })?;
16837            let location = Some({
16838                let target_buffer_handle = location_task.await.context("open local buffer")?;
16839                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16840                    let target_start = target_buffer
16841                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16842                    let target_end = target_buffer
16843                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16844                    target_buffer.anchor_after(target_start)
16845                        ..target_buffer.anchor_before(target_end)
16846                })?;
16847                Location {
16848                    buffer: target_buffer_handle,
16849                    range,
16850                }
16851            });
16852            Ok(location)
16853        })
16854    }
16855
16856    fn go_to_next_reference(
16857        &mut self,
16858        _: &GoToNextReference,
16859        window: &mut Window,
16860        cx: &mut Context<Self>,
16861    ) {
16862        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
16863        if let Some(task) = task {
16864            task.detach();
16865        };
16866    }
16867
16868    fn go_to_prev_reference(
16869        &mut self,
16870        _: &GoToPreviousReference,
16871        window: &mut Window,
16872        cx: &mut Context<Self>,
16873    ) {
16874        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
16875        if let Some(task) = task {
16876            task.detach();
16877        };
16878    }
16879
16880    pub fn go_to_reference_before_or_after_position(
16881        &mut self,
16882        direction: Direction,
16883        count: usize,
16884        window: &mut Window,
16885        cx: &mut Context<Self>,
16886    ) -> Option<Task<Result<()>>> {
16887        let selection = self.selections.newest_anchor();
16888        let head = selection.head();
16889
16890        let multi_buffer = self.buffer.read(cx);
16891
16892        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
16893        let workspace = self.workspace()?;
16894        let project = workspace.read(cx).project().clone();
16895        let references =
16896            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
16897        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
16898            let Some(locations) = references.await? else {
16899                return Ok(());
16900            };
16901
16902            if locations.is_empty() {
16903                // totally normal - the cursor may be on something which is not
16904                // a symbol (e.g. a keyword)
16905                log::info!("no references found under cursor");
16906                return Ok(());
16907            }
16908
16909            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
16910
16911            let multi_buffer_snapshot =
16912                multi_buffer.read_with(cx, |multi_buffer, cx| multi_buffer.snapshot(cx))?;
16913
16914            let (locations, current_location_index) =
16915                multi_buffer.update(cx, |multi_buffer, cx| {
16916                    let mut locations = locations
16917                        .into_iter()
16918                        .filter_map(|loc| {
16919                            let start = multi_buffer.buffer_anchor_to_anchor(
16920                                &loc.buffer,
16921                                loc.range.start,
16922                                cx,
16923                            )?;
16924                            let end = multi_buffer.buffer_anchor_to_anchor(
16925                                &loc.buffer,
16926                                loc.range.end,
16927                                cx,
16928                            )?;
16929                            Some(start..end)
16930                        })
16931                        .collect::<Vec<_>>();
16932
16933                    // There is an O(n) implementation, but given this list will be
16934                    // small (usually <100 items), the extra O(log(n)) factor isn't
16935                    // worth the (surprisingly large amount of) extra complexity.
16936                    locations
16937                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
16938
16939                    let head_offset = head.to_offset(&multi_buffer_snapshot);
16940
16941                    let current_location_index = locations.iter().position(|loc| {
16942                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
16943                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
16944                    });
16945
16946                    (locations, current_location_index)
16947                })?;
16948
16949            let Some(current_location_index) = current_location_index else {
16950                // This indicates something has gone wrong, because we already
16951                // handle the "no references" case above
16952                log::error!(
16953                    "failed to find current reference under cursor. Total references: {}",
16954                    locations.len()
16955                );
16956                return Ok(());
16957            };
16958
16959            let destination_location_index = match direction {
16960                Direction::Next => (current_location_index + count) % locations.len(),
16961                Direction::Prev => {
16962                    (current_location_index + locations.len() - count % locations.len())
16963                        % locations.len()
16964                }
16965            };
16966
16967            // TODO(cameron): is this needed?
16968            // the thinking is to avoid "jumping to the current location" (avoid
16969            // polluting "jumplist" in vim terms)
16970            if current_location_index == destination_location_index {
16971                return Ok(());
16972            }
16973
16974            let Range { start, end } = locations[destination_location_index];
16975
16976            editor.update_in(cx, |editor, window, cx| {
16977                let effects = SelectionEffects::default();
16978
16979                editor.unfold_ranges(&[start..end], false, false, cx);
16980                editor.change_selections(effects, window, cx, |s| {
16981                    s.select_ranges([start..start]);
16982                });
16983            })?;
16984
16985            Ok(())
16986        }))
16987    }
16988
16989    pub fn find_all_references(
16990        &mut self,
16991        _: &FindAllReferences,
16992        window: &mut Window,
16993        cx: &mut Context<Self>,
16994    ) -> Option<Task<Result<Navigated>>> {
16995        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
16996        let multi_buffer = self.buffer.read(cx);
16997        let head = selection.head();
16998
16999        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17000        let head_anchor = multi_buffer_snapshot.anchor_at(
17001            head,
17002            if head < selection.tail() {
17003                Bias::Right
17004            } else {
17005                Bias::Left
17006            },
17007        );
17008
17009        match self
17010            .find_all_references_task_sources
17011            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17012        {
17013            Ok(_) => {
17014                log::info!(
17015                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
17016                );
17017                return None;
17018            }
17019            Err(i) => {
17020                self.find_all_references_task_sources.insert(i, head_anchor);
17021            }
17022        }
17023
17024        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
17025        let workspace = self.workspace()?;
17026        let project = workspace.read(cx).project().clone();
17027        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
17028        Some(cx.spawn_in(window, async move |editor, cx| {
17029            let _cleanup = cx.on_drop(&editor, move |editor, _| {
17030                if let Ok(i) = editor
17031                    .find_all_references_task_sources
17032                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17033                {
17034                    editor.find_all_references_task_sources.remove(i);
17035                }
17036            });
17037
17038            let Some(locations) = references.await? else {
17039                return anyhow::Ok(Navigated::No);
17040            };
17041            let mut locations = cx.update(|_, cx| {
17042                locations
17043                    .into_iter()
17044                    .map(|location| {
17045                        let buffer = location.buffer.read(cx);
17046                        (location.buffer, location.range.to_point(buffer))
17047                    })
17048                    .into_group_map()
17049            })?;
17050            if locations.is_empty() {
17051                return anyhow::Ok(Navigated::No);
17052            }
17053            for ranges in locations.values_mut() {
17054                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17055                ranges.dedup();
17056            }
17057
17058            workspace.update_in(cx, |workspace, window, cx| {
17059                let target = locations
17060                    .iter()
17061                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17062                    .map(|(buffer, location)| {
17063                        buffer
17064                            .read(cx)
17065                            .text_for_range(location.clone())
17066                            .collect::<String>()
17067                    })
17068                    .filter(|text| !text.contains('\n'))
17069                    .unique()
17070                    .take(3)
17071                    .join(", ");
17072                let title = if target.is_empty() {
17073                    "References".to_owned()
17074                } else {
17075                    format!("References to {target}")
17076                };
17077                Self::open_locations_in_multibuffer(
17078                    workspace,
17079                    locations,
17080                    title,
17081                    false,
17082                    MultibufferSelectionMode::First,
17083                    window,
17084                    cx,
17085                );
17086                Navigated::Yes
17087            })
17088        }))
17089    }
17090
17091    /// Opens a multibuffer with the given project locations in it
17092    pub fn open_locations_in_multibuffer(
17093        workspace: &mut Workspace,
17094        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
17095        title: String,
17096        split: bool,
17097        multibuffer_selection_mode: MultibufferSelectionMode,
17098        window: &mut Window,
17099        cx: &mut Context<Workspace>,
17100    ) {
17101        if locations.is_empty() {
17102            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
17103            return;
17104        }
17105
17106        let capability = workspace.project().read(cx).capability();
17107        let mut ranges = <Vec<Range<Anchor>>>::new();
17108
17109        // a key to find existing multibuffer editors with the same set of locations
17110        // to prevent us from opening more and more multibuffer tabs for searches and the like
17111        let mut key = (title.clone(), vec![]);
17112        let excerpt_buffer = cx.new(|cx| {
17113            let key = &mut key.1;
17114            let mut multibuffer = MultiBuffer::new(capability);
17115            for (buffer, mut ranges_for_buffer) in locations {
17116                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17117                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17118                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17119                    PathKey::for_buffer(&buffer, cx),
17120                    buffer.clone(),
17121                    ranges_for_buffer,
17122                    multibuffer_context_lines(cx),
17123                    cx,
17124                );
17125                ranges.extend(new_ranges)
17126            }
17127
17128            multibuffer.with_title(title)
17129        });
17130        let existing = workspace.active_pane().update(cx, |pane, cx| {
17131            pane.items()
17132                .filter_map(|item| item.downcast::<Editor>())
17133                .find(|editor| {
17134                    editor
17135                        .read(cx)
17136                        .lookup_key
17137                        .as_ref()
17138                        .and_then(|it| {
17139                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17140                        })
17141                        .is_some_and(|it| *it == key)
17142                })
17143        });
17144        let editor = existing.unwrap_or_else(|| {
17145            cx.new(|cx| {
17146                let mut editor = Editor::for_multibuffer(
17147                    excerpt_buffer,
17148                    Some(workspace.project().clone()),
17149                    window,
17150                    cx,
17151                );
17152                editor.lookup_key = Some(Box::new(key));
17153                editor
17154            })
17155        });
17156        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17157            MultibufferSelectionMode::First => {
17158                if let Some(first_range) = ranges.first() {
17159                    editor.change_selections(
17160                        SelectionEffects::no_scroll(),
17161                        window,
17162                        cx,
17163                        |selections| {
17164                            selections.clear_disjoint();
17165                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17166                        },
17167                    );
17168                }
17169                editor.highlight_background::<Self>(
17170                    &ranges,
17171                    |theme| theme.colors().editor_highlighted_line_background,
17172                    cx,
17173                );
17174            }
17175            MultibufferSelectionMode::All => {
17176                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17177                    selections.clear_disjoint();
17178                    selections.select_anchor_ranges(ranges);
17179                });
17180            }
17181        });
17182
17183        let item = Box::new(editor);
17184        let item_id = item.item_id();
17185
17186        if split {
17187            let pane = workspace.adjacent_pane(window, cx);
17188            workspace.add_item(pane, item, None, true, true, window, cx);
17189        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
17190            let (preview_item_id, preview_item_idx) =
17191                workspace.active_pane().read_with(cx, |pane, _| {
17192                    (pane.preview_item_id(), pane.preview_item_idx())
17193                });
17194
17195            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
17196
17197            if let Some(preview_item_id) = preview_item_id {
17198                workspace.active_pane().update(cx, |pane, cx| {
17199                    pane.remove_item(preview_item_id, false, false, window, cx);
17200                });
17201            }
17202        } else {
17203            workspace.add_item_to_active_pane(item, None, true, window, cx);
17204        }
17205        workspace.active_pane().update(cx, |pane, cx| {
17206            pane.set_preview_item_id(Some(item_id), cx);
17207        });
17208    }
17209
17210    pub fn rename(
17211        &mut self,
17212        _: &Rename,
17213        window: &mut Window,
17214        cx: &mut Context<Self>,
17215    ) -> Option<Task<Result<()>>> {
17216        use language::ToOffset as _;
17217
17218        let provider = self.semantics_provider.clone()?;
17219        let selection = self.selections.newest_anchor().clone();
17220        let (cursor_buffer, cursor_buffer_position) = self
17221            .buffer
17222            .read(cx)
17223            .text_anchor_for_position(selection.head(), cx)?;
17224        let (tail_buffer, cursor_buffer_position_end) = self
17225            .buffer
17226            .read(cx)
17227            .text_anchor_for_position(selection.tail(), cx)?;
17228        if tail_buffer != cursor_buffer {
17229            return None;
17230        }
17231
17232        let snapshot = cursor_buffer.read(cx).snapshot();
17233        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17234        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17235        let prepare_rename = provider
17236            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17237            .unwrap_or_else(|| Task::ready(Ok(None)));
17238        drop(snapshot);
17239
17240        Some(cx.spawn_in(window, async move |this, cx| {
17241            let rename_range = if let Some(range) = prepare_rename.await? {
17242                Some(range)
17243            } else {
17244                this.update(cx, |this, cx| {
17245                    let buffer = this.buffer.read(cx).snapshot(cx);
17246                    let mut buffer_highlights = this
17247                        .document_highlights_for_position(selection.head(), &buffer)
17248                        .filter(|highlight| {
17249                            highlight.start.excerpt_id == selection.head().excerpt_id
17250                                && highlight.end.excerpt_id == selection.head().excerpt_id
17251                        });
17252                    buffer_highlights
17253                        .next()
17254                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17255                })?
17256            };
17257            if let Some(rename_range) = rename_range {
17258                this.update_in(cx, |this, window, cx| {
17259                    let snapshot = cursor_buffer.read(cx).snapshot();
17260                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17261                    let cursor_offset_in_rename_range =
17262                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17263                    let cursor_offset_in_rename_range_end =
17264                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17265
17266                    this.take_rename(false, window, cx);
17267                    let buffer = this.buffer.read(cx).read(cx);
17268                    let cursor_offset = selection.head().to_offset(&buffer);
17269                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
17270                    let rename_end = rename_start + rename_buffer_range.len();
17271                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17272                    let mut old_highlight_id = None;
17273                    let old_name: Arc<str> = buffer
17274                        .chunks(rename_start..rename_end, true)
17275                        .map(|chunk| {
17276                            if old_highlight_id.is_none() {
17277                                old_highlight_id = chunk.syntax_highlight_id;
17278                            }
17279                            chunk.text
17280                        })
17281                        .collect::<String>()
17282                        .into();
17283
17284                    drop(buffer);
17285
17286                    // Position the selection in the rename editor so that it matches the current selection.
17287                    this.show_local_selections = false;
17288                    let rename_editor = cx.new(|cx| {
17289                        let mut editor = Editor::single_line(window, cx);
17290                        editor.buffer.update(cx, |buffer, cx| {
17291                            buffer.edit([(0..0, old_name.clone())], None, cx)
17292                        });
17293                        let rename_selection_range = match cursor_offset_in_rename_range
17294                            .cmp(&cursor_offset_in_rename_range_end)
17295                        {
17296                            Ordering::Equal => {
17297                                editor.select_all(&SelectAll, window, cx);
17298                                return editor;
17299                            }
17300                            Ordering::Less => {
17301                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17302                            }
17303                            Ordering::Greater => {
17304                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17305                            }
17306                        };
17307                        if rename_selection_range.end > old_name.len() {
17308                            editor.select_all(&SelectAll, window, cx);
17309                        } else {
17310                            editor.change_selections(Default::default(), window, cx, |s| {
17311                                s.select_ranges([rename_selection_range]);
17312                            });
17313                        }
17314                        editor
17315                    });
17316                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17317                        if e == &EditorEvent::Focused {
17318                            cx.emit(EditorEvent::FocusedIn)
17319                        }
17320                    })
17321                    .detach();
17322
17323                    let write_highlights =
17324                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17325                    let read_highlights =
17326                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17327                    let ranges = write_highlights
17328                        .iter()
17329                        .flat_map(|(_, ranges)| ranges.iter())
17330                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17331                        .cloned()
17332                        .collect();
17333
17334                    this.highlight_text::<Rename>(
17335                        ranges,
17336                        HighlightStyle {
17337                            fade_out: Some(0.6),
17338                            ..Default::default()
17339                        },
17340                        cx,
17341                    );
17342                    let rename_focus_handle = rename_editor.focus_handle(cx);
17343                    window.focus(&rename_focus_handle);
17344                    let block_id = this.insert_blocks(
17345                        [BlockProperties {
17346                            style: BlockStyle::Flex,
17347                            placement: BlockPlacement::Below(range.start),
17348                            height: Some(1),
17349                            render: Arc::new({
17350                                let rename_editor = rename_editor.clone();
17351                                move |cx: &mut BlockContext| {
17352                                    let mut text_style = cx.editor_style.text.clone();
17353                                    if let Some(highlight_style) = old_highlight_id
17354                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17355                                    {
17356                                        text_style = text_style.highlight(highlight_style);
17357                                    }
17358                                    div()
17359                                        .block_mouse_except_scroll()
17360                                        .pl(cx.anchor_x)
17361                                        .child(EditorElement::new(
17362                                            &rename_editor,
17363                                            EditorStyle {
17364                                                background: cx.theme().system().transparent,
17365                                                local_player: cx.editor_style.local_player,
17366                                                text: text_style,
17367                                                scrollbar_width: cx.editor_style.scrollbar_width,
17368                                                syntax: cx.editor_style.syntax.clone(),
17369                                                status: cx.editor_style.status.clone(),
17370                                                inlay_hints_style: HighlightStyle {
17371                                                    font_weight: Some(FontWeight::BOLD),
17372                                                    ..make_inlay_hints_style(cx.app)
17373                                                },
17374                                                edit_prediction_styles: make_suggestion_styles(
17375                                                    cx.app,
17376                                                ),
17377                                                ..EditorStyle::default()
17378                                            },
17379                                        ))
17380                                        .into_any_element()
17381                                }
17382                            }),
17383                            priority: 0,
17384                        }],
17385                        Some(Autoscroll::fit()),
17386                        cx,
17387                    )[0];
17388                    this.pending_rename = Some(RenameState {
17389                        range,
17390                        old_name,
17391                        editor: rename_editor,
17392                        block_id,
17393                    });
17394                })?;
17395            }
17396
17397            Ok(())
17398        }))
17399    }
17400
17401    pub fn confirm_rename(
17402        &mut self,
17403        _: &ConfirmRename,
17404        window: &mut Window,
17405        cx: &mut Context<Self>,
17406    ) -> Option<Task<Result<()>>> {
17407        let rename = self.take_rename(false, window, cx)?;
17408        let workspace = self.workspace()?.downgrade();
17409        let (buffer, start) = self
17410            .buffer
17411            .read(cx)
17412            .text_anchor_for_position(rename.range.start, cx)?;
17413        let (end_buffer, _) = self
17414            .buffer
17415            .read(cx)
17416            .text_anchor_for_position(rename.range.end, cx)?;
17417        if buffer != end_buffer {
17418            return None;
17419        }
17420
17421        let old_name = rename.old_name;
17422        let new_name = rename.editor.read(cx).text(cx);
17423
17424        let rename = self.semantics_provider.as_ref()?.perform_rename(
17425            &buffer,
17426            start,
17427            new_name.clone(),
17428            cx,
17429        )?;
17430
17431        Some(cx.spawn_in(window, async move |editor, cx| {
17432            let project_transaction = rename.await?;
17433            Self::open_project_transaction(
17434                &editor,
17435                workspace,
17436                project_transaction,
17437                format!("Rename: {}{}", old_name, new_name),
17438                cx,
17439            )
17440            .await?;
17441
17442            editor.update(cx, |editor, cx| {
17443                editor.refresh_document_highlights(cx);
17444            })?;
17445            Ok(())
17446        }))
17447    }
17448
17449    fn take_rename(
17450        &mut self,
17451        moving_cursor: bool,
17452        window: &mut Window,
17453        cx: &mut Context<Self>,
17454    ) -> Option<RenameState> {
17455        let rename = self.pending_rename.take()?;
17456        if rename.editor.focus_handle(cx).is_focused(window) {
17457            window.focus(&self.focus_handle);
17458        }
17459
17460        self.remove_blocks(
17461            [rename.block_id].into_iter().collect(),
17462            Some(Autoscroll::fit()),
17463            cx,
17464        );
17465        self.clear_highlights::<Rename>(cx);
17466        self.show_local_selections = true;
17467
17468        if moving_cursor {
17469            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17470                editor
17471                    .selections
17472                    .newest::<usize>(&editor.display_snapshot(cx))
17473                    .head()
17474            });
17475
17476            // Update the selection to match the position of the selection inside
17477            // the rename editor.
17478            let snapshot = self.buffer.read(cx).read(cx);
17479            let rename_range = rename.range.to_offset(&snapshot);
17480            let cursor_in_editor = snapshot
17481                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17482                .min(rename_range.end);
17483            drop(snapshot);
17484
17485            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17486                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17487            });
17488        } else {
17489            self.refresh_document_highlights(cx);
17490        }
17491
17492        Some(rename)
17493    }
17494
17495    pub fn pending_rename(&self) -> Option<&RenameState> {
17496        self.pending_rename.as_ref()
17497    }
17498
17499    fn format(
17500        &mut self,
17501        _: &Format,
17502        window: &mut Window,
17503        cx: &mut Context<Self>,
17504    ) -> Option<Task<Result<()>>> {
17505        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17506
17507        let project = match &self.project {
17508            Some(project) => project.clone(),
17509            None => return None,
17510        };
17511
17512        Some(self.perform_format(
17513            project,
17514            FormatTrigger::Manual,
17515            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17516            window,
17517            cx,
17518        ))
17519    }
17520
17521    fn format_selections(
17522        &mut self,
17523        _: &FormatSelections,
17524        window: &mut Window,
17525        cx: &mut Context<Self>,
17526    ) -> Option<Task<Result<()>>> {
17527        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17528
17529        let project = match &self.project {
17530            Some(project) => project.clone(),
17531            None => return None,
17532        };
17533
17534        let ranges = self
17535            .selections
17536            .all_adjusted(&self.display_snapshot(cx))
17537            .into_iter()
17538            .map(|selection| selection.range())
17539            .collect_vec();
17540
17541        Some(self.perform_format(
17542            project,
17543            FormatTrigger::Manual,
17544            FormatTarget::Ranges(ranges),
17545            window,
17546            cx,
17547        ))
17548    }
17549
17550    fn perform_format(
17551        &mut self,
17552        project: Entity<Project>,
17553        trigger: FormatTrigger,
17554        target: FormatTarget,
17555        window: &mut Window,
17556        cx: &mut Context<Self>,
17557    ) -> Task<Result<()>> {
17558        let buffer = self.buffer.clone();
17559        let (buffers, target) = match target {
17560            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17561            FormatTarget::Ranges(selection_ranges) => {
17562                let multi_buffer = buffer.read(cx);
17563                let snapshot = multi_buffer.read(cx);
17564                let mut buffers = HashSet::default();
17565                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17566                    BTreeMap::new();
17567                for selection_range in selection_ranges {
17568                    for (buffer, buffer_range, _) in
17569                        snapshot.range_to_buffer_ranges(selection_range)
17570                    {
17571                        let buffer_id = buffer.remote_id();
17572                        let start = buffer.anchor_before(buffer_range.start);
17573                        let end = buffer.anchor_after(buffer_range.end);
17574                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17575                        buffer_id_to_ranges
17576                            .entry(buffer_id)
17577                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17578                            .or_insert_with(|| vec![start..end]);
17579                    }
17580                }
17581                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17582            }
17583        };
17584
17585        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17586        let selections_prev = transaction_id_prev
17587            .and_then(|transaction_id_prev| {
17588                // default to selections as they were after the last edit, if we have them,
17589                // instead of how they are now.
17590                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17591                // will take you back to where you made the last edit, instead of staying where you scrolled
17592                self.selection_history
17593                    .transaction(transaction_id_prev)
17594                    .map(|t| t.0.clone())
17595            })
17596            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17597
17598        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17599        let format = project.update(cx, |project, cx| {
17600            project.format(buffers, target, true, trigger, cx)
17601        });
17602
17603        cx.spawn_in(window, async move |editor, cx| {
17604            let transaction = futures::select_biased! {
17605                transaction = format.log_err().fuse() => transaction,
17606                () = timeout => {
17607                    log::warn!("timed out waiting for formatting");
17608                    None
17609                }
17610            };
17611
17612            buffer
17613                .update(cx, |buffer, cx| {
17614                    if let Some(transaction) = transaction
17615                        && !buffer.is_singleton()
17616                    {
17617                        buffer.push_transaction(&transaction.0, cx);
17618                    }
17619                    cx.notify();
17620                })
17621                .ok();
17622
17623            if let Some(transaction_id_now) =
17624                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17625            {
17626                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17627                if has_new_transaction {
17628                    _ = editor.update(cx, |editor, _| {
17629                        editor
17630                            .selection_history
17631                            .insert_transaction(transaction_id_now, selections_prev);
17632                    });
17633                }
17634            }
17635
17636            Ok(())
17637        })
17638    }
17639
17640    fn organize_imports(
17641        &mut self,
17642        _: &OrganizeImports,
17643        window: &mut Window,
17644        cx: &mut Context<Self>,
17645    ) -> Option<Task<Result<()>>> {
17646        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17647        let project = match &self.project {
17648            Some(project) => project.clone(),
17649            None => return None,
17650        };
17651        Some(self.perform_code_action_kind(
17652            project,
17653            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17654            window,
17655            cx,
17656        ))
17657    }
17658
17659    fn perform_code_action_kind(
17660        &mut self,
17661        project: Entity<Project>,
17662        kind: CodeActionKind,
17663        window: &mut Window,
17664        cx: &mut Context<Self>,
17665    ) -> Task<Result<()>> {
17666        let buffer = self.buffer.clone();
17667        let buffers = buffer.read(cx).all_buffers();
17668        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17669        let apply_action = project.update(cx, |project, cx| {
17670            project.apply_code_action_kind(buffers, kind, true, cx)
17671        });
17672        cx.spawn_in(window, async move |_, cx| {
17673            let transaction = futures::select_biased! {
17674                () = timeout => {
17675                    log::warn!("timed out waiting for executing code action");
17676                    None
17677                }
17678                transaction = apply_action.log_err().fuse() => transaction,
17679            };
17680            buffer
17681                .update(cx, |buffer, cx| {
17682                    // check if we need this
17683                    if let Some(transaction) = transaction
17684                        && !buffer.is_singleton()
17685                    {
17686                        buffer.push_transaction(&transaction.0, cx);
17687                    }
17688                    cx.notify();
17689                })
17690                .ok();
17691            Ok(())
17692        })
17693    }
17694
17695    pub fn restart_language_server(
17696        &mut self,
17697        _: &RestartLanguageServer,
17698        _: &mut Window,
17699        cx: &mut Context<Self>,
17700    ) {
17701        if let Some(project) = self.project.clone() {
17702            self.buffer.update(cx, |multi_buffer, cx| {
17703                project.update(cx, |project, cx| {
17704                    project.restart_language_servers_for_buffers(
17705                        multi_buffer.all_buffers().into_iter().collect(),
17706                        HashSet::default(),
17707                        cx,
17708                    );
17709                });
17710            })
17711        }
17712    }
17713
17714    pub fn stop_language_server(
17715        &mut self,
17716        _: &StopLanguageServer,
17717        _: &mut Window,
17718        cx: &mut Context<Self>,
17719    ) {
17720        if let Some(project) = self.project.clone() {
17721            self.buffer.update(cx, |multi_buffer, cx| {
17722                project.update(cx, |project, cx| {
17723                    project.stop_language_servers_for_buffers(
17724                        multi_buffer.all_buffers().into_iter().collect(),
17725                        HashSet::default(),
17726                        cx,
17727                    );
17728                });
17729            });
17730            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
17731        }
17732    }
17733
17734    fn cancel_language_server_work(
17735        workspace: &mut Workspace,
17736        _: &actions::CancelLanguageServerWork,
17737        _: &mut Window,
17738        cx: &mut Context<Workspace>,
17739    ) {
17740        let project = workspace.project();
17741        let buffers = workspace
17742            .active_item(cx)
17743            .and_then(|item| item.act_as::<Editor>(cx))
17744            .map_or(HashSet::default(), |editor| {
17745                editor.read(cx).buffer.read(cx).all_buffers()
17746            });
17747        project.update(cx, |project, cx| {
17748            project.cancel_language_server_work_for_buffers(buffers, cx);
17749        });
17750    }
17751
17752    fn show_character_palette(
17753        &mut self,
17754        _: &ShowCharacterPalette,
17755        window: &mut Window,
17756        _: &mut Context<Self>,
17757    ) {
17758        window.show_character_palette();
17759    }
17760
17761    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17762        if !self.diagnostics_enabled() {
17763            return;
17764        }
17765
17766        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17767            let buffer = self.buffer.read(cx).snapshot(cx);
17768            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17769            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17770            let is_valid = buffer
17771                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17772                .any(|entry| {
17773                    entry.diagnostic.is_primary
17774                        && !entry.range.is_empty()
17775                        && entry.range.start == primary_range_start
17776                        && entry.diagnostic.message == active_diagnostics.active_message
17777                });
17778
17779            if !is_valid {
17780                self.dismiss_diagnostics(cx);
17781            }
17782        }
17783    }
17784
17785    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17786        match &self.active_diagnostics {
17787            ActiveDiagnostic::Group(group) => Some(group),
17788            _ => None,
17789        }
17790    }
17791
17792    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17793        if !self.diagnostics_enabled() {
17794            return;
17795        }
17796        self.dismiss_diagnostics(cx);
17797        self.active_diagnostics = ActiveDiagnostic::All;
17798    }
17799
17800    fn activate_diagnostics(
17801        &mut self,
17802        buffer_id: BufferId,
17803        diagnostic: DiagnosticEntryRef<'_, usize>,
17804        window: &mut Window,
17805        cx: &mut Context<Self>,
17806    ) {
17807        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17808            return;
17809        }
17810        self.dismiss_diagnostics(cx);
17811        let snapshot = self.snapshot(window, cx);
17812        let buffer = self.buffer.read(cx).snapshot(cx);
17813        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17814            return;
17815        };
17816
17817        let diagnostic_group = buffer
17818            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17819            .collect::<Vec<_>>();
17820
17821        let blocks =
17822            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17823
17824        let blocks = self.display_map.update(cx, |display_map, cx| {
17825            display_map.insert_blocks(blocks, cx).into_iter().collect()
17826        });
17827        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17828            active_range: buffer.anchor_before(diagnostic.range.start)
17829                ..buffer.anchor_after(diagnostic.range.end),
17830            active_message: diagnostic.diagnostic.message.clone(),
17831            group_id: diagnostic.diagnostic.group_id,
17832            blocks,
17833        });
17834        cx.notify();
17835    }
17836
17837    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17838        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17839            return;
17840        };
17841
17842        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17843        if let ActiveDiagnostic::Group(group) = prev {
17844            self.display_map.update(cx, |display_map, cx| {
17845                display_map.remove_blocks(group.blocks, cx);
17846            });
17847            cx.notify();
17848        }
17849    }
17850
17851    /// Disable inline diagnostics rendering for this editor.
17852    pub fn disable_inline_diagnostics(&mut self) {
17853        self.inline_diagnostics_enabled = false;
17854        self.inline_diagnostics_update = Task::ready(());
17855        self.inline_diagnostics.clear();
17856    }
17857
17858    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17859        self.diagnostics_enabled = false;
17860        self.dismiss_diagnostics(cx);
17861        self.inline_diagnostics_update = Task::ready(());
17862        self.inline_diagnostics.clear();
17863    }
17864
17865    pub fn disable_word_completions(&mut self) {
17866        self.word_completions_enabled = false;
17867    }
17868
17869    pub fn diagnostics_enabled(&self) -> bool {
17870        self.diagnostics_enabled && self.mode.is_full()
17871    }
17872
17873    pub fn inline_diagnostics_enabled(&self) -> bool {
17874        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17875    }
17876
17877    pub fn show_inline_diagnostics(&self) -> bool {
17878        self.show_inline_diagnostics
17879    }
17880
17881    pub fn toggle_inline_diagnostics(
17882        &mut self,
17883        _: &ToggleInlineDiagnostics,
17884        window: &mut Window,
17885        cx: &mut Context<Editor>,
17886    ) {
17887        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17888        self.refresh_inline_diagnostics(false, window, cx);
17889    }
17890
17891    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17892        self.diagnostics_max_severity = severity;
17893        self.display_map.update(cx, |display_map, _| {
17894            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17895        });
17896    }
17897
17898    pub fn toggle_diagnostics(
17899        &mut self,
17900        _: &ToggleDiagnostics,
17901        window: &mut Window,
17902        cx: &mut Context<Editor>,
17903    ) {
17904        if !self.diagnostics_enabled() {
17905            return;
17906        }
17907
17908        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17909            EditorSettings::get_global(cx)
17910                .diagnostics_max_severity
17911                .filter(|severity| severity != &DiagnosticSeverity::Off)
17912                .unwrap_or(DiagnosticSeverity::Hint)
17913        } else {
17914            DiagnosticSeverity::Off
17915        };
17916        self.set_max_diagnostics_severity(new_severity, cx);
17917        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17918            self.active_diagnostics = ActiveDiagnostic::None;
17919            self.inline_diagnostics_update = Task::ready(());
17920            self.inline_diagnostics.clear();
17921        } else {
17922            self.refresh_inline_diagnostics(false, window, cx);
17923        }
17924
17925        cx.notify();
17926    }
17927
17928    pub fn toggle_minimap(
17929        &mut self,
17930        _: &ToggleMinimap,
17931        window: &mut Window,
17932        cx: &mut Context<Editor>,
17933    ) {
17934        if self.supports_minimap(cx) {
17935            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17936        }
17937    }
17938
17939    fn refresh_inline_diagnostics(
17940        &mut self,
17941        debounce: bool,
17942        window: &mut Window,
17943        cx: &mut Context<Self>,
17944    ) {
17945        let max_severity = ProjectSettings::get_global(cx)
17946            .diagnostics
17947            .inline
17948            .max_severity
17949            .unwrap_or(self.diagnostics_max_severity);
17950
17951        if !self.inline_diagnostics_enabled()
17952            || !self.diagnostics_enabled()
17953            || !self.show_inline_diagnostics
17954            || max_severity == DiagnosticSeverity::Off
17955        {
17956            self.inline_diagnostics_update = Task::ready(());
17957            self.inline_diagnostics.clear();
17958            return;
17959        }
17960
17961        let debounce_ms = ProjectSettings::get_global(cx)
17962            .diagnostics
17963            .inline
17964            .update_debounce_ms;
17965        let debounce = if debounce && debounce_ms > 0 {
17966            Some(Duration::from_millis(debounce_ms))
17967        } else {
17968            None
17969        };
17970        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17971            if let Some(debounce) = debounce {
17972                cx.background_executor().timer(debounce).await;
17973            }
17974            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17975                editor
17976                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17977                    .ok()
17978            }) else {
17979                return;
17980            };
17981
17982            let new_inline_diagnostics = cx
17983                .background_spawn(async move {
17984                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17985                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17986                        let message = diagnostic_entry
17987                            .diagnostic
17988                            .message
17989                            .split_once('\n')
17990                            .map(|(line, _)| line)
17991                            .map(SharedString::new)
17992                            .unwrap_or_else(|| {
17993                                SharedString::new(&*diagnostic_entry.diagnostic.message)
17994                            });
17995                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17996                        let (Ok(i) | Err(i)) = inline_diagnostics
17997                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17998                        inline_diagnostics.insert(
17999                            i,
18000                            (
18001                                start_anchor,
18002                                InlineDiagnostic {
18003                                    message,
18004                                    group_id: diagnostic_entry.diagnostic.group_id,
18005                                    start: diagnostic_entry.range.start.to_point(&snapshot),
18006                                    is_primary: diagnostic_entry.diagnostic.is_primary,
18007                                    severity: diagnostic_entry.diagnostic.severity,
18008                                },
18009                            ),
18010                        );
18011                    }
18012                    inline_diagnostics
18013                })
18014                .await;
18015
18016            editor
18017                .update(cx, |editor, cx| {
18018                    editor.inline_diagnostics = new_inline_diagnostics;
18019                    cx.notify();
18020                })
18021                .ok();
18022        });
18023    }
18024
18025    fn pull_diagnostics(
18026        &mut self,
18027        buffer_id: Option<BufferId>,
18028        window: &Window,
18029        cx: &mut Context<Self>,
18030    ) -> Option<()> {
18031        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
18032            return None;
18033        }
18034        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
18035            .diagnostics
18036            .lsp_pull_diagnostics;
18037        if !pull_diagnostics_settings.enabled {
18038            return None;
18039        }
18040        let project = self.project()?.downgrade();
18041        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
18042        let mut buffers = self.buffer.read(cx).all_buffers();
18043        buffers.retain(|buffer| {
18044            let buffer_id_to_retain = buffer.read(cx).remote_id();
18045            buffer_id.is_none_or(|buffer_id| buffer_id == buffer_id_to_retain)
18046                && self.registered_buffers.contains_key(&buffer_id_to_retain)
18047        });
18048        if buffers.is_empty() {
18049            self.pull_diagnostics_task = Task::ready(());
18050            return None;
18051        }
18052
18053        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
18054            cx.background_executor().timer(debounce).await;
18055
18056            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
18057                buffers
18058                    .into_iter()
18059                    .filter_map(|buffer| {
18060                        project
18061                            .update(cx, |project, cx| {
18062                                project.lsp_store().update(cx, |lsp_store, cx| {
18063                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
18064                                })
18065                            })
18066                            .ok()
18067                    })
18068                    .collect::<FuturesUnordered<_>>()
18069            }) else {
18070                return;
18071            };
18072
18073            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
18074                match pull_task {
18075                    Ok(()) => {
18076                        if editor
18077                            .update_in(cx, |editor, window, cx| {
18078                                editor.update_diagnostics_state(window, cx);
18079                            })
18080                            .is_err()
18081                        {
18082                            return;
18083                        }
18084                    }
18085                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
18086                }
18087            }
18088        });
18089
18090        Some(())
18091    }
18092
18093    pub fn set_selections_from_remote(
18094        &mut self,
18095        selections: Vec<Selection<Anchor>>,
18096        pending_selection: Option<Selection<Anchor>>,
18097        window: &mut Window,
18098        cx: &mut Context<Self>,
18099    ) {
18100        let old_cursor_position = self.selections.newest_anchor().head();
18101        self.selections
18102            .change_with(&self.display_snapshot(cx), |s| {
18103                s.select_anchors(selections);
18104                if let Some(pending_selection) = pending_selection {
18105                    s.set_pending(pending_selection, SelectMode::Character);
18106                } else {
18107                    s.clear_pending();
18108                }
18109            });
18110        self.selections_did_change(
18111            false,
18112            &old_cursor_position,
18113            SelectionEffects::default(),
18114            window,
18115            cx,
18116        );
18117    }
18118
18119    pub fn transact(
18120        &mut self,
18121        window: &mut Window,
18122        cx: &mut Context<Self>,
18123        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
18124    ) -> Option<TransactionId> {
18125        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18126            this.start_transaction_at(Instant::now(), window, cx);
18127            update(this, window, cx);
18128            this.end_transaction_at(Instant::now(), cx)
18129        })
18130    }
18131
18132    pub fn start_transaction_at(
18133        &mut self,
18134        now: Instant,
18135        window: &mut Window,
18136        cx: &mut Context<Self>,
18137    ) -> Option<TransactionId> {
18138        self.end_selection(window, cx);
18139        if let Some(tx_id) = self
18140            .buffer
18141            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18142        {
18143            self.selection_history
18144                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18145            cx.emit(EditorEvent::TransactionBegun {
18146                transaction_id: tx_id,
18147            });
18148            Some(tx_id)
18149        } else {
18150            None
18151        }
18152    }
18153
18154    pub fn end_transaction_at(
18155        &mut self,
18156        now: Instant,
18157        cx: &mut Context<Self>,
18158    ) -> Option<TransactionId> {
18159        if let Some(transaction_id) = self
18160            .buffer
18161            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18162        {
18163            if let Some((_, end_selections)) =
18164                self.selection_history.transaction_mut(transaction_id)
18165            {
18166                *end_selections = Some(self.selections.disjoint_anchors_arc());
18167            } else {
18168                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18169            }
18170
18171            cx.emit(EditorEvent::Edited { transaction_id });
18172            Some(transaction_id)
18173        } else {
18174            None
18175        }
18176    }
18177
18178    pub fn modify_transaction_selection_history(
18179        &mut self,
18180        transaction_id: TransactionId,
18181        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18182    ) -> bool {
18183        self.selection_history
18184            .transaction_mut(transaction_id)
18185            .map(modify)
18186            .is_some()
18187    }
18188
18189    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18190        if self.selection_mark_mode {
18191            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18192                s.move_with(|_, sel| {
18193                    sel.collapse_to(sel.head(), SelectionGoal::None);
18194                });
18195            })
18196        }
18197        self.selection_mark_mode = true;
18198        cx.notify();
18199    }
18200
18201    pub fn swap_selection_ends(
18202        &mut self,
18203        _: &actions::SwapSelectionEnds,
18204        window: &mut Window,
18205        cx: &mut Context<Self>,
18206    ) {
18207        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18208            s.move_with(|_, sel| {
18209                if sel.start != sel.end {
18210                    sel.reversed = !sel.reversed
18211                }
18212            });
18213        });
18214        self.request_autoscroll(Autoscroll::newest(), cx);
18215        cx.notify();
18216    }
18217
18218    pub fn toggle_focus(
18219        workspace: &mut Workspace,
18220        _: &actions::ToggleFocus,
18221        window: &mut Window,
18222        cx: &mut Context<Workspace>,
18223    ) {
18224        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18225            return;
18226        };
18227        workspace.activate_item(&item, true, true, window, cx);
18228    }
18229
18230    pub fn toggle_fold(
18231        &mut self,
18232        _: &actions::ToggleFold,
18233        window: &mut Window,
18234        cx: &mut Context<Self>,
18235    ) {
18236        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18237            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18238            let selection = self.selections.newest::<Point>(&display_map);
18239
18240            let range = if selection.is_empty() {
18241                let point = selection.head().to_display_point(&display_map);
18242                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18243                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18244                    .to_point(&display_map);
18245                start..end
18246            } else {
18247                selection.range()
18248            };
18249            if display_map.folds_in_range(range).next().is_some() {
18250                self.unfold_lines(&Default::default(), window, cx)
18251            } else {
18252                self.fold(&Default::default(), window, cx)
18253            }
18254        } else {
18255            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18256            let buffer_ids: HashSet<_> = self
18257                .selections
18258                .disjoint_anchor_ranges()
18259                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18260                .collect();
18261
18262            let should_unfold = buffer_ids
18263                .iter()
18264                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18265
18266            for buffer_id in buffer_ids {
18267                if should_unfold {
18268                    self.unfold_buffer(buffer_id, cx);
18269                } else {
18270                    self.fold_buffer(buffer_id, cx);
18271                }
18272            }
18273        }
18274    }
18275
18276    pub fn toggle_fold_recursive(
18277        &mut self,
18278        _: &actions::ToggleFoldRecursive,
18279        window: &mut Window,
18280        cx: &mut Context<Self>,
18281    ) {
18282        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
18283
18284        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18285        let range = if selection.is_empty() {
18286            let point = selection.head().to_display_point(&display_map);
18287            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18288            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18289                .to_point(&display_map);
18290            start..end
18291        } else {
18292            selection.range()
18293        };
18294        if display_map.folds_in_range(range).next().is_some() {
18295            self.unfold_recursive(&Default::default(), window, cx)
18296        } else {
18297            self.fold_recursive(&Default::default(), window, cx)
18298        }
18299    }
18300
18301    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18302        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18303            let mut to_fold = Vec::new();
18304            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18305            let selections = self.selections.all_adjusted(&display_map);
18306
18307            for selection in selections {
18308                let range = selection.range().sorted();
18309                let buffer_start_row = range.start.row;
18310
18311                if range.start.row != range.end.row {
18312                    let mut found = false;
18313                    let mut row = range.start.row;
18314                    while row <= range.end.row {
18315                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18316                        {
18317                            found = true;
18318                            row = crease.range().end.row + 1;
18319                            to_fold.push(crease);
18320                        } else {
18321                            row += 1
18322                        }
18323                    }
18324                    if found {
18325                        continue;
18326                    }
18327                }
18328
18329                for row in (0..=range.start.row).rev() {
18330                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18331                        && crease.range().end.row >= buffer_start_row
18332                    {
18333                        to_fold.push(crease);
18334                        if row <= range.start.row {
18335                            break;
18336                        }
18337                    }
18338                }
18339            }
18340
18341            self.fold_creases(to_fold, true, window, cx);
18342        } else {
18343            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18344            let buffer_ids = self
18345                .selections
18346                .disjoint_anchor_ranges()
18347                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18348                .collect::<HashSet<_>>();
18349            for buffer_id in buffer_ids {
18350                self.fold_buffer(buffer_id, cx);
18351            }
18352        }
18353    }
18354
18355    pub fn toggle_fold_all(
18356        &mut self,
18357        _: &actions::ToggleFoldAll,
18358        window: &mut Window,
18359        cx: &mut Context<Self>,
18360    ) {
18361        if self.buffer.read(cx).is_singleton() {
18362            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18363            let has_folds = display_map
18364                .folds_in_range(0..display_map.buffer_snapshot().len())
18365                .next()
18366                .is_some();
18367
18368            if has_folds {
18369                self.unfold_all(&actions::UnfoldAll, window, cx);
18370            } else {
18371                self.fold_all(&actions::FoldAll, window, cx);
18372            }
18373        } else {
18374            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18375            let should_unfold = buffer_ids
18376                .iter()
18377                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18378
18379            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18380                editor
18381                    .update_in(cx, |editor, _, cx| {
18382                        for buffer_id in buffer_ids {
18383                            if should_unfold {
18384                                editor.unfold_buffer(buffer_id, cx);
18385                            } else {
18386                                editor.fold_buffer(buffer_id, cx);
18387                            }
18388                        }
18389                    })
18390                    .ok();
18391            });
18392        }
18393    }
18394
18395    fn fold_at_level(
18396        &mut self,
18397        fold_at: &FoldAtLevel,
18398        window: &mut Window,
18399        cx: &mut Context<Self>,
18400    ) {
18401        if !self.buffer.read(cx).is_singleton() {
18402            return;
18403        }
18404
18405        let fold_at_level = fold_at.0;
18406        let snapshot = self.buffer.read(cx).snapshot(cx);
18407        let mut to_fold = Vec::new();
18408        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18409
18410        let row_ranges_to_keep: Vec<Range<u32>> = self
18411            .selections
18412            .all::<Point>(&self.display_snapshot(cx))
18413            .into_iter()
18414            .map(|sel| sel.start.row..sel.end.row)
18415            .collect();
18416
18417        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18418            while start_row < end_row {
18419                match self
18420                    .snapshot(window, cx)
18421                    .crease_for_buffer_row(MultiBufferRow(start_row))
18422                {
18423                    Some(crease) => {
18424                        let nested_start_row = crease.range().start.row + 1;
18425                        let nested_end_row = crease.range().end.row;
18426
18427                        if current_level < fold_at_level {
18428                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18429                        } else if current_level == fold_at_level {
18430                            // Fold iff there is no selection completely contained within the fold region
18431                            if !row_ranges_to_keep.iter().any(|selection| {
18432                                selection.end >= nested_start_row
18433                                    && selection.start <= nested_end_row
18434                            }) {
18435                                to_fold.push(crease);
18436                            }
18437                        }
18438
18439                        start_row = nested_end_row + 1;
18440                    }
18441                    None => start_row += 1,
18442                }
18443            }
18444        }
18445
18446        self.fold_creases(to_fold, true, window, cx);
18447    }
18448
18449    pub fn fold_at_level_1(
18450        &mut self,
18451        _: &actions::FoldAtLevel1,
18452        window: &mut Window,
18453        cx: &mut Context<Self>,
18454    ) {
18455        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18456    }
18457
18458    pub fn fold_at_level_2(
18459        &mut self,
18460        _: &actions::FoldAtLevel2,
18461        window: &mut Window,
18462        cx: &mut Context<Self>,
18463    ) {
18464        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18465    }
18466
18467    pub fn fold_at_level_3(
18468        &mut self,
18469        _: &actions::FoldAtLevel3,
18470        window: &mut Window,
18471        cx: &mut Context<Self>,
18472    ) {
18473        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18474    }
18475
18476    pub fn fold_at_level_4(
18477        &mut self,
18478        _: &actions::FoldAtLevel4,
18479        window: &mut Window,
18480        cx: &mut Context<Self>,
18481    ) {
18482        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18483    }
18484
18485    pub fn fold_at_level_5(
18486        &mut self,
18487        _: &actions::FoldAtLevel5,
18488        window: &mut Window,
18489        cx: &mut Context<Self>,
18490    ) {
18491        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18492    }
18493
18494    pub fn fold_at_level_6(
18495        &mut self,
18496        _: &actions::FoldAtLevel6,
18497        window: &mut Window,
18498        cx: &mut Context<Self>,
18499    ) {
18500        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18501    }
18502
18503    pub fn fold_at_level_7(
18504        &mut self,
18505        _: &actions::FoldAtLevel7,
18506        window: &mut Window,
18507        cx: &mut Context<Self>,
18508    ) {
18509        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18510    }
18511
18512    pub fn fold_at_level_8(
18513        &mut self,
18514        _: &actions::FoldAtLevel8,
18515        window: &mut Window,
18516        cx: &mut Context<Self>,
18517    ) {
18518        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18519    }
18520
18521    pub fn fold_at_level_9(
18522        &mut self,
18523        _: &actions::FoldAtLevel9,
18524        window: &mut Window,
18525        cx: &mut Context<Self>,
18526    ) {
18527        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18528    }
18529
18530    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18531        if self.buffer.read(cx).is_singleton() {
18532            let mut fold_ranges = Vec::new();
18533            let snapshot = self.buffer.read(cx).snapshot(cx);
18534
18535            for row in 0..snapshot.max_row().0 {
18536                if let Some(foldable_range) = self
18537                    .snapshot(window, cx)
18538                    .crease_for_buffer_row(MultiBufferRow(row))
18539                {
18540                    fold_ranges.push(foldable_range);
18541                }
18542            }
18543
18544            self.fold_creases(fold_ranges, true, window, cx);
18545        } else {
18546            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18547                editor
18548                    .update_in(cx, |editor, _, cx| {
18549                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18550                            editor.fold_buffer(buffer_id, cx);
18551                        }
18552                    })
18553                    .ok();
18554            });
18555        }
18556    }
18557
18558    pub fn fold_function_bodies(
18559        &mut self,
18560        _: &actions::FoldFunctionBodies,
18561        window: &mut Window,
18562        cx: &mut Context<Self>,
18563    ) {
18564        let snapshot = self.buffer.read(cx).snapshot(cx);
18565
18566        let ranges = snapshot
18567            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18568            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18569            .collect::<Vec<_>>();
18570
18571        let creases = ranges
18572            .into_iter()
18573            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18574            .collect();
18575
18576        self.fold_creases(creases, true, window, cx);
18577    }
18578
18579    pub fn fold_recursive(
18580        &mut self,
18581        _: &actions::FoldRecursive,
18582        window: &mut Window,
18583        cx: &mut Context<Self>,
18584    ) {
18585        let mut to_fold = Vec::new();
18586        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18587        let selections = self.selections.all_adjusted(&display_map);
18588
18589        for selection in selections {
18590            let range = selection.range().sorted();
18591            let buffer_start_row = range.start.row;
18592
18593            if range.start.row != range.end.row {
18594                let mut found = false;
18595                for row in range.start.row..=range.end.row {
18596                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18597                        found = true;
18598                        to_fold.push(crease);
18599                    }
18600                }
18601                if found {
18602                    continue;
18603                }
18604            }
18605
18606            for row in (0..=range.start.row).rev() {
18607                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18608                    if crease.range().end.row >= buffer_start_row {
18609                        to_fold.push(crease);
18610                    } else {
18611                        break;
18612                    }
18613                }
18614            }
18615        }
18616
18617        self.fold_creases(to_fold, true, window, cx);
18618    }
18619
18620    pub fn fold_at(
18621        &mut self,
18622        buffer_row: MultiBufferRow,
18623        window: &mut Window,
18624        cx: &mut Context<Self>,
18625    ) {
18626        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18627
18628        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18629            let autoscroll = self
18630                .selections
18631                .all::<Point>(&display_map)
18632                .iter()
18633                .any(|selection| crease.range().overlaps(&selection.range()));
18634
18635            self.fold_creases(vec![crease], autoscroll, window, cx);
18636        }
18637    }
18638
18639    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18640        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18641            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18642            let buffer = display_map.buffer_snapshot();
18643            let selections = self.selections.all::<Point>(&display_map);
18644            let ranges = selections
18645                .iter()
18646                .map(|s| {
18647                    let range = s.display_range(&display_map).sorted();
18648                    let mut start = range.start.to_point(&display_map);
18649                    let mut end = range.end.to_point(&display_map);
18650                    start.column = 0;
18651                    end.column = buffer.line_len(MultiBufferRow(end.row));
18652                    start..end
18653                })
18654                .collect::<Vec<_>>();
18655
18656            self.unfold_ranges(&ranges, true, true, cx);
18657        } else {
18658            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18659            let buffer_ids = self
18660                .selections
18661                .disjoint_anchor_ranges()
18662                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18663                .collect::<HashSet<_>>();
18664            for buffer_id in buffer_ids {
18665                self.unfold_buffer(buffer_id, cx);
18666            }
18667        }
18668    }
18669
18670    pub fn unfold_recursive(
18671        &mut self,
18672        _: &UnfoldRecursive,
18673        _window: &mut Window,
18674        cx: &mut Context<Self>,
18675    ) {
18676        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18677        let selections = self.selections.all::<Point>(&display_map);
18678        let ranges = selections
18679            .iter()
18680            .map(|s| {
18681                let mut range = s.display_range(&display_map).sorted();
18682                *range.start.column_mut() = 0;
18683                *range.end.column_mut() = display_map.line_len(range.end.row());
18684                let start = range.start.to_point(&display_map);
18685                let end = range.end.to_point(&display_map);
18686                start..end
18687            })
18688            .collect::<Vec<_>>();
18689
18690        self.unfold_ranges(&ranges, true, true, cx);
18691    }
18692
18693    pub fn unfold_at(
18694        &mut self,
18695        buffer_row: MultiBufferRow,
18696        _window: &mut Window,
18697        cx: &mut Context<Self>,
18698    ) {
18699        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18700
18701        let intersection_range = Point::new(buffer_row.0, 0)
18702            ..Point::new(
18703                buffer_row.0,
18704                display_map.buffer_snapshot().line_len(buffer_row),
18705            );
18706
18707        let autoscroll = self
18708            .selections
18709            .all::<Point>(&display_map)
18710            .iter()
18711            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18712
18713        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18714    }
18715
18716    pub fn unfold_all(
18717        &mut self,
18718        _: &actions::UnfoldAll,
18719        _window: &mut Window,
18720        cx: &mut Context<Self>,
18721    ) {
18722        if self.buffer.read(cx).is_singleton() {
18723            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18724            self.unfold_ranges(&[0..display_map.buffer_snapshot().len()], true, true, cx);
18725        } else {
18726            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18727                editor
18728                    .update(cx, |editor, cx| {
18729                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18730                            editor.unfold_buffer(buffer_id, cx);
18731                        }
18732                    })
18733                    .ok();
18734            });
18735        }
18736    }
18737
18738    pub fn fold_selected_ranges(
18739        &mut self,
18740        _: &FoldSelectedRanges,
18741        window: &mut Window,
18742        cx: &mut Context<Self>,
18743    ) {
18744        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18745        let selections = self.selections.all_adjusted(&display_map);
18746        let ranges = selections
18747            .into_iter()
18748            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18749            .collect::<Vec<_>>();
18750        self.fold_creases(ranges, true, window, cx);
18751    }
18752
18753    pub fn fold_ranges<T: ToOffset + Clone>(
18754        &mut self,
18755        ranges: Vec<Range<T>>,
18756        auto_scroll: bool,
18757        window: &mut Window,
18758        cx: &mut Context<Self>,
18759    ) {
18760        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18761        let ranges = ranges
18762            .into_iter()
18763            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18764            .collect::<Vec<_>>();
18765        self.fold_creases(ranges, auto_scroll, window, cx);
18766    }
18767
18768    pub fn fold_creases<T: ToOffset + Clone>(
18769        &mut self,
18770        creases: Vec<Crease<T>>,
18771        auto_scroll: bool,
18772        _window: &mut Window,
18773        cx: &mut Context<Self>,
18774    ) {
18775        if creases.is_empty() {
18776            return;
18777        }
18778
18779        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18780
18781        if auto_scroll {
18782            self.request_autoscroll(Autoscroll::fit(), cx);
18783        }
18784
18785        cx.notify();
18786
18787        self.scrollbar_marker_state.dirty = true;
18788        self.folds_did_change(cx);
18789    }
18790
18791    /// Removes any folds whose ranges intersect any of the given ranges.
18792    pub fn unfold_ranges<T: ToOffset + Clone>(
18793        &mut self,
18794        ranges: &[Range<T>],
18795        inclusive: bool,
18796        auto_scroll: bool,
18797        cx: &mut Context<Self>,
18798    ) {
18799        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18800            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18801        });
18802        self.folds_did_change(cx);
18803    }
18804
18805    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18806        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18807            return;
18808        }
18809        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18810        self.display_map.update(cx, |display_map, cx| {
18811            display_map.fold_buffers([buffer_id], cx)
18812        });
18813        cx.emit(EditorEvent::BufferFoldToggled {
18814            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18815            folded: true,
18816        });
18817        cx.notify();
18818    }
18819
18820    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18821        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18822            return;
18823        }
18824        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18825        self.display_map.update(cx, |display_map, cx| {
18826            display_map.unfold_buffers([buffer_id], cx);
18827        });
18828        cx.emit(EditorEvent::BufferFoldToggled {
18829            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18830            folded: false,
18831        });
18832        cx.notify();
18833    }
18834
18835    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18836        self.display_map.read(cx).is_buffer_folded(buffer)
18837    }
18838
18839    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18840        self.display_map.read(cx).folded_buffers()
18841    }
18842
18843    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18844        self.display_map.update(cx, |display_map, cx| {
18845            display_map.disable_header_for_buffer(buffer_id, cx);
18846        });
18847        cx.notify();
18848    }
18849
18850    /// Removes any folds with the given ranges.
18851    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18852        &mut self,
18853        ranges: &[Range<T>],
18854        type_id: TypeId,
18855        auto_scroll: bool,
18856        cx: &mut Context<Self>,
18857    ) {
18858        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18859            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18860        });
18861        self.folds_did_change(cx);
18862    }
18863
18864    fn remove_folds_with<T: ToOffset + Clone>(
18865        &mut self,
18866        ranges: &[Range<T>],
18867        auto_scroll: bool,
18868        cx: &mut Context<Self>,
18869        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18870    ) {
18871        if ranges.is_empty() {
18872            return;
18873        }
18874
18875        let mut buffers_affected = HashSet::default();
18876        let multi_buffer = self.buffer().read(cx);
18877        for range in ranges {
18878            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18879                buffers_affected.insert(buffer.read(cx).remote_id());
18880            };
18881        }
18882
18883        self.display_map.update(cx, update);
18884
18885        if auto_scroll {
18886            self.request_autoscroll(Autoscroll::fit(), cx);
18887        }
18888
18889        cx.notify();
18890        self.scrollbar_marker_state.dirty = true;
18891        self.active_indent_guides_state.dirty = true;
18892    }
18893
18894    pub fn update_renderer_widths(
18895        &mut self,
18896        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18897        cx: &mut Context<Self>,
18898    ) -> bool {
18899        self.display_map
18900            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18901    }
18902
18903    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18904        self.display_map.read(cx).fold_placeholder.clone()
18905    }
18906
18907    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18908        self.buffer.update(cx, |buffer, cx| {
18909            buffer.set_all_diff_hunks_expanded(cx);
18910        });
18911    }
18912
18913    pub fn expand_all_diff_hunks(
18914        &mut self,
18915        _: &ExpandAllDiffHunks,
18916        _window: &mut Window,
18917        cx: &mut Context<Self>,
18918    ) {
18919        self.buffer.update(cx, |buffer, cx| {
18920            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18921        });
18922    }
18923
18924    pub fn collapse_all_diff_hunks(
18925        &mut self,
18926        _: &CollapseAllDiffHunks,
18927        _window: &mut Window,
18928        cx: &mut Context<Self>,
18929    ) {
18930        self.buffer.update(cx, |buffer, cx| {
18931            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18932        });
18933    }
18934
18935    pub fn toggle_selected_diff_hunks(
18936        &mut self,
18937        _: &ToggleSelectedDiffHunks,
18938        _window: &mut Window,
18939        cx: &mut Context<Self>,
18940    ) {
18941        let ranges: Vec<_> = self
18942            .selections
18943            .disjoint_anchors()
18944            .iter()
18945            .map(|s| s.range())
18946            .collect();
18947        self.toggle_diff_hunks_in_ranges(ranges, cx);
18948    }
18949
18950    pub fn diff_hunks_in_ranges<'a>(
18951        &'a self,
18952        ranges: &'a [Range<Anchor>],
18953        buffer: &'a MultiBufferSnapshot,
18954    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18955        ranges.iter().flat_map(move |range| {
18956            let end_excerpt_id = range.end.excerpt_id;
18957            let range = range.to_point(buffer);
18958            let mut peek_end = range.end;
18959            if range.end.row < buffer.max_row().0 {
18960                peek_end = Point::new(range.end.row + 1, 0);
18961            }
18962            buffer
18963                .diff_hunks_in_range(range.start..peek_end)
18964                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18965        })
18966    }
18967
18968    pub fn has_stageable_diff_hunks_in_ranges(
18969        &self,
18970        ranges: &[Range<Anchor>],
18971        snapshot: &MultiBufferSnapshot,
18972    ) -> bool {
18973        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18974        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18975    }
18976
18977    pub fn toggle_staged_selected_diff_hunks(
18978        &mut self,
18979        _: &::git::ToggleStaged,
18980        _: &mut Window,
18981        cx: &mut Context<Self>,
18982    ) {
18983        let snapshot = self.buffer.read(cx).snapshot(cx);
18984        let ranges: Vec<_> = self
18985            .selections
18986            .disjoint_anchors()
18987            .iter()
18988            .map(|s| s.range())
18989            .collect();
18990        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18991        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18992    }
18993
18994    pub fn set_render_diff_hunk_controls(
18995        &mut self,
18996        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18997        cx: &mut Context<Self>,
18998    ) {
18999        self.render_diff_hunk_controls = render_diff_hunk_controls;
19000        cx.notify();
19001    }
19002
19003    pub fn stage_and_next(
19004        &mut self,
19005        _: &::git::StageAndNext,
19006        window: &mut Window,
19007        cx: &mut Context<Self>,
19008    ) {
19009        self.do_stage_or_unstage_and_next(true, window, cx);
19010    }
19011
19012    pub fn unstage_and_next(
19013        &mut self,
19014        _: &::git::UnstageAndNext,
19015        window: &mut Window,
19016        cx: &mut Context<Self>,
19017    ) {
19018        self.do_stage_or_unstage_and_next(false, window, cx);
19019    }
19020
19021    pub fn stage_or_unstage_diff_hunks(
19022        &mut self,
19023        stage: bool,
19024        ranges: Vec<Range<Anchor>>,
19025        cx: &mut Context<Self>,
19026    ) {
19027        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
19028        cx.spawn(async move |this, cx| {
19029            task.await?;
19030            this.update(cx, |this, cx| {
19031                let snapshot = this.buffer.read(cx).snapshot(cx);
19032                let chunk_by = this
19033                    .diff_hunks_in_ranges(&ranges, &snapshot)
19034                    .chunk_by(|hunk| hunk.buffer_id);
19035                for (buffer_id, hunks) in &chunk_by {
19036                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
19037                }
19038            })
19039        })
19040        .detach_and_log_err(cx);
19041    }
19042
19043    fn save_buffers_for_ranges_if_needed(
19044        &mut self,
19045        ranges: &[Range<Anchor>],
19046        cx: &mut Context<Editor>,
19047    ) -> Task<Result<()>> {
19048        let multibuffer = self.buffer.read(cx);
19049        let snapshot = multibuffer.read(cx);
19050        let buffer_ids: HashSet<_> = ranges
19051            .iter()
19052            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
19053            .collect();
19054        drop(snapshot);
19055
19056        let mut buffers = HashSet::default();
19057        for buffer_id in buffer_ids {
19058            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
19059                let buffer = buffer_entity.read(cx);
19060                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
19061                {
19062                    buffers.insert(buffer_entity);
19063                }
19064            }
19065        }
19066
19067        if let Some(project) = &self.project {
19068            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
19069        } else {
19070            Task::ready(Ok(()))
19071        }
19072    }
19073
19074    fn do_stage_or_unstage_and_next(
19075        &mut self,
19076        stage: bool,
19077        window: &mut Window,
19078        cx: &mut Context<Self>,
19079    ) {
19080        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
19081
19082        if ranges.iter().any(|range| range.start != range.end) {
19083            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19084            return;
19085        }
19086
19087        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19088        let snapshot = self.snapshot(window, cx);
19089        let position = self
19090            .selections
19091            .newest::<Point>(&snapshot.display_snapshot)
19092            .head();
19093        let mut row = snapshot
19094            .buffer_snapshot()
19095            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
19096            .find(|hunk| hunk.row_range.start.0 > position.row)
19097            .map(|hunk| hunk.row_range.start);
19098
19099        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
19100        // Outside of the project diff editor, wrap around to the beginning.
19101        if !all_diff_hunks_expanded {
19102            row = row.or_else(|| {
19103                snapshot
19104                    .buffer_snapshot()
19105                    .diff_hunks_in_range(Point::zero()..position)
19106                    .find(|hunk| hunk.row_range.end.0 < position.row)
19107                    .map(|hunk| hunk.row_range.start)
19108            });
19109        }
19110
19111        if let Some(row) = row {
19112            let destination = Point::new(row.0, 0);
19113            let autoscroll = Autoscroll::center();
19114
19115            self.unfold_ranges(&[destination..destination], false, false, cx);
19116            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
19117                s.select_ranges([destination..destination]);
19118            });
19119        }
19120    }
19121
19122    fn do_stage_or_unstage(
19123        &self,
19124        stage: bool,
19125        buffer_id: BufferId,
19126        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
19127        cx: &mut App,
19128    ) -> Option<()> {
19129        let project = self.project()?;
19130        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19131        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19132        let buffer_snapshot = buffer.read(cx).snapshot();
19133        let file_exists = buffer_snapshot
19134            .file()
19135            .is_some_and(|file| file.disk_state().exists());
19136        diff.update(cx, |diff, cx| {
19137            diff.stage_or_unstage_hunks(
19138                stage,
19139                &hunks
19140                    .map(|hunk| buffer_diff::DiffHunk {
19141                        buffer_range: hunk.buffer_range,
19142                        diff_base_byte_range: hunk.diff_base_byte_range,
19143                        secondary_status: hunk.secondary_status,
19144                        range: Point::zero()..Point::zero(), // unused
19145                    })
19146                    .collect::<Vec<_>>(),
19147                &buffer_snapshot,
19148                file_exists,
19149                cx,
19150            )
19151        });
19152        None
19153    }
19154
19155    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19156        let ranges: Vec<_> = self
19157            .selections
19158            .disjoint_anchors()
19159            .iter()
19160            .map(|s| s.range())
19161            .collect();
19162        self.buffer
19163            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19164    }
19165
19166    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19167        self.buffer.update(cx, |buffer, cx| {
19168            let ranges = vec![Anchor::min()..Anchor::max()];
19169            if !buffer.all_diff_hunks_expanded()
19170                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19171            {
19172                buffer.collapse_diff_hunks(ranges, cx);
19173                true
19174            } else {
19175                false
19176            }
19177        })
19178    }
19179
19180    fn toggle_diff_hunks_in_ranges(
19181        &mut self,
19182        ranges: Vec<Range<Anchor>>,
19183        cx: &mut Context<Editor>,
19184    ) {
19185        self.buffer.update(cx, |buffer, cx| {
19186            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
19187            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
19188        })
19189    }
19190
19191    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
19192        self.buffer.update(cx, |buffer, cx| {
19193            let snapshot = buffer.snapshot(cx);
19194            let excerpt_id = range.end.excerpt_id;
19195            let point_range = range.to_point(&snapshot);
19196            let expand = !buffer.single_hunk_is_expanded(range, cx);
19197            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
19198        })
19199    }
19200
19201    pub(crate) fn apply_all_diff_hunks(
19202        &mut self,
19203        _: &ApplyAllDiffHunks,
19204        window: &mut Window,
19205        cx: &mut Context<Self>,
19206    ) {
19207        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19208
19209        let buffers = self.buffer.read(cx).all_buffers();
19210        for branch_buffer in buffers {
19211            branch_buffer.update(cx, |branch_buffer, cx| {
19212                branch_buffer.merge_into_base(Vec::new(), cx);
19213            });
19214        }
19215
19216        if let Some(project) = self.project.clone() {
19217            self.save(
19218                SaveOptions {
19219                    format: true,
19220                    autosave: false,
19221                },
19222                project,
19223                window,
19224                cx,
19225            )
19226            .detach_and_log_err(cx);
19227        }
19228    }
19229
19230    pub(crate) fn apply_selected_diff_hunks(
19231        &mut self,
19232        _: &ApplyDiffHunk,
19233        window: &mut Window,
19234        cx: &mut Context<Self>,
19235    ) {
19236        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19237        let snapshot = self.snapshot(window, cx);
19238        let hunks = snapshot.hunks_for_ranges(
19239            self.selections
19240                .all(&snapshot.display_snapshot)
19241                .into_iter()
19242                .map(|selection| selection.range()),
19243        );
19244        let mut ranges_by_buffer = HashMap::default();
19245        self.transact(window, cx, |editor, _window, cx| {
19246            for hunk in hunks {
19247                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19248                    ranges_by_buffer
19249                        .entry(buffer.clone())
19250                        .or_insert_with(Vec::new)
19251                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19252                }
19253            }
19254
19255            for (buffer, ranges) in ranges_by_buffer {
19256                buffer.update(cx, |buffer, cx| {
19257                    buffer.merge_into_base(ranges, cx);
19258                });
19259            }
19260        });
19261
19262        if let Some(project) = self.project.clone() {
19263            self.save(
19264                SaveOptions {
19265                    format: true,
19266                    autosave: false,
19267                },
19268                project,
19269                window,
19270                cx,
19271            )
19272            .detach_and_log_err(cx);
19273        }
19274    }
19275
19276    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19277        if hovered != self.gutter_hovered {
19278            self.gutter_hovered = hovered;
19279            cx.notify();
19280        }
19281    }
19282
19283    pub fn insert_blocks(
19284        &mut self,
19285        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19286        autoscroll: Option<Autoscroll>,
19287        cx: &mut Context<Self>,
19288    ) -> Vec<CustomBlockId> {
19289        let blocks = self
19290            .display_map
19291            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19292        if let Some(autoscroll) = autoscroll {
19293            self.request_autoscroll(autoscroll, cx);
19294        }
19295        cx.notify();
19296        blocks
19297    }
19298
19299    pub fn resize_blocks(
19300        &mut self,
19301        heights: HashMap<CustomBlockId, u32>,
19302        autoscroll: Option<Autoscroll>,
19303        cx: &mut Context<Self>,
19304    ) {
19305        self.display_map
19306            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19307        if let Some(autoscroll) = autoscroll {
19308            self.request_autoscroll(autoscroll, cx);
19309        }
19310        cx.notify();
19311    }
19312
19313    pub fn replace_blocks(
19314        &mut self,
19315        renderers: HashMap<CustomBlockId, RenderBlock>,
19316        autoscroll: Option<Autoscroll>,
19317        cx: &mut Context<Self>,
19318    ) {
19319        self.display_map
19320            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19321        if let Some(autoscroll) = autoscroll {
19322            self.request_autoscroll(autoscroll, cx);
19323        }
19324        cx.notify();
19325    }
19326
19327    pub fn remove_blocks(
19328        &mut self,
19329        block_ids: HashSet<CustomBlockId>,
19330        autoscroll: Option<Autoscroll>,
19331        cx: &mut Context<Self>,
19332    ) {
19333        self.display_map.update(cx, |display_map, cx| {
19334            display_map.remove_blocks(block_ids, cx)
19335        });
19336        if let Some(autoscroll) = autoscroll {
19337            self.request_autoscroll(autoscroll, cx);
19338        }
19339        cx.notify();
19340    }
19341
19342    pub fn row_for_block(
19343        &self,
19344        block_id: CustomBlockId,
19345        cx: &mut Context<Self>,
19346    ) -> Option<DisplayRow> {
19347        self.display_map
19348            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19349    }
19350
19351    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19352        self.focused_block = Some(focused_block);
19353    }
19354
19355    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19356        self.focused_block.take()
19357    }
19358
19359    pub fn insert_creases(
19360        &mut self,
19361        creases: impl IntoIterator<Item = Crease<Anchor>>,
19362        cx: &mut Context<Self>,
19363    ) -> Vec<CreaseId> {
19364        self.display_map
19365            .update(cx, |map, cx| map.insert_creases(creases, cx))
19366    }
19367
19368    pub fn remove_creases(
19369        &mut self,
19370        ids: impl IntoIterator<Item = CreaseId>,
19371        cx: &mut Context<Self>,
19372    ) -> Vec<(CreaseId, Range<Anchor>)> {
19373        self.display_map
19374            .update(cx, |map, cx| map.remove_creases(ids, cx))
19375    }
19376
19377    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19378        self.display_map
19379            .update(cx, |map, cx| map.snapshot(cx))
19380            .longest_row()
19381    }
19382
19383    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19384        self.display_map
19385            .update(cx, |map, cx| map.snapshot(cx))
19386            .max_point()
19387    }
19388
19389    pub fn text(&self, cx: &App) -> String {
19390        self.buffer.read(cx).read(cx).text()
19391    }
19392
19393    pub fn is_empty(&self, cx: &App) -> bool {
19394        self.buffer.read(cx).read(cx).is_empty()
19395    }
19396
19397    pub fn text_option(&self, cx: &App) -> Option<String> {
19398        let text = self.text(cx);
19399        let text = text.trim();
19400
19401        if text.is_empty() {
19402            return None;
19403        }
19404
19405        Some(text.to_string())
19406    }
19407
19408    pub fn set_text(
19409        &mut self,
19410        text: impl Into<Arc<str>>,
19411        window: &mut Window,
19412        cx: &mut Context<Self>,
19413    ) {
19414        self.transact(window, cx, |this, _, cx| {
19415            this.buffer
19416                .read(cx)
19417                .as_singleton()
19418                .expect("you can only call set_text on editors for singleton buffers")
19419                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19420        });
19421    }
19422
19423    pub fn display_text(&self, cx: &mut App) -> String {
19424        self.display_map
19425            .update(cx, |map, cx| map.snapshot(cx))
19426            .text()
19427    }
19428
19429    fn create_minimap(
19430        &self,
19431        minimap_settings: MinimapSettings,
19432        window: &mut Window,
19433        cx: &mut Context<Self>,
19434    ) -> Option<Entity<Self>> {
19435        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19436            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19437    }
19438
19439    fn initialize_new_minimap(
19440        &self,
19441        minimap_settings: MinimapSettings,
19442        window: &mut Window,
19443        cx: &mut Context<Self>,
19444    ) -> Entity<Self> {
19445        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19446
19447        let mut minimap = Editor::new_internal(
19448            EditorMode::Minimap {
19449                parent: cx.weak_entity(),
19450            },
19451            self.buffer.clone(),
19452            None,
19453            Some(self.display_map.clone()),
19454            window,
19455            cx,
19456        );
19457        minimap.scroll_manager.clone_state(&self.scroll_manager);
19458        minimap.set_text_style_refinement(TextStyleRefinement {
19459            font_size: Some(MINIMAP_FONT_SIZE),
19460            font_weight: Some(MINIMAP_FONT_WEIGHT),
19461            ..Default::default()
19462        });
19463        minimap.update_minimap_configuration(minimap_settings, cx);
19464        cx.new(|_| minimap)
19465    }
19466
19467    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19468        let current_line_highlight = minimap_settings
19469            .current_line_highlight
19470            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19471        self.set_current_line_highlight(Some(current_line_highlight));
19472    }
19473
19474    pub fn minimap(&self) -> Option<&Entity<Self>> {
19475        self.minimap
19476            .as_ref()
19477            .filter(|_| self.minimap_visibility.visible())
19478    }
19479
19480    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19481        let mut wrap_guides = smallvec![];
19482
19483        if self.show_wrap_guides == Some(false) {
19484            return wrap_guides;
19485        }
19486
19487        let settings = self.buffer.read(cx).language_settings(cx);
19488        if settings.show_wrap_guides {
19489            match self.soft_wrap_mode(cx) {
19490                SoftWrap::Column(soft_wrap) => {
19491                    wrap_guides.push((soft_wrap as usize, true));
19492                }
19493                SoftWrap::Bounded(soft_wrap) => {
19494                    wrap_guides.push((soft_wrap as usize, true));
19495                }
19496                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19497            }
19498            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19499        }
19500
19501        wrap_guides
19502    }
19503
19504    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19505        let settings = self.buffer.read(cx).language_settings(cx);
19506        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19507        match mode {
19508            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19509                SoftWrap::None
19510            }
19511            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19512            language_settings::SoftWrap::PreferredLineLength => {
19513                SoftWrap::Column(settings.preferred_line_length)
19514            }
19515            language_settings::SoftWrap::Bounded => {
19516                SoftWrap::Bounded(settings.preferred_line_length)
19517            }
19518        }
19519    }
19520
19521    pub fn set_soft_wrap_mode(
19522        &mut self,
19523        mode: language_settings::SoftWrap,
19524
19525        cx: &mut Context<Self>,
19526    ) {
19527        self.soft_wrap_mode_override = Some(mode);
19528        cx.notify();
19529    }
19530
19531    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19532        self.hard_wrap = hard_wrap;
19533        cx.notify();
19534    }
19535
19536    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19537        self.text_style_refinement = Some(style);
19538    }
19539
19540    /// called by the Element so we know what style we were most recently rendered with.
19541    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19542        // We intentionally do not inform the display map about the minimap style
19543        // so that wrapping is not recalculated and stays consistent for the editor
19544        // and its linked minimap.
19545        if !self.mode.is_minimap() {
19546            let font = style.text.font();
19547            let font_size = style.text.font_size.to_pixels(window.rem_size());
19548            let display_map = self
19549                .placeholder_display_map
19550                .as_ref()
19551                .filter(|_| self.is_empty(cx))
19552                .unwrap_or(&self.display_map);
19553
19554            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19555        }
19556        self.style = Some(style);
19557    }
19558
19559    pub fn style(&self) -> Option<&EditorStyle> {
19560        self.style.as_ref()
19561    }
19562
19563    // Called by the element. This method is not designed to be called outside of the editor
19564    // element's layout code because it does not notify when rewrapping is computed synchronously.
19565    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19566        if self.is_empty(cx) {
19567            self.placeholder_display_map
19568                .as_ref()
19569                .map_or(false, |display_map| {
19570                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19571                })
19572        } else {
19573            self.display_map
19574                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19575        }
19576    }
19577
19578    pub fn set_soft_wrap(&mut self) {
19579        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19580    }
19581
19582    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19583        if self.soft_wrap_mode_override.is_some() {
19584            self.soft_wrap_mode_override.take();
19585        } else {
19586            let soft_wrap = match self.soft_wrap_mode(cx) {
19587                SoftWrap::GitDiff => return,
19588                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19589                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19590                    language_settings::SoftWrap::None
19591                }
19592            };
19593            self.soft_wrap_mode_override = Some(soft_wrap);
19594        }
19595        cx.notify();
19596    }
19597
19598    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19599        let Some(workspace) = self.workspace() else {
19600            return;
19601        };
19602        let fs = workspace.read(cx).app_state().fs.clone();
19603        let current_show = TabBarSettings::get_global(cx).show;
19604        update_settings_file(fs, cx, move |setting, _| {
19605            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19606        });
19607    }
19608
19609    pub fn toggle_indent_guides(
19610        &mut self,
19611        _: &ToggleIndentGuides,
19612        _: &mut Window,
19613        cx: &mut Context<Self>,
19614    ) {
19615        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19616            self.buffer
19617                .read(cx)
19618                .language_settings(cx)
19619                .indent_guides
19620                .enabled
19621        });
19622        self.show_indent_guides = Some(!currently_enabled);
19623        cx.notify();
19624    }
19625
19626    fn should_show_indent_guides(&self) -> Option<bool> {
19627        self.show_indent_guides
19628    }
19629
19630    pub fn toggle_line_numbers(
19631        &mut self,
19632        _: &ToggleLineNumbers,
19633        _: &mut Window,
19634        cx: &mut Context<Self>,
19635    ) {
19636        let mut editor_settings = EditorSettings::get_global(cx).clone();
19637        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19638        EditorSettings::override_global(editor_settings, cx);
19639    }
19640
19641    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19642        if let Some(show_line_numbers) = self.show_line_numbers {
19643            return show_line_numbers;
19644        }
19645        EditorSettings::get_global(cx).gutter.line_numbers
19646    }
19647
19648    pub fn relative_line_numbers(&self, cx: &mut App) -> RelativeLineNumbers {
19649        match (
19650            self.use_relative_line_numbers,
19651            EditorSettings::get_global(cx).relative_line_numbers,
19652        ) {
19653            (None, setting) => setting,
19654            (Some(false), _) => RelativeLineNumbers::Disabled,
19655            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
19656            (Some(true), _) => RelativeLineNumbers::Enabled,
19657        }
19658    }
19659
19660    pub fn toggle_relative_line_numbers(
19661        &mut self,
19662        _: &ToggleRelativeLineNumbers,
19663        _: &mut Window,
19664        cx: &mut Context<Self>,
19665    ) {
19666        let is_relative = self.relative_line_numbers(cx);
19667        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
19668    }
19669
19670    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19671        self.use_relative_line_numbers = is_relative;
19672        cx.notify();
19673    }
19674
19675    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19676        self.show_gutter = show_gutter;
19677        cx.notify();
19678    }
19679
19680    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19681        self.show_scrollbars = ScrollbarAxes {
19682            horizontal: show,
19683            vertical: show,
19684        };
19685        cx.notify();
19686    }
19687
19688    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19689        self.show_scrollbars.vertical = show;
19690        cx.notify();
19691    }
19692
19693    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19694        self.show_scrollbars.horizontal = show;
19695        cx.notify();
19696    }
19697
19698    pub fn set_minimap_visibility(
19699        &mut self,
19700        minimap_visibility: MinimapVisibility,
19701        window: &mut Window,
19702        cx: &mut Context<Self>,
19703    ) {
19704        if self.minimap_visibility != minimap_visibility {
19705            if minimap_visibility.visible() && self.minimap.is_none() {
19706                let minimap_settings = EditorSettings::get_global(cx).minimap;
19707                self.minimap =
19708                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19709            }
19710            self.minimap_visibility = minimap_visibility;
19711            cx.notify();
19712        }
19713    }
19714
19715    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19716        self.set_show_scrollbars(false, cx);
19717        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19718    }
19719
19720    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19721        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19722    }
19723
19724    /// Normally the text in full mode and auto height editors is padded on the
19725    /// left side by roughly half a character width for improved hit testing.
19726    ///
19727    /// Use this method to disable this for cases where this is not wanted (e.g.
19728    /// if you want to align the editor text with some other text above or below)
19729    /// or if you want to add this padding to single-line editors.
19730    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19731        self.offset_content = offset_content;
19732        cx.notify();
19733    }
19734
19735    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19736        self.show_line_numbers = Some(show_line_numbers);
19737        cx.notify();
19738    }
19739
19740    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19741        self.disable_expand_excerpt_buttons = true;
19742        cx.notify();
19743    }
19744
19745    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19746        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19747        cx.notify();
19748    }
19749
19750    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19751        self.show_code_actions = Some(show_code_actions);
19752        cx.notify();
19753    }
19754
19755    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19756        self.show_runnables = Some(show_runnables);
19757        cx.notify();
19758    }
19759
19760    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19761        self.show_breakpoints = Some(show_breakpoints);
19762        cx.notify();
19763    }
19764
19765    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19766        if self.display_map.read(cx).masked != masked {
19767            self.display_map.update(cx, |map, _| map.masked = masked);
19768        }
19769        cx.notify()
19770    }
19771
19772    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19773        self.show_wrap_guides = Some(show_wrap_guides);
19774        cx.notify();
19775    }
19776
19777    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19778        self.show_indent_guides = Some(show_indent_guides);
19779        cx.notify();
19780    }
19781
19782    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19783        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19784            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19785                && let Some(dir) = file.abs_path(cx).parent()
19786            {
19787                return Some(dir.to_owned());
19788            }
19789        }
19790
19791        None
19792    }
19793
19794    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19795        self.active_excerpt(cx)?
19796            .1
19797            .read(cx)
19798            .file()
19799            .and_then(|f| f.as_local())
19800    }
19801
19802    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19803        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19804            let buffer = buffer.read(cx);
19805            if let Some(project_path) = buffer.project_path(cx) {
19806                let project = self.project()?.read(cx);
19807                project.absolute_path(&project_path, cx)
19808            } else {
19809                buffer
19810                    .file()
19811                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19812            }
19813        })
19814    }
19815
19816    pub fn reveal_in_finder(
19817        &mut self,
19818        _: &RevealInFileManager,
19819        _window: &mut Window,
19820        cx: &mut Context<Self>,
19821    ) {
19822        if let Some(target) = self.target_file(cx) {
19823            cx.reveal_path(&target.abs_path(cx));
19824        }
19825    }
19826
19827    pub fn copy_path(
19828        &mut self,
19829        _: &zed_actions::workspace::CopyPath,
19830        _window: &mut Window,
19831        cx: &mut Context<Self>,
19832    ) {
19833        if let Some(path) = self.target_file_abs_path(cx)
19834            && let Some(path) = path.to_str()
19835        {
19836            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19837        } else {
19838            cx.propagate();
19839        }
19840    }
19841
19842    pub fn copy_relative_path(
19843        &mut self,
19844        _: &zed_actions::workspace::CopyRelativePath,
19845        _window: &mut Window,
19846        cx: &mut Context<Self>,
19847    ) {
19848        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19849            let project = self.project()?.read(cx);
19850            let path = buffer.read(cx).file()?.path();
19851            let path = path.display(project.path_style(cx));
19852            Some(path)
19853        }) {
19854            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19855        } else {
19856            cx.propagate();
19857        }
19858    }
19859
19860    /// Returns the project path for the editor's buffer, if any buffer is
19861    /// opened in the editor.
19862    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19863        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19864            buffer.read(cx).project_path(cx)
19865        } else {
19866            None
19867        }
19868    }
19869
19870    // Returns true if the editor handled a go-to-line request
19871    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19872        maybe!({
19873            let breakpoint_store = self.breakpoint_store.as_ref()?;
19874
19875            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19876            else {
19877                self.clear_row_highlights::<ActiveDebugLine>();
19878                return None;
19879            };
19880
19881            let position = active_stack_frame.position;
19882            let buffer_id = position.buffer_id?;
19883            let snapshot = self
19884                .project
19885                .as_ref()?
19886                .read(cx)
19887                .buffer_for_id(buffer_id, cx)?
19888                .read(cx)
19889                .snapshot();
19890
19891            let mut handled = false;
19892            for (id, ExcerptRange { context, .. }) in
19893                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19894            {
19895                if context.start.cmp(&position, &snapshot).is_ge()
19896                    || context.end.cmp(&position, &snapshot).is_lt()
19897                {
19898                    continue;
19899                }
19900                let snapshot = self.buffer.read(cx).snapshot(cx);
19901                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19902
19903                handled = true;
19904                self.clear_row_highlights::<ActiveDebugLine>();
19905
19906                self.go_to_line::<ActiveDebugLine>(
19907                    multibuffer_anchor,
19908                    Some(cx.theme().colors().editor_debugger_active_line_background),
19909                    window,
19910                    cx,
19911                );
19912
19913                cx.notify();
19914            }
19915
19916            handled.then_some(())
19917        })
19918        .is_some()
19919    }
19920
19921    pub fn copy_file_name_without_extension(
19922        &mut self,
19923        _: &CopyFileNameWithoutExtension,
19924        _: &mut Window,
19925        cx: &mut Context<Self>,
19926    ) {
19927        if let Some(file) = self.target_file(cx)
19928            && let Some(file_stem) = file.path().file_stem()
19929        {
19930            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
19931        }
19932    }
19933
19934    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19935        if let Some(file) = self.target_file(cx)
19936            && let Some(name) = file.path().file_name()
19937        {
19938            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19939        }
19940    }
19941
19942    pub fn toggle_git_blame(
19943        &mut self,
19944        _: &::git::Blame,
19945        window: &mut Window,
19946        cx: &mut Context<Self>,
19947    ) {
19948        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19949
19950        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19951            self.start_git_blame(true, window, cx);
19952        }
19953
19954        cx.notify();
19955    }
19956
19957    pub fn toggle_git_blame_inline(
19958        &mut self,
19959        _: &ToggleGitBlameInline,
19960        window: &mut Window,
19961        cx: &mut Context<Self>,
19962    ) {
19963        self.toggle_git_blame_inline_internal(true, window, cx);
19964        cx.notify();
19965    }
19966
19967    pub fn open_git_blame_commit(
19968        &mut self,
19969        _: &OpenGitBlameCommit,
19970        window: &mut Window,
19971        cx: &mut Context<Self>,
19972    ) {
19973        self.open_git_blame_commit_internal(window, cx);
19974    }
19975
19976    fn open_git_blame_commit_internal(
19977        &mut self,
19978        window: &mut Window,
19979        cx: &mut Context<Self>,
19980    ) -> Option<()> {
19981        let blame = self.blame.as_ref()?;
19982        let snapshot = self.snapshot(window, cx);
19983        let cursor = self
19984            .selections
19985            .newest::<Point>(&snapshot.display_snapshot)
19986            .head();
19987        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
19988        let (_, blame_entry) = blame
19989            .update(cx, |blame, cx| {
19990                blame
19991                    .blame_for_rows(
19992                        &[RowInfo {
19993                            buffer_id: Some(buffer.remote_id()),
19994                            buffer_row: Some(point.row),
19995                            ..Default::default()
19996                        }],
19997                        cx,
19998                    )
19999                    .next()
20000            })
20001            .flatten()?;
20002        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20003        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
20004        let workspace = self.workspace()?.downgrade();
20005        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
20006        None
20007    }
20008
20009    pub fn git_blame_inline_enabled(&self) -> bool {
20010        self.git_blame_inline_enabled
20011    }
20012
20013    pub fn toggle_selection_menu(
20014        &mut self,
20015        _: &ToggleSelectionMenu,
20016        _: &mut Window,
20017        cx: &mut Context<Self>,
20018    ) {
20019        self.show_selection_menu = self
20020            .show_selection_menu
20021            .map(|show_selections_menu| !show_selections_menu)
20022            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
20023
20024        cx.notify();
20025    }
20026
20027    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
20028        self.show_selection_menu
20029            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
20030    }
20031
20032    fn start_git_blame(
20033        &mut self,
20034        user_triggered: bool,
20035        window: &mut Window,
20036        cx: &mut Context<Self>,
20037    ) {
20038        if let Some(project) = self.project() {
20039            if let Some(buffer) = self.buffer().read(cx).as_singleton()
20040                && buffer.read(cx).file().is_none()
20041            {
20042                return;
20043            }
20044
20045            let focused = self.focus_handle(cx).contains_focused(window, cx);
20046
20047            let project = project.clone();
20048            let blame = cx
20049                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
20050            self.blame_subscription =
20051                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
20052            self.blame = Some(blame);
20053        }
20054    }
20055
20056    fn toggle_git_blame_inline_internal(
20057        &mut self,
20058        user_triggered: bool,
20059        window: &mut Window,
20060        cx: &mut Context<Self>,
20061    ) {
20062        if self.git_blame_inline_enabled {
20063            self.git_blame_inline_enabled = false;
20064            self.show_git_blame_inline = false;
20065            self.show_git_blame_inline_delay_task.take();
20066        } else {
20067            self.git_blame_inline_enabled = true;
20068            self.start_git_blame_inline(user_triggered, window, cx);
20069        }
20070
20071        cx.notify();
20072    }
20073
20074    fn start_git_blame_inline(
20075        &mut self,
20076        user_triggered: bool,
20077        window: &mut Window,
20078        cx: &mut Context<Self>,
20079    ) {
20080        self.start_git_blame(user_triggered, window, cx);
20081
20082        if ProjectSettings::get_global(cx)
20083            .git
20084            .inline_blame_delay()
20085            .is_some()
20086        {
20087            self.start_inline_blame_timer(window, cx);
20088        } else {
20089            self.show_git_blame_inline = true
20090        }
20091    }
20092
20093    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
20094        self.blame.as_ref()
20095    }
20096
20097    pub fn show_git_blame_gutter(&self) -> bool {
20098        self.show_git_blame_gutter
20099    }
20100
20101    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
20102        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
20103    }
20104
20105    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
20106        self.show_git_blame_inline
20107            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
20108            && !self.newest_selection_head_on_empty_line(cx)
20109            && self.has_blame_entries(cx)
20110    }
20111
20112    fn has_blame_entries(&self, cx: &App) -> bool {
20113        self.blame()
20114            .is_some_and(|blame| blame.read(cx).has_generated_entries())
20115    }
20116
20117    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
20118        let cursor_anchor = self.selections.newest_anchor().head();
20119
20120        let snapshot = self.buffer.read(cx).snapshot(cx);
20121        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
20122
20123        snapshot.line_len(buffer_row) == 0
20124    }
20125
20126    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
20127        let buffer_and_selection = maybe!({
20128            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20129            let selection_range = selection.range();
20130
20131            let multi_buffer = self.buffer().read(cx);
20132            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20133            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
20134
20135            let (buffer, range, _) = if selection.reversed {
20136                buffer_ranges.first()
20137            } else {
20138                buffer_ranges.last()
20139            }?;
20140
20141            let selection = text::ToPoint::to_point(&range.start, buffer).row
20142                ..text::ToPoint::to_point(&range.end, buffer).row;
20143            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
20144        });
20145
20146        let Some((buffer, selection)) = buffer_and_selection else {
20147            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
20148        };
20149
20150        let Some(project) = self.project() else {
20151            return Task::ready(Err(anyhow!("editor does not have project")));
20152        };
20153
20154        project.update(cx, |project, cx| {
20155            project.get_permalink_to_line(&buffer, selection, cx)
20156        })
20157    }
20158
20159    pub fn copy_permalink_to_line(
20160        &mut self,
20161        _: &CopyPermalinkToLine,
20162        window: &mut Window,
20163        cx: &mut Context<Self>,
20164    ) {
20165        let permalink_task = self.get_permalink_to_line(cx);
20166        let workspace = self.workspace();
20167
20168        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20169            Ok(permalink) => {
20170                cx.update(|_, cx| {
20171                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
20172                })
20173                .ok();
20174            }
20175            Err(err) => {
20176                let message = format!("Failed to copy permalink: {err}");
20177
20178                anyhow::Result::<()>::Err(err).log_err();
20179
20180                if let Some(workspace) = workspace {
20181                    workspace
20182                        .update_in(cx, |workspace, _, cx| {
20183                            struct CopyPermalinkToLine;
20184
20185                            workspace.show_toast(
20186                                Toast::new(
20187                                    NotificationId::unique::<CopyPermalinkToLine>(),
20188                                    message,
20189                                ),
20190                                cx,
20191                            )
20192                        })
20193                        .ok();
20194                }
20195            }
20196        })
20197        .detach();
20198    }
20199
20200    pub fn copy_file_location(
20201        &mut self,
20202        _: &CopyFileLocation,
20203        _: &mut Window,
20204        cx: &mut Context<Self>,
20205    ) {
20206        let selection = self
20207            .selections
20208            .newest::<Point>(&self.display_snapshot(cx))
20209            .start
20210            .row
20211            + 1;
20212        if let Some(file) = self.target_file(cx) {
20213            let path = file.path().display(file.path_style(cx));
20214            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
20215        }
20216    }
20217
20218    pub fn open_permalink_to_line(
20219        &mut self,
20220        _: &OpenPermalinkToLine,
20221        window: &mut Window,
20222        cx: &mut Context<Self>,
20223    ) {
20224        let permalink_task = self.get_permalink_to_line(cx);
20225        let workspace = self.workspace();
20226
20227        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20228            Ok(permalink) => {
20229                cx.update(|_, cx| {
20230                    cx.open_url(permalink.as_ref());
20231                })
20232                .ok();
20233            }
20234            Err(err) => {
20235                let message = format!("Failed to open permalink: {err}");
20236
20237                anyhow::Result::<()>::Err(err).log_err();
20238
20239                if let Some(workspace) = workspace {
20240                    workspace
20241                        .update(cx, |workspace, cx| {
20242                            struct OpenPermalinkToLine;
20243
20244                            workspace.show_toast(
20245                                Toast::new(
20246                                    NotificationId::unique::<OpenPermalinkToLine>(),
20247                                    message,
20248                                ),
20249                                cx,
20250                            )
20251                        })
20252                        .ok();
20253                }
20254            }
20255        })
20256        .detach();
20257    }
20258
20259    pub fn insert_uuid_v4(
20260        &mut self,
20261        _: &InsertUuidV4,
20262        window: &mut Window,
20263        cx: &mut Context<Self>,
20264    ) {
20265        self.insert_uuid(UuidVersion::V4, window, cx);
20266    }
20267
20268    pub fn insert_uuid_v7(
20269        &mut self,
20270        _: &InsertUuidV7,
20271        window: &mut Window,
20272        cx: &mut Context<Self>,
20273    ) {
20274        self.insert_uuid(UuidVersion::V7, window, cx);
20275    }
20276
20277    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20278        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20279        self.transact(window, cx, |this, window, cx| {
20280            let edits = this
20281                .selections
20282                .all::<Point>(&this.display_snapshot(cx))
20283                .into_iter()
20284                .map(|selection| {
20285                    let uuid = match version {
20286                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20287                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20288                    };
20289
20290                    (selection.range(), uuid.to_string())
20291                });
20292            this.edit(edits, cx);
20293            this.refresh_edit_prediction(true, false, window, cx);
20294        });
20295    }
20296
20297    pub fn open_selections_in_multibuffer(
20298        &mut self,
20299        _: &OpenSelectionsInMultibuffer,
20300        window: &mut Window,
20301        cx: &mut Context<Self>,
20302    ) {
20303        let multibuffer = self.buffer.read(cx);
20304
20305        let Some(buffer) = multibuffer.as_singleton() else {
20306            return;
20307        };
20308
20309        let Some(workspace) = self.workspace() else {
20310            return;
20311        };
20312
20313        let title = multibuffer.title(cx).to_string();
20314
20315        let locations = self
20316            .selections
20317            .all_anchors(&self.display_snapshot(cx))
20318            .iter()
20319            .map(|selection| {
20320                (
20321                    buffer.clone(),
20322                    (selection.start.text_anchor..selection.end.text_anchor)
20323                        .to_point(buffer.read(cx)),
20324                )
20325            })
20326            .into_group_map();
20327
20328        cx.spawn_in(window, async move |_, cx| {
20329            workspace.update_in(cx, |workspace, window, cx| {
20330                Self::open_locations_in_multibuffer(
20331                    workspace,
20332                    locations,
20333                    format!("Selections for '{title}'"),
20334                    false,
20335                    MultibufferSelectionMode::All,
20336                    window,
20337                    cx,
20338                );
20339            })
20340        })
20341        .detach();
20342    }
20343
20344    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20345    /// last highlight added will be used.
20346    ///
20347    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20348    pub fn highlight_rows<T: 'static>(
20349        &mut self,
20350        range: Range<Anchor>,
20351        color: Hsla,
20352        options: RowHighlightOptions,
20353        cx: &mut Context<Self>,
20354    ) {
20355        let snapshot = self.buffer().read(cx).snapshot(cx);
20356        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20357        let ix = row_highlights.binary_search_by(|highlight| {
20358            Ordering::Equal
20359                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20360                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20361        });
20362
20363        if let Err(mut ix) = ix {
20364            let index = post_inc(&mut self.highlight_order);
20365
20366            // If this range intersects with the preceding highlight, then merge it with
20367            // the preceding highlight. Otherwise insert a new highlight.
20368            let mut merged = false;
20369            if ix > 0 {
20370                let prev_highlight = &mut row_highlights[ix - 1];
20371                if prev_highlight
20372                    .range
20373                    .end
20374                    .cmp(&range.start, &snapshot)
20375                    .is_ge()
20376                {
20377                    ix -= 1;
20378                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20379                        prev_highlight.range.end = range.end;
20380                    }
20381                    merged = true;
20382                    prev_highlight.index = index;
20383                    prev_highlight.color = color;
20384                    prev_highlight.options = options;
20385                }
20386            }
20387
20388            if !merged {
20389                row_highlights.insert(
20390                    ix,
20391                    RowHighlight {
20392                        range,
20393                        index,
20394                        color,
20395                        options,
20396                        type_id: TypeId::of::<T>(),
20397                    },
20398                );
20399            }
20400
20401            // If any of the following highlights intersect with this one, merge them.
20402            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20403                let highlight = &row_highlights[ix];
20404                if next_highlight
20405                    .range
20406                    .start
20407                    .cmp(&highlight.range.end, &snapshot)
20408                    .is_le()
20409                {
20410                    if next_highlight
20411                        .range
20412                        .end
20413                        .cmp(&highlight.range.end, &snapshot)
20414                        .is_gt()
20415                    {
20416                        row_highlights[ix].range.end = next_highlight.range.end;
20417                    }
20418                    row_highlights.remove(ix + 1);
20419                } else {
20420                    break;
20421                }
20422            }
20423        }
20424    }
20425
20426    /// Remove any highlighted row ranges of the given type that intersect the
20427    /// given ranges.
20428    pub fn remove_highlighted_rows<T: 'static>(
20429        &mut self,
20430        ranges_to_remove: Vec<Range<Anchor>>,
20431        cx: &mut Context<Self>,
20432    ) {
20433        let snapshot = self.buffer().read(cx).snapshot(cx);
20434        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20435        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20436        row_highlights.retain(|highlight| {
20437            while let Some(range_to_remove) = ranges_to_remove.peek() {
20438                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20439                    Ordering::Less | Ordering::Equal => {
20440                        ranges_to_remove.next();
20441                    }
20442                    Ordering::Greater => {
20443                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20444                            Ordering::Less | Ordering::Equal => {
20445                                return false;
20446                            }
20447                            Ordering::Greater => break,
20448                        }
20449                    }
20450                }
20451            }
20452
20453            true
20454        })
20455    }
20456
20457    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20458    pub fn clear_row_highlights<T: 'static>(&mut self) {
20459        self.highlighted_rows.remove(&TypeId::of::<T>());
20460    }
20461
20462    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20463    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20464        self.highlighted_rows
20465            .get(&TypeId::of::<T>())
20466            .map_or(&[] as &[_], |vec| vec.as_slice())
20467            .iter()
20468            .map(|highlight| (highlight.range.clone(), highlight.color))
20469    }
20470
20471    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20472    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20473    /// Allows to ignore certain kinds of highlights.
20474    pub fn highlighted_display_rows(
20475        &self,
20476        window: &mut Window,
20477        cx: &mut App,
20478    ) -> BTreeMap<DisplayRow, LineHighlight> {
20479        let snapshot = self.snapshot(window, cx);
20480        let mut used_highlight_orders = HashMap::default();
20481        self.highlighted_rows
20482            .iter()
20483            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20484            .fold(
20485                BTreeMap::<DisplayRow, LineHighlight>::new(),
20486                |mut unique_rows, highlight| {
20487                    let start = highlight.range.start.to_display_point(&snapshot);
20488                    let end = highlight.range.end.to_display_point(&snapshot);
20489                    let start_row = start.row().0;
20490                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20491                        && end.column() == 0
20492                    {
20493                        end.row().0.saturating_sub(1)
20494                    } else {
20495                        end.row().0
20496                    };
20497                    for row in start_row..=end_row {
20498                        let used_index =
20499                            used_highlight_orders.entry(row).or_insert(highlight.index);
20500                        if highlight.index >= *used_index {
20501                            *used_index = highlight.index;
20502                            unique_rows.insert(
20503                                DisplayRow(row),
20504                                LineHighlight {
20505                                    include_gutter: highlight.options.include_gutter,
20506                                    border: None,
20507                                    background: highlight.color.into(),
20508                                    type_id: Some(highlight.type_id),
20509                                },
20510                            );
20511                        }
20512                    }
20513                    unique_rows
20514                },
20515            )
20516    }
20517
20518    pub fn highlighted_display_row_for_autoscroll(
20519        &self,
20520        snapshot: &DisplaySnapshot,
20521    ) -> Option<DisplayRow> {
20522        self.highlighted_rows
20523            .values()
20524            .flat_map(|highlighted_rows| highlighted_rows.iter())
20525            .filter_map(|highlight| {
20526                if highlight.options.autoscroll {
20527                    Some(highlight.range.start.to_display_point(snapshot).row())
20528                } else {
20529                    None
20530                }
20531            })
20532            .min()
20533    }
20534
20535    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20536        self.highlight_background::<SearchWithinRange>(
20537            ranges,
20538            |colors| colors.colors().editor_document_highlight_read_background,
20539            cx,
20540        )
20541    }
20542
20543    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20544        self.breadcrumb_header = Some(new_header);
20545    }
20546
20547    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20548        self.clear_background_highlights::<SearchWithinRange>(cx);
20549    }
20550
20551    pub fn highlight_background<T: 'static>(
20552        &mut self,
20553        ranges: &[Range<Anchor>],
20554        color_fetcher: fn(&Theme) -> Hsla,
20555        cx: &mut Context<Self>,
20556    ) {
20557        self.background_highlights.insert(
20558            HighlightKey::Type(TypeId::of::<T>()),
20559            (color_fetcher, Arc::from(ranges)),
20560        );
20561        self.scrollbar_marker_state.dirty = true;
20562        cx.notify();
20563    }
20564
20565    pub fn highlight_background_key<T: 'static>(
20566        &mut self,
20567        key: usize,
20568        ranges: &[Range<Anchor>],
20569        color_fetcher: fn(&Theme) -> Hsla,
20570        cx: &mut Context<Self>,
20571    ) {
20572        self.background_highlights.insert(
20573            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20574            (color_fetcher, Arc::from(ranges)),
20575        );
20576        self.scrollbar_marker_state.dirty = true;
20577        cx.notify();
20578    }
20579
20580    pub fn clear_background_highlights<T: 'static>(
20581        &mut self,
20582        cx: &mut Context<Self>,
20583    ) -> Option<BackgroundHighlight> {
20584        let text_highlights = self
20585            .background_highlights
20586            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20587        if !text_highlights.1.is_empty() {
20588            self.scrollbar_marker_state.dirty = true;
20589            cx.notify();
20590        }
20591        Some(text_highlights)
20592    }
20593
20594    pub fn highlight_gutter<T: 'static>(
20595        &mut self,
20596        ranges: impl Into<Vec<Range<Anchor>>>,
20597        color_fetcher: fn(&App) -> Hsla,
20598        cx: &mut Context<Self>,
20599    ) {
20600        self.gutter_highlights
20601            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20602        cx.notify();
20603    }
20604
20605    pub fn clear_gutter_highlights<T: 'static>(
20606        &mut self,
20607        cx: &mut Context<Self>,
20608    ) -> Option<GutterHighlight> {
20609        cx.notify();
20610        self.gutter_highlights.remove(&TypeId::of::<T>())
20611    }
20612
20613    pub fn insert_gutter_highlight<T: 'static>(
20614        &mut self,
20615        range: Range<Anchor>,
20616        color_fetcher: fn(&App) -> Hsla,
20617        cx: &mut Context<Self>,
20618    ) {
20619        let snapshot = self.buffer().read(cx).snapshot(cx);
20620        let mut highlights = self
20621            .gutter_highlights
20622            .remove(&TypeId::of::<T>())
20623            .map(|(_, highlights)| highlights)
20624            .unwrap_or_default();
20625        let ix = highlights.binary_search_by(|highlight| {
20626            Ordering::Equal
20627                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20628                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20629        });
20630        if let Err(ix) = ix {
20631            highlights.insert(ix, range);
20632        }
20633        self.gutter_highlights
20634            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20635    }
20636
20637    pub fn remove_gutter_highlights<T: 'static>(
20638        &mut self,
20639        ranges_to_remove: Vec<Range<Anchor>>,
20640        cx: &mut Context<Self>,
20641    ) {
20642        let snapshot = self.buffer().read(cx).snapshot(cx);
20643        let Some((color_fetcher, mut gutter_highlights)) =
20644            self.gutter_highlights.remove(&TypeId::of::<T>())
20645        else {
20646            return;
20647        };
20648        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20649        gutter_highlights.retain(|highlight| {
20650            while let Some(range_to_remove) = ranges_to_remove.peek() {
20651                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20652                    Ordering::Less | Ordering::Equal => {
20653                        ranges_to_remove.next();
20654                    }
20655                    Ordering::Greater => {
20656                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20657                            Ordering::Less | Ordering::Equal => {
20658                                return false;
20659                            }
20660                            Ordering::Greater => break,
20661                        }
20662                    }
20663                }
20664            }
20665
20666            true
20667        });
20668        self.gutter_highlights
20669            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20670    }
20671
20672    #[cfg(feature = "test-support")]
20673    pub fn all_text_highlights(
20674        &self,
20675        window: &mut Window,
20676        cx: &mut Context<Self>,
20677    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20678        let snapshot = self.snapshot(window, cx);
20679        self.display_map.update(cx, |display_map, _| {
20680            display_map
20681                .all_text_highlights()
20682                .map(|highlight| {
20683                    let (style, ranges) = highlight.as_ref();
20684                    (
20685                        *style,
20686                        ranges
20687                            .iter()
20688                            .map(|range| range.clone().to_display_points(&snapshot))
20689                            .collect(),
20690                    )
20691                })
20692                .collect()
20693        })
20694    }
20695
20696    #[cfg(feature = "test-support")]
20697    pub fn all_text_background_highlights(
20698        &self,
20699        window: &mut Window,
20700        cx: &mut Context<Self>,
20701    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20702        let snapshot = self.snapshot(window, cx);
20703        let buffer = &snapshot.buffer_snapshot();
20704        let start = buffer.anchor_before(0);
20705        let end = buffer.anchor_after(buffer.len());
20706        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20707    }
20708
20709    #[cfg(any(test, feature = "test-support"))]
20710    pub fn sorted_background_highlights_in_range(
20711        &self,
20712        search_range: Range<Anchor>,
20713        display_snapshot: &DisplaySnapshot,
20714        theme: &Theme,
20715    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20716        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20717        res.sort_by(|a, b| {
20718            a.0.start
20719                .cmp(&b.0.start)
20720                .then_with(|| a.0.end.cmp(&b.0.end))
20721                .then_with(|| a.1.cmp(&b.1))
20722        });
20723        res
20724    }
20725
20726    #[cfg(feature = "test-support")]
20727    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20728        let snapshot = self.buffer().read(cx).snapshot(cx);
20729
20730        let highlights = self
20731            .background_highlights
20732            .get(&HighlightKey::Type(TypeId::of::<
20733                items::BufferSearchHighlights,
20734            >()));
20735
20736        if let Some((_color, ranges)) = highlights {
20737            ranges
20738                .iter()
20739                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20740                .collect_vec()
20741        } else {
20742            vec![]
20743        }
20744    }
20745
20746    fn document_highlights_for_position<'a>(
20747        &'a self,
20748        position: Anchor,
20749        buffer: &'a MultiBufferSnapshot,
20750    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20751        let read_highlights = self
20752            .background_highlights
20753            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20754            .map(|h| &h.1);
20755        let write_highlights = self
20756            .background_highlights
20757            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20758            .map(|h| &h.1);
20759        let left_position = position.bias_left(buffer);
20760        let right_position = position.bias_right(buffer);
20761        read_highlights
20762            .into_iter()
20763            .chain(write_highlights)
20764            .flat_map(move |ranges| {
20765                let start_ix = match ranges.binary_search_by(|probe| {
20766                    let cmp = probe.end.cmp(&left_position, buffer);
20767                    if cmp.is_ge() {
20768                        Ordering::Greater
20769                    } else {
20770                        Ordering::Less
20771                    }
20772                }) {
20773                    Ok(i) | Err(i) => i,
20774                };
20775
20776                ranges[start_ix..]
20777                    .iter()
20778                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20779            })
20780    }
20781
20782    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20783        self.background_highlights
20784            .get(&HighlightKey::Type(TypeId::of::<T>()))
20785            .is_some_and(|(_, highlights)| !highlights.is_empty())
20786    }
20787
20788    /// Returns all background highlights for a given range.
20789    ///
20790    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20791    pub fn background_highlights_in_range(
20792        &self,
20793        search_range: Range<Anchor>,
20794        display_snapshot: &DisplaySnapshot,
20795        theme: &Theme,
20796    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20797        let mut results = Vec::new();
20798        for (color_fetcher, ranges) in self.background_highlights.values() {
20799            let color = color_fetcher(theme);
20800            let start_ix = match ranges.binary_search_by(|probe| {
20801                let cmp = probe
20802                    .end
20803                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20804                if cmp.is_gt() {
20805                    Ordering::Greater
20806                } else {
20807                    Ordering::Less
20808                }
20809            }) {
20810                Ok(i) | Err(i) => i,
20811            };
20812            for range in &ranges[start_ix..] {
20813                if range
20814                    .start
20815                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20816                    .is_ge()
20817                {
20818                    break;
20819                }
20820
20821                let start = range.start.to_display_point(display_snapshot);
20822                let end = range.end.to_display_point(display_snapshot);
20823                results.push((start..end, color))
20824            }
20825        }
20826        results
20827    }
20828
20829    pub fn gutter_highlights_in_range(
20830        &self,
20831        search_range: Range<Anchor>,
20832        display_snapshot: &DisplaySnapshot,
20833        cx: &App,
20834    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20835        let mut results = Vec::new();
20836        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20837            let color = color_fetcher(cx);
20838            let start_ix = match ranges.binary_search_by(|probe| {
20839                let cmp = probe
20840                    .end
20841                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20842                if cmp.is_gt() {
20843                    Ordering::Greater
20844                } else {
20845                    Ordering::Less
20846                }
20847            }) {
20848                Ok(i) | Err(i) => i,
20849            };
20850            for range in &ranges[start_ix..] {
20851                if range
20852                    .start
20853                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20854                    .is_ge()
20855                {
20856                    break;
20857                }
20858
20859                let start = range.start.to_display_point(display_snapshot);
20860                let end = range.end.to_display_point(display_snapshot);
20861                results.push((start..end, color))
20862            }
20863        }
20864        results
20865    }
20866
20867    /// Get the text ranges corresponding to the redaction query
20868    pub fn redacted_ranges(
20869        &self,
20870        search_range: Range<Anchor>,
20871        display_snapshot: &DisplaySnapshot,
20872        cx: &App,
20873    ) -> Vec<Range<DisplayPoint>> {
20874        display_snapshot
20875            .buffer_snapshot()
20876            .redacted_ranges(search_range, |file| {
20877                if let Some(file) = file {
20878                    file.is_private()
20879                        && EditorSettings::get(
20880                            Some(SettingsLocation {
20881                                worktree_id: file.worktree_id(cx),
20882                                path: file.path().as_ref(),
20883                            }),
20884                            cx,
20885                        )
20886                        .redact_private_values
20887                } else {
20888                    false
20889                }
20890            })
20891            .map(|range| {
20892                range.start.to_display_point(display_snapshot)
20893                    ..range.end.to_display_point(display_snapshot)
20894            })
20895            .collect()
20896    }
20897
20898    pub fn highlight_text_key<T: 'static>(
20899        &mut self,
20900        key: usize,
20901        ranges: Vec<Range<Anchor>>,
20902        style: HighlightStyle,
20903        cx: &mut Context<Self>,
20904    ) {
20905        self.display_map.update(cx, |map, _| {
20906            map.highlight_text(
20907                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20908                ranges,
20909                style,
20910            );
20911        });
20912        cx.notify();
20913    }
20914
20915    pub fn highlight_text<T: 'static>(
20916        &mut self,
20917        ranges: Vec<Range<Anchor>>,
20918        style: HighlightStyle,
20919        cx: &mut Context<Self>,
20920    ) {
20921        self.display_map.update(cx, |map, _| {
20922            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20923        });
20924        cx.notify();
20925    }
20926
20927    pub fn text_highlights<'a, T: 'static>(
20928        &'a self,
20929        cx: &'a App,
20930    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20931        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20932    }
20933
20934    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20935        let cleared = self
20936            .display_map
20937            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20938        if cleared {
20939            cx.notify();
20940        }
20941    }
20942
20943    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20944        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20945            && self.focus_handle.is_focused(window)
20946    }
20947
20948    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20949        self.show_cursor_when_unfocused = is_enabled;
20950        cx.notify();
20951    }
20952
20953    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20954        cx.notify();
20955    }
20956
20957    fn on_debug_session_event(
20958        &mut self,
20959        _session: Entity<Session>,
20960        event: &SessionEvent,
20961        cx: &mut Context<Self>,
20962    ) {
20963        if let SessionEvent::InvalidateInlineValue = event {
20964            self.refresh_inline_values(cx);
20965        }
20966    }
20967
20968    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20969        let Some(project) = self.project.clone() else {
20970            return;
20971        };
20972
20973        if !self.inline_value_cache.enabled {
20974            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20975            self.splice_inlays(&inlays, Vec::new(), cx);
20976            return;
20977        }
20978
20979        let current_execution_position = self
20980            .highlighted_rows
20981            .get(&TypeId::of::<ActiveDebugLine>())
20982            .and_then(|lines| lines.last().map(|line| line.range.end));
20983
20984        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20985            let inline_values = editor
20986                .update(cx, |editor, cx| {
20987                    let Some(current_execution_position) = current_execution_position else {
20988                        return Some(Task::ready(Ok(Vec::new())));
20989                    };
20990
20991                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20992                        let snapshot = buffer.snapshot(cx);
20993
20994                        let excerpt = snapshot.excerpt_containing(
20995                            current_execution_position..current_execution_position,
20996                        )?;
20997
20998                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20999                    })?;
21000
21001                    let range =
21002                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
21003
21004                    project.inline_values(buffer, range, cx)
21005                })
21006                .ok()
21007                .flatten()?
21008                .await
21009                .context("refreshing debugger inlays")
21010                .log_err()?;
21011
21012            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
21013
21014            for (buffer_id, inline_value) in inline_values
21015                .into_iter()
21016                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
21017            {
21018                buffer_inline_values
21019                    .entry(buffer_id)
21020                    .or_default()
21021                    .push(inline_value);
21022            }
21023
21024            editor
21025                .update(cx, |editor, cx| {
21026                    let snapshot = editor.buffer.read(cx).snapshot(cx);
21027                    let mut new_inlays = Vec::default();
21028
21029                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
21030                        let buffer_id = buffer_snapshot.remote_id();
21031                        buffer_inline_values
21032                            .get(&buffer_id)
21033                            .into_iter()
21034                            .flatten()
21035                            .for_each(|hint| {
21036                                let inlay = Inlay::debugger(
21037                                    post_inc(&mut editor.next_inlay_id),
21038                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
21039                                    hint.text(),
21040                                );
21041                                if !inlay.text().chars().contains(&'\n') {
21042                                    new_inlays.push(inlay);
21043                                }
21044                            });
21045                    }
21046
21047                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
21048                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
21049
21050                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
21051                })
21052                .ok()?;
21053            Some(())
21054        });
21055    }
21056
21057    fn on_buffer_event(
21058        &mut self,
21059        multibuffer: &Entity<MultiBuffer>,
21060        event: &multi_buffer::Event,
21061        window: &mut Window,
21062        cx: &mut Context<Self>,
21063    ) {
21064        match event {
21065            multi_buffer::Event::Edited { edited_buffer } => {
21066                self.scrollbar_marker_state.dirty = true;
21067                self.active_indent_guides_state.dirty = true;
21068                self.refresh_active_diagnostics(cx);
21069                self.refresh_code_actions(window, cx);
21070                self.refresh_selected_text_highlights(true, window, cx);
21071                self.refresh_single_line_folds(window, cx);
21072                self.refresh_matching_bracket_highlights(window, cx);
21073                if self.has_active_edit_prediction() {
21074                    self.update_visible_edit_prediction(window, cx);
21075                }
21076
21077                if let Some(buffer) = edited_buffer {
21078                    if buffer.read(cx).file().is_none() {
21079                        cx.emit(EditorEvent::TitleChanged);
21080                    }
21081
21082                    if self.project.is_some() {
21083                        let buffer_id = buffer.read(cx).remote_id();
21084                        self.register_buffer(buffer_id, cx);
21085                        self.update_lsp_data(Some(buffer_id), window, cx);
21086                        self.refresh_inlay_hints(
21087                            InlayHintRefreshReason::BufferEdited(buffer_id),
21088                            cx,
21089                        );
21090                    }
21091                }
21092
21093                cx.emit(EditorEvent::BufferEdited);
21094                cx.emit(SearchEvent::MatchesInvalidated);
21095
21096                let Some(project) = &self.project else { return };
21097                let (telemetry, is_via_ssh) = {
21098                    let project = project.read(cx);
21099                    let telemetry = project.client().telemetry().clone();
21100                    let is_via_ssh = project.is_via_remote_server();
21101                    (telemetry, is_via_ssh)
21102                };
21103                telemetry.log_edit_event("editor", is_via_ssh);
21104            }
21105            multi_buffer::Event::ExcerptsAdded {
21106                buffer,
21107                predecessor,
21108                excerpts,
21109            } => {
21110                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21111                let buffer_id = buffer.read(cx).remote_id();
21112                if self.buffer.read(cx).diff_for(buffer_id).is_none()
21113                    && let Some(project) = &self.project
21114                {
21115                    update_uncommitted_diff_for_buffer(
21116                        cx.entity(),
21117                        project,
21118                        [buffer.clone()],
21119                        self.buffer.clone(),
21120                        cx,
21121                    )
21122                    .detach();
21123                }
21124                self.update_lsp_data(Some(buffer_id), window, cx);
21125                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21126                cx.emit(EditorEvent::ExcerptsAdded {
21127                    buffer: buffer.clone(),
21128                    predecessor: *predecessor,
21129                    excerpts: excerpts.clone(),
21130                });
21131            }
21132            multi_buffer::Event::ExcerptsRemoved {
21133                ids,
21134                removed_buffer_ids,
21135            } => {
21136                if let Some(inlay_hints) = &mut self.inlay_hints {
21137                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
21138                }
21139                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
21140                for buffer_id in removed_buffer_ids {
21141                    self.registered_buffers.remove(buffer_id);
21142                }
21143                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21144                cx.emit(EditorEvent::ExcerptsRemoved {
21145                    ids: ids.clone(),
21146                    removed_buffer_ids: removed_buffer_ids.clone(),
21147                });
21148            }
21149            multi_buffer::Event::ExcerptsEdited {
21150                excerpt_ids,
21151                buffer_ids,
21152            } => {
21153                self.display_map.update(cx, |map, cx| {
21154                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
21155                });
21156                cx.emit(EditorEvent::ExcerptsEdited {
21157                    ids: excerpt_ids.clone(),
21158                });
21159            }
21160            multi_buffer::Event::ExcerptsExpanded { ids } => {
21161                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21162                self.refresh_document_highlights(cx);
21163                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
21164            }
21165            multi_buffer::Event::Reparsed(buffer_id) => {
21166                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21167                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21168
21169                cx.emit(EditorEvent::Reparsed(*buffer_id));
21170            }
21171            multi_buffer::Event::DiffHunksToggled => {
21172                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21173            }
21174            multi_buffer::Event::LanguageChanged(buffer_id) => {
21175                self.registered_buffers.remove(&buffer_id);
21176                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21177                cx.emit(EditorEvent::Reparsed(*buffer_id));
21178                cx.notify();
21179            }
21180            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
21181            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21182            multi_buffer::Event::FileHandleChanged
21183            | multi_buffer::Event::Reloaded
21184            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21185            multi_buffer::Event::DiagnosticsUpdated => {
21186                self.update_diagnostics_state(window, cx);
21187            }
21188            _ => {}
21189        };
21190    }
21191
21192    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21193        if !self.diagnostics_enabled() {
21194            return;
21195        }
21196        self.refresh_active_diagnostics(cx);
21197        self.refresh_inline_diagnostics(true, window, cx);
21198        self.scrollbar_marker_state.dirty = true;
21199        cx.notify();
21200    }
21201
21202    pub fn start_temporary_diff_override(&mut self) {
21203        self.load_diff_task.take();
21204        self.temporary_diff_override = true;
21205    }
21206
21207    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21208        self.temporary_diff_override = false;
21209        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21210        self.buffer.update(cx, |buffer, cx| {
21211            buffer.set_all_diff_hunks_collapsed(cx);
21212        });
21213
21214        if let Some(project) = self.project.clone() {
21215            self.load_diff_task = Some(
21216                update_uncommitted_diff_for_buffer(
21217                    cx.entity(),
21218                    &project,
21219                    self.buffer.read(cx).all_buffers(),
21220                    self.buffer.clone(),
21221                    cx,
21222                )
21223                .shared(),
21224            );
21225        }
21226    }
21227
21228    fn on_display_map_changed(
21229        &mut self,
21230        _: Entity<DisplayMap>,
21231        _: &mut Window,
21232        cx: &mut Context<Self>,
21233    ) {
21234        cx.notify();
21235    }
21236
21237    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21238        if self.diagnostics_enabled() {
21239            let new_severity = EditorSettings::get_global(cx)
21240                .diagnostics_max_severity
21241                .unwrap_or(DiagnosticSeverity::Hint);
21242            self.set_max_diagnostics_severity(new_severity, cx);
21243        }
21244        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21245        self.update_edit_prediction_settings(cx);
21246        self.refresh_edit_prediction(true, false, window, cx);
21247        self.refresh_inline_values(cx);
21248        self.refresh_inlay_hints(
21249            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21250                self.selections.newest_anchor().head(),
21251                &self.buffer.read(cx).snapshot(cx),
21252                cx,
21253            )),
21254            cx,
21255        );
21256
21257        let old_cursor_shape = self.cursor_shape;
21258        let old_show_breadcrumbs = self.show_breadcrumbs;
21259
21260        {
21261            let editor_settings = EditorSettings::get_global(cx);
21262            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21263            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21264            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21265            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21266        }
21267
21268        if old_cursor_shape != self.cursor_shape {
21269            cx.emit(EditorEvent::CursorShapeChanged);
21270        }
21271
21272        if old_show_breadcrumbs != self.show_breadcrumbs {
21273            cx.emit(EditorEvent::BreadcrumbsChanged);
21274        }
21275
21276        let project_settings = ProjectSettings::get_global(cx);
21277        self.buffer_serialization = self
21278            .should_serialize_buffer()
21279            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
21280
21281        if self.mode.is_full() {
21282            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21283            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21284            if self.show_inline_diagnostics != show_inline_diagnostics {
21285                self.show_inline_diagnostics = show_inline_diagnostics;
21286                self.refresh_inline_diagnostics(false, window, cx);
21287            }
21288
21289            if self.git_blame_inline_enabled != inline_blame_enabled {
21290                self.toggle_git_blame_inline_internal(false, window, cx);
21291            }
21292
21293            let minimap_settings = EditorSettings::get_global(cx).minimap;
21294            if self.minimap_visibility != MinimapVisibility::Disabled {
21295                if self.minimap_visibility.settings_visibility()
21296                    != minimap_settings.minimap_enabled()
21297                {
21298                    self.set_minimap_visibility(
21299                        MinimapVisibility::for_mode(self.mode(), cx),
21300                        window,
21301                        cx,
21302                    );
21303                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21304                    minimap_entity.update(cx, |minimap_editor, cx| {
21305                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21306                    })
21307                }
21308            }
21309        }
21310
21311        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21312            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21313        }) {
21314            if !inlay_splice.is_empty() {
21315                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21316            }
21317            self.refresh_colors_for_visible_range(None, window, cx);
21318        }
21319
21320        cx.notify();
21321    }
21322
21323    pub fn set_searchable(&mut self, searchable: bool) {
21324        self.searchable = searchable;
21325    }
21326
21327    pub fn searchable(&self) -> bool {
21328        self.searchable
21329    }
21330
21331    pub fn open_excerpts_in_split(
21332        &mut self,
21333        _: &OpenExcerptsSplit,
21334        window: &mut Window,
21335        cx: &mut Context<Self>,
21336    ) {
21337        self.open_excerpts_common(None, true, window, cx)
21338    }
21339
21340    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21341        self.open_excerpts_common(None, false, window, cx)
21342    }
21343
21344    fn open_excerpts_common(
21345        &mut self,
21346        jump_data: Option<JumpData>,
21347        split: bool,
21348        window: &mut Window,
21349        cx: &mut Context<Self>,
21350    ) {
21351        let Some(workspace) = self.workspace() else {
21352            cx.propagate();
21353            return;
21354        };
21355
21356        if self.buffer.read(cx).is_singleton() {
21357            cx.propagate();
21358            return;
21359        }
21360
21361        let mut new_selections_by_buffer = HashMap::default();
21362        match &jump_data {
21363            Some(JumpData::MultiBufferPoint {
21364                excerpt_id,
21365                position,
21366                anchor,
21367                line_offset_from_top,
21368            }) => {
21369                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21370                if let Some(buffer) = multi_buffer_snapshot
21371                    .buffer_id_for_excerpt(*excerpt_id)
21372                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21373                {
21374                    let buffer_snapshot = buffer.read(cx).snapshot();
21375                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21376                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21377                    } else {
21378                        buffer_snapshot.clip_point(*position, Bias::Left)
21379                    };
21380                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21381                    new_selections_by_buffer.insert(
21382                        buffer,
21383                        (
21384                            vec![jump_to_offset..jump_to_offset],
21385                            Some(*line_offset_from_top),
21386                        ),
21387                    );
21388                }
21389            }
21390            Some(JumpData::MultiBufferRow {
21391                row,
21392                line_offset_from_top,
21393            }) => {
21394                let point = MultiBufferPoint::new(row.0, 0);
21395                if let Some((buffer, buffer_point, _)) =
21396                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21397                {
21398                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21399                    new_selections_by_buffer
21400                        .entry(buffer)
21401                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21402                        .0
21403                        .push(buffer_offset..buffer_offset)
21404                }
21405            }
21406            None => {
21407                let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
21408                let multi_buffer = self.buffer.read(cx);
21409                for selection in selections {
21410                    for (snapshot, range, _, anchor) in multi_buffer
21411                        .snapshot(cx)
21412                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21413                    {
21414                        if let Some(anchor) = anchor {
21415                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21416                            else {
21417                                continue;
21418                            };
21419                            let offset = text::ToOffset::to_offset(
21420                                &anchor.text_anchor,
21421                                &buffer_handle.read(cx).snapshot(),
21422                            );
21423                            let range = offset..offset;
21424                            new_selections_by_buffer
21425                                .entry(buffer_handle)
21426                                .or_insert((Vec::new(), None))
21427                                .0
21428                                .push(range)
21429                        } else {
21430                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21431                            else {
21432                                continue;
21433                            };
21434                            new_selections_by_buffer
21435                                .entry(buffer_handle)
21436                                .or_insert((Vec::new(), None))
21437                                .0
21438                                .push(range)
21439                        }
21440                    }
21441                }
21442            }
21443        }
21444
21445        new_selections_by_buffer
21446            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21447
21448        if new_selections_by_buffer.is_empty() {
21449            return;
21450        }
21451
21452        // We defer the pane interaction because we ourselves are a workspace item
21453        // and activating a new item causes the pane to call a method on us reentrantly,
21454        // which panics if we're on the stack.
21455        window.defer(cx, move |window, cx| {
21456            workspace.update(cx, |workspace, cx| {
21457                let pane = if split {
21458                    workspace.adjacent_pane(window, cx)
21459                } else {
21460                    workspace.active_pane().clone()
21461                };
21462
21463                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21464                    let editor = buffer
21465                        .read(cx)
21466                        .file()
21467                        .is_none()
21468                        .then(|| {
21469                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21470                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21471                            // Instead, we try to activate the existing editor in the pane first.
21472                            let (editor, pane_item_index) =
21473                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21474                                    let editor = item.downcast::<Editor>()?;
21475                                    let singleton_buffer =
21476                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21477                                    if singleton_buffer == buffer {
21478                                        Some((editor, i))
21479                                    } else {
21480                                        None
21481                                    }
21482                                })?;
21483                            pane.update(cx, |pane, cx| {
21484                                pane.activate_item(pane_item_index, true, true, window, cx)
21485                            });
21486                            Some(editor)
21487                        })
21488                        .flatten()
21489                        .unwrap_or_else(|| {
21490                            workspace.open_project_item::<Self>(
21491                                pane.clone(),
21492                                buffer,
21493                                true,
21494                                true,
21495                                window,
21496                                cx,
21497                            )
21498                        });
21499
21500                    editor.update(cx, |editor, cx| {
21501                        let autoscroll = match scroll_offset {
21502                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21503                            None => Autoscroll::newest(),
21504                        };
21505                        let nav_history = editor.nav_history.take();
21506                        editor.change_selections(
21507                            SelectionEffects::scroll(autoscroll),
21508                            window,
21509                            cx,
21510                            |s| {
21511                                s.select_ranges(ranges);
21512                            },
21513                        );
21514                        editor.nav_history = nav_history;
21515                    });
21516                }
21517            })
21518        });
21519    }
21520
21521    // For now, don't allow opening excerpts in buffers that aren't backed by
21522    // regular project files.
21523    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21524        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21525    }
21526
21527    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21528        let snapshot = self.buffer.read(cx).read(cx);
21529        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21530        Some(
21531            ranges
21532                .iter()
21533                .map(move |range| {
21534                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21535                })
21536                .collect(),
21537        )
21538    }
21539
21540    fn selection_replacement_ranges(
21541        &self,
21542        range: Range<OffsetUtf16>,
21543        cx: &mut App,
21544    ) -> Vec<Range<OffsetUtf16>> {
21545        let selections = self
21546            .selections
21547            .all::<OffsetUtf16>(&self.display_snapshot(cx));
21548        let newest_selection = selections
21549            .iter()
21550            .max_by_key(|selection| selection.id)
21551            .unwrap();
21552        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21553        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21554        let snapshot = self.buffer.read(cx).read(cx);
21555        selections
21556            .into_iter()
21557            .map(|mut selection| {
21558                selection.start.0 =
21559                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21560                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21561                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21562                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21563            })
21564            .collect()
21565    }
21566
21567    fn report_editor_event(
21568        &self,
21569        reported_event: ReportEditorEvent,
21570        file_extension: Option<String>,
21571        cx: &App,
21572    ) {
21573        if cfg!(any(test, feature = "test-support")) {
21574            return;
21575        }
21576
21577        let Some(project) = &self.project else { return };
21578
21579        // If None, we are in a file without an extension
21580        let file = self
21581            .buffer
21582            .read(cx)
21583            .as_singleton()
21584            .and_then(|b| b.read(cx).file());
21585        let file_extension = file_extension.or(file
21586            .as_ref()
21587            .and_then(|file| Path::new(file.file_name(cx)).extension())
21588            .and_then(|e| e.to_str())
21589            .map(|a| a.to_string()));
21590
21591        let vim_mode = vim_flavor(cx).is_some();
21592
21593        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21594        let copilot_enabled = edit_predictions_provider
21595            == language::language_settings::EditPredictionProvider::Copilot;
21596        let copilot_enabled_for_language = self
21597            .buffer
21598            .read(cx)
21599            .language_settings(cx)
21600            .show_edit_predictions;
21601
21602        let project = project.read(cx);
21603        let event_type = reported_event.event_type();
21604
21605        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21606            telemetry::event!(
21607                event_type,
21608                type = if auto_saved {"autosave"} else {"manual"},
21609                file_extension,
21610                vim_mode,
21611                copilot_enabled,
21612                copilot_enabled_for_language,
21613                edit_predictions_provider,
21614                is_via_ssh = project.is_via_remote_server(),
21615            );
21616        } else {
21617            telemetry::event!(
21618                event_type,
21619                file_extension,
21620                vim_mode,
21621                copilot_enabled,
21622                copilot_enabled_for_language,
21623                edit_predictions_provider,
21624                is_via_ssh = project.is_via_remote_server(),
21625            );
21626        };
21627    }
21628
21629    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21630    /// with each line being an array of {text, highlight} objects.
21631    fn copy_highlight_json(
21632        &mut self,
21633        _: &CopyHighlightJson,
21634        window: &mut Window,
21635        cx: &mut Context<Self>,
21636    ) {
21637        #[derive(Serialize)]
21638        struct Chunk<'a> {
21639            text: String,
21640            highlight: Option<&'a str>,
21641        }
21642
21643        let snapshot = self.buffer.read(cx).snapshot(cx);
21644        let range = self
21645            .selected_text_range(false, window, cx)
21646            .and_then(|selection| {
21647                if selection.range.is_empty() {
21648                    None
21649                } else {
21650                    Some(
21651                        snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.start))
21652                            ..snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.end)),
21653                    )
21654                }
21655            })
21656            .unwrap_or_else(|| 0..snapshot.len());
21657
21658        let chunks = snapshot.chunks(range, true);
21659        let mut lines = Vec::new();
21660        let mut line: VecDeque<Chunk> = VecDeque::new();
21661
21662        let Some(style) = self.style.as_ref() else {
21663            return;
21664        };
21665
21666        for chunk in chunks {
21667            let highlight = chunk
21668                .syntax_highlight_id
21669                .and_then(|id| id.name(&style.syntax));
21670            let mut chunk_lines = chunk.text.split('\n').peekable();
21671            while let Some(text) = chunk_lines.next() {
21672                let mut merged_with_last_token = false;
21673                if let Some(last_token) = line.back_mut()
21674                    && last_token.highlight == highlight
21675                {
21676                    last_token.text.push_str(text);
21677                    merged_with_last_token = true;
21678                }
21679
21680                if !merged_with_last_token {
21681                    line.push_back(Chunk {
21682                        text: text.into(),
21683                        highlight,
21684                    });
21685                }
21686
21687                if chunk_lines.peek().is_some() {
21688                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21689                        line.pop_front();
21690                    }
21691                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21692                        line.pop_back();
21693                    }
21694
21695                    lines.push(mem::take(&mut line));
21696                }
21697            }
21698        }
21699
21700        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21701            return;
21702        };
21703        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21704    }
21705
21706    pub fn open_context_menu(
21707        &mut self,
21708        _: &OpenContextMenu,
21709        window: &mut Window,
21710        cx: &mut Context<Self>,
21711    ) {
21712        self.request_autoscroll(Autoscroll::newest(), cx);
21713        let position = self
21714            .selections
21715            .newest_display(&self.display_snapshot(cx))
21716            .start;
21717        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21718    }
21719
21720    pub fn replay_insert_event(
21721        &mut self,
21722        text: &str,
21723        relative_utf16_range: Option<Range<isize>>,
21724        window: &mut Window,
21725        cx: &mut Context<Self>,
21726    ) {
21727        if !self.input_enabled {
21728            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21729            return;
21730        }
21731        if let Some(relative_utf16_range) = relative_utf16_range {
21732            let selections = self
21733                .selections
21734                .all::<OffsetUtf16>(&self.display_snapshot(cx));
21735            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21736                let new_ranges = selections.into_iter().map(|range| {
21737                    let start = OffsetUtf16(
21738                        range
21739                            .head()
21740                            .0
21741                            .saturating_add_signed(relative_utf16_range.start),
21742                    );
21743                    let end = OffsetUtf16(
21744                        range
21745                            .head()
21746                            .0
21747                            .saturating_add_signed(relative_utf16_range.end),
21748                    );
21749                    start..end
21750                });
21751                s.select_ranges(new_ranges);
21752            });
21753        }
21754
21755        self.handle_input(text, window, cx);
21756    }
21757
21758    pub fn is_focused(&self, window: &Window) -> bool {
21759        self.focus_handle.is_focused(window)
21760    }
21761
21762    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21763        cx.emit(EditorEvent::Focused);
21764
21765        if let Some(descendant) = self
21766            .last_focused_descendant
21767            .take()
21768            .and_then(|descendant| descendant.upgrade())
21769        {
21770            window.focus(&descendant);
21771        } else {
21772            if let Some(blame) = self.blame.as_ref() {
21773                blame.update(cx, GitBlame::focus)
21774            }
21775
21776            self.blink_manager.update(cx, BlinkManager::enable);
21777            self.show_cursor_names(window, cx);
21778            self.buffer.update(cx, |buffer, cx| {
21779                buffer.finalize_last_transaction(cx);
21780                if self.leader_id.is_none() {
21781                    buffer.set_active_selections(
21782                        &self.selections.disjoint_anchors_arc(),
21783                        self.selections.line_mode(),
21784                        self.cursor_shape,
21785                        cx,
21786                    );
21787                }
21788            });
21789        }
21790    }
21791
21792    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21793        cx.emit(EditorEvent::FocusedIn)
21794    }
21795
21796    fn handle_focus_out(
21797        &mut self,
21798        event: FocusOutEvent,
21799        _window: &mut Window,
21800        cx: &mut Context<Self>,
21801    ) {
21802        if event.blurred != self.focus_handle {
21803            self.last_focused_descendant = Some(event.blurred);
21804        }
21805        self.selection_drag_state = SelectionDragState::None;
21806        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21807    }
21808
21809    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21810        self.blink_manager.update(cx, BlinkManager::disable);
21811        self.buffer
21812            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21813
21814        if let Some(blame) = self.blame.as_ref() {
21815            blame.update(cx, GitBlame::blur)
21816        }
21817        if !self.hover_state.focused(window, cx) {
21818            hide_hover(self, cx);
21819        }
21820        if !self
21821            .context_menu
21822            .borrow()
21823            .as_ref()
21824            .is_some_and(|context_menu| context_menu.focused(window, cx))
21825        {
21826            self.hide_context_menu(window, cx);
21827        }
21828        self.take_active_edit_prediction(cx);
21829        cx.emit(EditorEvent::Blurred);
21830        cx.notify();
21831    }
21832
21833    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21834        let mut pending: String = window
21835            .pending_input_keystrokes()
21836            .into_iter()
21837            .flatten()
21838            .filter_map(|keystroke| {
21839                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21840                    keystroke.key_char.clone()
21841                } else {
21842                    None
21843                }
21844            })
21845            .collect();
21846
21847        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21848            pending = "".to_string();
21849        }
21850
21851        let existing_pending = self
21852            .text_highlights::<PendingInput>(cx)
21853            .map(|(_, ranges)| ranges.to_vec());
21854        if existing_pending.is_none() && pending.is_empty() {
21855            return;
21856        }
21857        let transaction =
21858            self.transact(window, cx, |this, window, cx| {
21859                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
21860                let edits = selections
21861                    .iter()
21862                    .map(|selection| (selection.end..selection.end, pending.clone()));
21863                this.edit(edits, cx);
21864                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21865                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21866                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21867                    }));
21868                });
21869                if let Some(existing_ranges) = existing_pending {
21870                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21871                    this.edit(edits, cx);
21872                }
21873            });
21874
21875        let snapshot = self.snapshot(window, cx);
21876        let ranges = self
21877            .selections
21878            .all::<usize>(&snapshot.display_snapshot)
21879            .into_iter()
21880            .map(|selection| {
21881                snapshot.buffer_snapshot().anchor_after(selection.end)
21882                    ..snapshot
21883                        .buffer_snapshot()
21884                        .anchor_before(selection.end + pending.len())
21885            })
21886            .collect();
21887
21888        if pending.is_empty() {
21889            self.clear_highlights::<PendingInput>(cx);
21890        } else {
21891            self.highlight_text::<PendingInput>(
21892                ranges,
21893                HighlightStyle {
21894                    underline: Some(UnderlineStyle {
21895                        thickness: px(1.),
21896                        color: None,
21897                        wavy: false,
21898                    }),
21899                    ..Default::default()
21900                },
21901                cx,
21902            );
21903        }
21904
21905        self.ime_transaction = self.ime_transaction.or(transaction);
21906        if let Some(transaction) = self.ime_transaction {
21907            self.buffer.update(cx, |buffer, cx| {
21908                buffer.group_until_transaction(transaction, cx);
21909            });
21910        }
21911
21912        if self.text_highlights::<PendingInput>(cx).is_none() {
21913            self.ime_transaction.take();
21914        }
21915    }
21916
21917    pub fn register_action_renderer(
21918        &mut self,
21919        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21920    ) -> Subscription {
21921        let id = self.next_editor_action_id.post_inc();
21922        self.editor_actions
21923            .borrow_mut()
21924            .insert(id, Box::new(listener));
21925
21926        let editor_actions = self.editor_actions.clone();
21927        Subscription::new(move || {
21928            editor_actions.borrow_mut().remove(&id);
21929        })
21930    }
21931
21932    pub fn register_action<A: Action>(
21933        &mut self,
21934        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21935    ) -> Subscription {
21936        let id = self.next_editor_action_id.post_inc();
21937        let listener = Arc::new(listener);
21938        self.editor_actions.borrow_mut().insert(
21939            id,
21940            Box::new(move |_, window, _| {
21941                let listener = listener.clone();
21942                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21943                    let action = action.downcast_ref().unwrap();
21944                    if phase == DispatchPhase::Bubble {
21945                        listener(action, window, cx)
21946                    }
21947                })
21948            }),
21949        );
21950
21951        let editor_actions = self.editor_actions.clone();
21952        Subscription::new(move || {
21953            editor_actions.borrow_mut().remove(&id);
21954        })
21955    }
21956
21957    pub fn file_header_size(&self) -> u32 {
21958        FILE_HEADER_HEIGHT
21959    }
21960
21961    pub fn restore(
21962        &mut self,
21963        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21964        window: &mut Window,
21965        cx: &mut Context<Self>,
21966    ) {
21967        let workspace = self.workspace();
21968        let project = self.project();
21969        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21970            let mut tasks = Vec::new();
21971            for (buffer_id, changes) in revert_changes {
21972                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21973                    buffer.update(cx, |buffer, cx| {
21974                        buffer.edit(
21975                            changes
21976                                .into_iter()
21977                                .map(|(range, text)| (range, text.to_string())),
21978                            None,
21979                            cx,
21980                        );
21981                    });
21982
21983                    if let Some(project) =
21984                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21985                    {
21986                        project.update(cx, |project, cx| {
21987                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21988                        })
21989                    }
21990                }
21991            }
21992            tasks
21993        });
21994        cx.spawn_in(window, async move |_, cx| {
21995            for (buffer, task) in save_tasks {
21996                let result = task.await;
21997                if result.is_err() {
21998                    let Some(path) = buffer
21999                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
22000                        .ok()
22001                    else {
22002                        continue;
22003                    };
22004                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
22005                        let Some(task) = cx
22006                            .update_window_entity(workspace, |workspace, window, cx| {
22007                                workspace
22008                                    .open_path_preview(path, None, false, false, false, window, cx)
22009                            })
22010                            .ok()
22011                        else {
22012                            continue;
22013                        };
22014                        task.await.log_err();
22015                    }
22016                }
22017            }
22018        })
22019        .detach();
22020        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
22021            selections.refresh()
22022        });
22023    }
22024
22025    pub fn to_pixel_point(
22026        &self,
22027        source: multi_buffer::Anchor,
22028        editor_snapshot: &EditorSnapshot,
22029        window: &mut Window,
22030    ) -> Option<gpui::Point<Pixels>> {
22031        let source_point = source.to_display_point(editor_snapshot);
22032        self.display_to_pixel_point(source_point, editor_snapshot, window)
22033    }
22034
22035    pub fn display_to_pixel_point(
22036        &self,
22037        source: DisplayPoint,
22038        editor_snapshot: &EditorSnapshot,
22039        window: &mut Window,
22040    ) -> Option<gpui::Point<Pixels>> {
22041        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
22042        let text_layout_details = self.text_layout_details(window);
22043        let scroll_top = text_layout_details
22044            .scroll_anchor
22045            .scroll_position(editor_snapshot)
22046            .y;
22047
22048        if source.row().as_f64() < scroll_top.floor() {
22049            return None;
22050        }
22051        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
22052        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
22053        Some(gpui::Point::new(source_x, source_y))
22054    }
22055
22056    pub fn has_visible_completions_menu(&self) -> bool {
22057        !self.edit_prediction_preview_is_active()
22058            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
22059                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
22060            })
22061    }
22062
22063    pub fn register_addon<T: Addon>(&mut self, instance: T) {
22064        if self.mode.is_minimap() {
22065            return;
22066        }
22067        self.addons
22068            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
22069    }
22070
22071    pub fn unregister_addon<T: Addon>(&mut self) {
22072        self.addons.remove(&std::any::TypeId::of::<T>());
22073    }
22074
22075    pub fn addon<T: Addon>(&self) -> Option<&T> {
22076        let type_id = std::any::TypeId::of::<T>();
22077        self.addons
22078            .get(&type_id)
22079            .and_then(|item| item.to_any().downcast_ref::<T>())
22080    }
22081
22082    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
22083        let type_id = std::any::TypeId::of::<T>();
22084        self.addons
22085            .get_mut(&type_id)
22086            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
22087    }
22088
22089    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
22090        let text_layout_details = self.text_layout_details(window);
22091        let style = &text_layout_details.editor_style;
22092        let font_id = window.text_system().resolve_font(&style.text.font());
22093        let font_size = style.text.font_size.to_pixels(window.rem_size());
22094        let line_height = style.text.line_height_in_pixels(window.rem_size());
22095        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
22096        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
22097
22098        CharacterDimensions {
22099            em_width,
22100            em_advance,
22101            line_height,
22102        }
22103    }
22104
22105    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
22106        self.load_diff_task.clone()
22107    }
22108
22109    fn read_metadata_from_db(
22110        &mut self,
22111        item_id: u64,
22112        workspace_id: WorkspaceId,
22113        window: &mut Window,
22114        cx: &mut Context<Editor>,
22115    ) {
22116        if self.buffer_kind(cx) == ItemBufferKind::Singleton
22117            && !self.mode.is_minimap()
22118            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
22119        {
22120            let buffer_snapshot = OnceCell::new();
22121
22122            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
22123                && !folds.is_empty()
22124            {
22125                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22126                self.fold_ranges(
22127                    folds
22128                        .into_iter()
22129                        .map(|(start, end)| {
22130                            snapshot.clip_offset(start, Bias::Left)
22131                                ..snapshot.clip_offset(end, Bias::Right)
22132                        })
22133                        .collect(),
22134                    false,
22135                    window,
22136                    cx,
22137                );
22138            }
22139
22140            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
22141                && !selections.is_empty()
22142            {
22143                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22144                // skip adding the initial selection to selection history
22145                self.selection_history.mode = SelectionHistoryMode::Skipping;
22146                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22147                    s.select_ranges(selections.into_iter().map(|(start, end)| {
22148                        snapshot.clip_offset(start, Bias::Left)
22149                            ..snapshot.clip_offset(end, Bias::Right)
22150                    }));
22151                });
22152                self.selection_history.mode = SelectionHistoryMode::Normal;
22153            };
22154        }
22155
22156        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22157    }
22158
22159    fn update_lsp_data(
22160        &mut self,
22161        for_buffer: Option<BufferId>,
22162        window: &mut Window,
22163        cx: &mut Context<'_, Self>,
22164    ) {
22165        self.pull_diagnostics(for_buffer, window, cx);
22166        self.refresh_colors_for_visible_range(for_buffer, window, cx);
22167    }
22168
22169    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
22170        if self.ignore_lsp_data() {
22171            return;
22172        }
22173        for (_, (visible_buffer, _, _)) in self.visible_excerpts(cx) {
22174            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
22175        }
22176    }
22177
22178    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
22179        if self.ignore_lsp_data() {
22180            return;
22181        }
22182
22183        if !self.registered_buffers.contains_key(&buffer_id)
22184            && let Some(project) = self.project.as_ref()
22185        {
22186            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
22187                project.update(cx, |project, cx| {
22188                    self.registered_buffers.insert(
22189                        buffer_id,
22190                        project.register_buffer_with_language_servers(&buffer, cx),
22191                    );
22192                });
22193            } else {
22194                self.registered_buffers.remove(&buffer_id);
22195            }
22196        }
22197    }
22198
22199    fn ignore_lsp_data(&self) -> bool {
22200        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
22201        // skip any LSP updates for it.
22202        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
22203    }
22204}
22205
22206fn edit_for_markdown_paste<'a>(
22207    buffer: &MultiBufferSnapshot,
22208    range: Range<usize>,
22209    to_insert: &'a str,
22210    url: Option<url::Url>,
22211) -> (Range<usize>, Cow<'a, str>) {
22212    if url.is_none() {
22213        return (range, Cow::Borrowed(to_insert));
22214    };
22215
22216    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22217
22218    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22219        Cow::Borrowed(to_insert)
22220    } else {
22221        Cow::Owned(format!("[{old_text}]({to_insert})"))
22222    };
22223    (range, new_text)
22224}
22225
22226#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
22227pub enum VimFlavor {
22228    Vim,
22229    Helix,
22230}
22231
22232pub fn vim_flavor(cx: &App) -> Option<VimFlavor> {
22233    if vim_mode_setting::HelixModeSetting::try_get(cx)
22234        .map(|helix_mode| helix_mode.0)
22235        .unwrap_or(false)
22236    {
22237        Some(VimFlavor::Helix)
22238    } else if vim_mode_setting::VimModeSetting::try_get(cx)
22239        .map(|vim_mode| vim_mode.0)
22240        .unwrap_or(false)
22241    {
22242        Some(VimFlavor::Vim)
22243    } else {
22244        None // neither vim nor helix mode
22245    }
22246}
22247
22248fn process_completion_for_edit(
22249    completion: &Completion,
22250    intent: CompletionIntent,
22251    buffer: &Entity<Buffer>,
22252    cursor_position: &text::Anchor,
22253    cx: &mut Context<Editor>,
22254) -> CompletionEdit {
22255    let buffer = buffer.read(cx);
22256    let buffer_snapshot = buffer.snapshot();
22257    let (snippet, new_text) = if completion.is_snippet() {
22258        let mut snippet_source = completion.new_text.clone();
22259        // Workaround for typescript language server issues so that methods don't expand within
22260        // strings and functions with type expressions. The previous point is used because the query
22261        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22262        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22263        let previous_point = if previous_point.column > 0 {
22264            cursor_position.to_previous_offset(&buffer_snapshot)
22265        } else {
22266            cursor_position.to_offset(&buffer_snapshot)
22267        };
22268        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22269            && scope.prefers_label_for_snippet_in_completion()
22270            && let Some(label) = completion.label()
22271            && matches!(
22272                completion.kind(),
22273                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22274            )
22275        {
22276            snippet_source = label;
22277        }
22278        match Snippet::parse(&snippet_source).log_err() {
22279            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22280            None => (None, completion.new_text.clone()),
22281        }
22282    } else {
22283        (None, completion.new_text.clone())
22284    };
22285
22286    let mut range_to_replace = {
22287        let replace_range = &completion.replace_range;
22288        if let CompletionSource::Lsp {
22289            insert_range: Some(insert_range),
22290            ..
22291        } = &completion.source
22292        {
22293            debug_assert_eq!(
22294                insert_range.start, replace_range.start,
22295                "insert_range and replace_range should start at the same position"
22296            );
22297            debug_assert!(
22298                insert_range
22299                    .start
22300                    .cmp(cursor_position, &buffer_snapshot)
22301                    .is_le(),
22302                "insert_range should start before or at cursor position"
22303            );
22304            debug_assert!(
22305                replace_range
22306                    .start
22307                    .cmp(cursor_position, &buffer_snapshot)
22308                    .is_le(),
22309                "replace_range should start before or at cursor position"
22310            );
22311
22312            let should_replace = match intent {
22313                CompletionIntent::CompleteWithInsert => false,
22314                CompletionIntent::CompleteWithReplace => true,
22315                CompletionIntent::Complete | CompletionIntent::Compose => {
22316                    let insert_mode =
22317                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22318                            .completions
22319                            .lsp_insert_mode;
22320                    match insert_mode {
22321                        LspInsertMode::Insert => false,
22322                        LspInsertMode::Replace => true,
22323                        LspInsertMode::ReplaceSubsequence => {
22324                            let mut text_to_replace = buffer.chars_for_range(
22325                                buffer.anchor_before(replace_range.start)
22326                                    ..buffer.anchor_after(replace_range.end),
22327                            );
22328                            let mut current_needle = text_to_replace.next();
22329                            for haystack_ch in completion.label.text.chars() {
22330                                if let Some(needle_ch) = current_needle
22331                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22332                                {
22333                                    current_needle = text_to_replace.next();
22334                                }
22335                            }
22336                            current_needle.is_none()
22337                        }
22338                        LspInsertMode::ReplaceSuffix => {
22339                            if replace_range
22340                                .end
22341                                .cmp(cursor_position, &buffer_snapshot)
22342                                .is_gt()
22343                            {
22344                                let range_after_cursor = *cursor_position..replace_range.end;
22345                                let text_after_cursor = buffer
22346                                    .text_for_range(
22347                                        buffer.anchor_before(range_after_cursor.start)
22348                                            ..buffer.anchor_after(range_after_cursor.end),
22349                                    )
22350                                    .collect::<String>()
22351                                    .to_ascii_lowercase();
22352                                completion
22353                                    .label
22354                                    .text
22355                                    .to_ascii_lowercase()
22356                                    .ends_with(&text_after_cursor)
22357                            } else {
22358                                true
22359                            }
22360                        }
22361                    }
22362                }
22363            };
22364
22365            if should_replace {
22366                replace_range.clone()
22367            } else {
22368                insert_range.clone()
22369            }
22370        } else {
22371            replace_range.clone()
22372        }
22373    };
22374
22375    if range_to_replace
22376        .end
22377        .cmp(cursor_position, &buffer_snapshot)
22378        .is_lt()
22379    {
22380        range_to_replace.end = *cursor_position;
22381    }
22382
22383    CompletionEdit {
22384        new_text,
22385        replace_range: range_to_replace.to_offset(buffer),
22386        snippet,
22387    }
22388}
22389
22390struct CompletionEdit {
22391    new_text: String,
22392    replace_range: Range<usize>,
22393    snippet: Option<Snippet>,
22394}
22395
22396fn insert_extra_newline_brackets(
22397    buffer: &MultiBufferSnapshot,
22398    range: Range<usize>,
22399    language: &language::LanguageScope,
22400) -> bool {
22401    let leading_whitespace_len = buffer
22402        .reversed_chars_at(range.start)
22403        .take_while(|c| c.is_whitespace() && *c != '\n')
22404        .map(|c| c.len_utf8())
22405        .sum::<usize>();
22406    let trailing_whitespace_len = buffer
22407        .chars_at(range.end)
22408        .take_while(|c| c.is_whitespace() && *c != '\n')
22409        .map(|c| c.len_utf8())
22410        .sum::<usize>();
22411    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22412
22413    language.brackets().any(|(pair, enabled)| {
22414        let pair_start = pair.start.trim_end();
22415        let pair_end = pair.end.trim_start();
22416
22417        enabled
22418            && pair.newline
22419            && buffer.contains_str_at(range.end, pair_end)
22420            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22421    })
22422}
22423
22424fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22425    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22426        [(buffer, range, _)] => (*buffer, range.clone()),
22427        _ => return false,
22428    };
22429    let pair = {
22430        let mut result: Option<BracketMatch> = None;
22431
22432        for pair in buffer
22433            .all_bracket_ranges(range.clone())
22434            .filter(move |pair| {
22435                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22436            })
22437        {
22438            let len = pair.close_range.end - pair.open_range.start;
22439
22440            if let Some(existing) = &result {
22441                let existing_len = existing.close_range.end - existing.open_range.start;
22442                if len > existing_len {
22443                    continue;
22444                }
22445            }
22446
22447            result = Some(pair);
22448        }
22449
22450        result
22451    };
22452    let Some(pair) = pair else {
22453        return false;
22454    };
22455    pair.newline_only
22456        && buffer
22457            .chars_for_range(pair.open_range.end..range.start)
22458            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22459            .all(|c| c.is_whitespace() && c != '\n')
22460}
22461
22462fn update_uncommitted_diff_for_buffer(
22463    editor: Entity<Editor>,
22464    project: &Entity<Project>,
22465    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22466    buffer: Entity<MultiBuffer>,
22467    cx: &mut App,
22468) -> Task<()> {
22469    let mut tasks = Vec::new();
22470    project.update(cx, |project, cx| {
22471        for buffer in buffers {
22472            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22473                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22474            }
22475        }
22476    });
22477    cx.spawn(async move |cx| {
22478        let diffs = future::join_all(tasks).await;
22479        if editor
22480            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22481            .unwrap_or(false)
22482        {
22483            return;
22484        }
22485
22486        buffer
22487            .update(cx, |buffer, cx| {
22488                for diff in diffs.into_iter().flatten() {
22489                    buffer.add_diff(diff, cx);
22490                }
22491            })
22492            .ok();
22493    })
22494}
22495
22496fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22497    let tab_size = tab_size.get() as usize;
22498    let mut width = offset;
22499
22500    for ch in text.chars() {
22501        width += if ch == '\t' {
22502            tab_size - (width % tab_size)
22503        } else {
22504            1
22505        };
22506    }
22507
22508    width - offset
22509}
22510
22511#[cfg(test)]
22512mod tests {
22513    use super::*;
22514
22515    #[test]
22516    fn test_string_size_with_expanded_tabs() {
22517        let nz = |val| NonZeroU32::new(val).unwrap();
22518        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22519        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22520        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22521        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22522        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22523        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22524        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22525        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22526    }
22527}
22528
22529/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22530struct WordBreakingTokenizer<'a> {
22531    input: &'a str,
22532}
22533
22534impl<'a> WordBreakingTokenizer<'a> {
22535    fn new(input: &'a str) -> Self {
22536        Self { input }
22537    }
22538}
22539
22540fn is_char_ideographic(ch: char) -> bool {
22541    use unicode_script::Script::*;
22542    use unicode_script::UnicodeScript;
22543    matches!(ch.script(), Han | Tangut | Yi)
22544}
22545
22546fn is_grapheme_ideographic(text: &str) -> bool {
22547    text.chars().any(is_char_ideographic)
22548}
22549
22550fn is_grapheme_whitespace(text: &str) -> bool {
22551    text.chars().any(|x| x.is_whitespace())
22552}
22553
22554fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22555    text.chars()
22556        .next()
22557        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22558}
22559
22560#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22561enum WordBreakToken<'a> {
22562    Word { token: &'a str, grapheme_len: usize },
22563    InlineWhitespace { token: &'a str, grapheme_len: usize },
22564    Newline,
22565}
22566
22567impl<'a> Iterator for WordBreakingTokenizer<'a> {
22568    /// Yields a span, the count of graphemes in the token, and whether it was
22569    /// whitespace. Note that it also breaks at word boundaries.
22570    type Item = WordBreakToken<'a>;
22571
22572    fn next(&mut self) -> Option<Self::Item> {
22573        use unicode_segmentation::UnicodeSegmentation;
22574        if self.input.is_empty() {
22575            return None;
22576        }
22577
22578        let mut iter = self.input.graphemes(true).peekable();
22579        let mut offset = 0;
22580        let mut grapheme_len = 0;
22581        if let Some(first_grapheme) = iter.next() {
22582            let is_newline = first_grapheme == "\n";
22583            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22584            offset += first_grapheme.len();
22585            grapheme_len += 1;
22586            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22587                if let Some(grapheme) = iter.peek().copied()
22588                    && should_stay_with_preceding_ideograph(grapheme)
22589                {
22590                    offset += grapheme.len();
22591                    grapheme_len += 1;
22592                }
22593            } else {
22594                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22595                let mut next_word_bound = words.peek().copied();
22596                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22597                    next_word_bound = words.next();
22598                }
22599                while let Some(grapheme) = iter.peek().copied() {
22600                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22601                        break;
22602                    };
22603                    if is_grapheme_whitespace(grapheme) != is_whitespace
22604                        || (grapheme == "\n") != is_newline
22605                    {
22606                        break;
22607                    };
22608                    offset += grapheme.len();
22609                    grapheme_len += 1;
22610                    iter.next();
22611                }
22612            }
22613            let token = &self.input[..offset];
22614            self.input = &self.input[offset..];
22615            if token == "\n" {
22616                Some(WordBreakToken::Newline)
22617            } else if is_whitespace {
22618                Some(WordBreakToken::InlineWhitespace {
22619                    token,
22620                    grapheme_len,
22621                })
22622            } else {
22623                Some(WordBreakToken::Word {
22624                    token,
22625                    grapheme_len,
22626                })
22627            }
22628        } else {
22629            None
22630        }
22631    }
22632}
22633
22634#[test]
22635fn test_word_breaking_tokenizer() {
22636    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22637        ("", &[]),
22638        ("  ", &[whitespace("  ", 2)]),
22639        ("Ʒ", &[word("Ʒ", 1)]),
22640        ("Ǽ", &[word("Ǽ", 1)]),
22641        ("", &[word("", 1)]),
22642        ("⋑⋑", &[word("⋑⋑", 2)]),
22643        (
22644            "原理,进而",
22645            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22646        ),
22647        (
22648            "hello world",
22649            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22650        ),
22651        (
22652            "hello, world",
22653            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22654        ),
22655        (
22656            "  hello world",
22657            &[
22658                whitespace("  ", 2),
22659                word("hello", 5),
22660                whitespace(" ", 1),
22661                word("world", 5),
22662            ],
22663        ),
22664        (
22665            "这是什么 \n 钢笔",
22666            &[
22667                word("", 1),
22668                word("", 1),
22669                word("", 1),
22670                word("", 1),
22671                whitespace(" ", 1),
22672                newline(),
22673                whitespace(" ", 1),
22674                word("", 1),
22675                word("", 1),
22676            ],
22677        ),
22678        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22679    ];
22680
22681    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22682        WordBreakToken::Word {
22683            token,
22684            grapheme_len,
22685        }
22686    }
22687
22688    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22689        WordBreakToken::InlineWhitespace {
22690            token,
22691            grapheme_len,
22692        }
22693    }
22694
22695    fn newline() -> WordBreakToken<'static> {
22696        WordBreakToken::Newline
22697    }
22698
22699    for (input, result) in tests {
22700        assert_eq!(
22701            WordBreakingTokenizer::new(input)
22702                .collect::<Vec<_>>()
22703                .as_slice(),
22704            *result,
22705        );
22706    }
22707}
22708
22709fn wrap_with_prefix(
22710    first_line_prefix: String,
22711    subsequent_lines_prefix: String,
22712    unwrapped_text: String,
22713    wrap_column: usize,
22714    tab_size: NonZeroU32,
22715    preserve_existing_whitespace: bool,
22716) -> String {
22717    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22718    let subsequent_lines_prefix_len =
22719        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22720    let mut wrapped_text = String::new();
22721    let mut current_line = first_line_prefix;
22722    let mut is_first_line = true;
22723
22724    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22725    let mut current_line_len = first_line_prefix_len;
22726    let mut in_whitespace = false;
22727    for token in tokenizer {
22728        let have_preceding_whitespace = in_whitespace;
22729        match token {
22730            WordBreakToken::Word {
22731                token,
22732                grapheme_len,
22733            } => {
22734                in_whitespace = false;
22735                let current_prefix_len = if is_first_line {
22736                    first_line_prefix_len
22737                } else {
22738                    subsequent_lines_prefix_len
22739                };
22740                if current_line_len + grapheme_len > wrap_column
22741                    && current_line_len != current_prefix_len
22742                {
22743                    wrapped_text.push_str(current_line.trim_end());
22744                    wrapped_text.push('\n');
22745                    is_first_line = false;
22746                    current_line = subsequent_lines_prefix.clone();
22747                    current_line_len = subsequent_lines_prefix_len;
22748                }
22749                current_line.push_str(token);
22750                current_line_len += grapheme_len;
22751            }
22752            WordBreakToken::InlineWhitespace {
22753                mut token,
22754                mut grapheme_len,
22755            } => {
22756                in_whitespace = true;
22757                if have_preceding_whitespace && !preserve_existing_whitespace {
22758                    continue;
22759                }
22760                if !preserve_existing_whitespace {
22761                    // Keep a single whitespace grapheme as-is
22762                    if let Some(first) =
22763                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
22764                    {
22765                        token = first;
22766                    } else {
22767                        token = " ";
22768                    }
22769                    grapheme_len = 1;
22770                }
22771                let current_prefix_len = if is_first_line {
22772                    first_line_prefix_len
22773                } else {
22774                    subsequent_lines_prefix_len
22775                };
22776                if current_line_len + grapheme_len > wrap_column {
22777                    wrapped_text.push_str(current_line.trim_end());
22778                    wrapped_text.push('\n');
22779                    is_first_line = false;
22780                    current_line = subsequent_lines_prefix.clone();
22781                    current_line_len = subsequent_lines_prefix_len;
22782                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22783                    current_line.push_str(token);
22784                    current_line_len += grapheme_len;
22785                }
22786            }
22787            WordBreakToken::Newline => {
22788                in_whitespace = true;
22789                let current_prefix_len = if is_first_line {
22790                    first_line_prefix_len
22791                } else {
22792                    subsequent_lines_prefix_len
22793                };
22794                if preserve_existing_whitespace {
22795                    wrapped_text.push_str(current_line.trim_end());
22796                    wrapped_text.push('\n');
22797                    is_first_line = false;
22798                    current_line = subsequent_lines_prefix.clone();
22799                    current_line_len = subsequent_lines_prefix_len;
22800                } else if have_preceding_whitespace {
22801                    continue;
22802                } else if current_line_len + 1 > wrap_column
22803                    && current_line_len != current_prefix_len
22804                {
22805                    wrapped_text.push_str(current_line.trim_end());
22806                    wrapped_text.push('\n');
22807                    is_first_line = false;
22808                    current_line = subsequent_lines_prefix.clone();
22809                    current_line_len = subsequent_lines_prefix_len;
22810                } else if current_line_len != current_prefix_len {
22811                    current_line.push(' ');
22812                    current_line_len += 1;
22813                }
22814            }
22815        }
22816    }
22817
22818    if !current_line.is_empty() {
22819        wrapped_text.push_str(&current_line);
22820    }
22821    wrapped_text
22822}
22823
22824#[test]
22825fn test_wrap_with_prefix() {
22826    assert_eq!(
22827        wrap_with_prefix(
22828            "# ".to_string(),
22829            "# ".to_string(),
22830            "abcdefg".to_string(),
22831            4,
22832            NonZeroU32::new(4).unwrap(),
22833            false,
22834        ),
22835        "# abcdefg"
22836    );
22837    assert_eq!(
22838        wrap_with_prefix(
22839            "".to_string(),
22840            "".to_string(),
22841            "\thello world".to_string(),
22842            8,
22843            NonZeroU32::new(4).unwrap(),
22844            false,
22845        ),
22846        "hello\nworld"
22847    );
22848    assert_eq!(
22849        wrap_with_prefix(
22850            "// ".to_string(),
22851            "// ".to_string(),
22852            "xx \nyy zz aa bb cc".to_string(),
22853            12,
22854            NonZeroU32::new(4).unwrap(),
22855            false,
22856        ),
22857        "// xx yy zz\n// aa bb cc"
22858    );
22859    assert_eq!(
22860        wrap_with_prefix(
22861            String::new(),
22862            String::new(),
22863            "这是什么 \n 钢笔".to_string(),
22864            3,
22865            NonZeroU32::new(4).unwrap(),
22866            false,
22867        ),
22868        "这是什\n么 钢\n"
22869    );
22870    assert_eq!(
22871        wrap_with_prefix(
22872            String::new(),
22873            String::new(),
22874            format!("foo{}bar", '\u{2009}'), // thin space
22875            80,
22876            NonZeroU32::new(4).unwrap(),
22877            false,
22878        ),
22879        format!("foo{}bar", '\u{2009}')
22880    );
22881}
22882
22883pub trait CollaborationHub {
22884    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22885    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22886    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22887}
22888
22889impl CollaborationHub for Entity<Project> {
22890    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22891        self.read(cx).collaborators()
22892    }
22893
22894    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22895        self.read(cx).user_store().read(cx).participant_indices()
22896    }
22897
22898    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22899        let this = self.read(cx);
22900        let user_ids = this.collaborators().values().map(|c| c.user_id);
22901        this.user_store().read(cx).participant_names(user_ids, cx)
22902    }
22903}
22904
22905pub trait SemanticsProvider {
22906    fn hover(
22907        &self,
22908        buffer: &Entity<Buffer>,
22909        position: text::Anchor,
22910        cx: &mut App,
22911    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22912
22913    fn inline_values(
22914        &self,
22915        buffer_handle: Entity<Buffer>,
22916        range: Range<text::Anchor>,
22917        cx: &mut App,
22918    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22919
22920    fn applicable_inlay_chunks(
22921        &self,
22922        buffer: &Entity<Buffer>,
22923        ranges: &[Range<text::Anchor>],
22924        cx: &mut App,
22925    ) -> Vec<Range<BufferRow>>;
22926
22927    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
22928
22929    fn inlay_hints(
22930        &self,
22931        invalidate: InvalidationStrategy,
22932        buffer: Entity<Buffer>,
22933        ranges: Vec<Range<text::Anchor>>,
22934        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
22935        cx: &mut App,
22936    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
22937
22938    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22939
22940    fn document_highlights(
22941        &self,
22942        buffer: &Entity<Buffer>,
22943        position: text::Anchor,
22944        cx: &mut App,
22945    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22946
22947    fn definitions(
22948        &self,
22949        buffer: &Entity<Buffer>,
22950        position: text::Anchor,
22951        kind: GotoDefinitionKind,
22952        cx: &mut App,
22953    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22954
22955    fn range_for_rename(
22956        &self,
22957        buffer: &Entity<Buffer>,
22958        position: text::Anchor,
22959        cx: &mut App,
22960    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22961
22962    fn perform_rename(
22963        &self,
22964        buffer: &Entity<Buffer>,
22965        position: text::Anchor,
22966        new_name: String,
22967        cx: &mut App,
22968    ) -> Option<Task<Result<ProjectTransaction>>>;
22969}
22970
22971pub trait CompletionProvider {
22972    fn completions(
22973        &self,
22974        excerpt_id: ExcerptId,
22975        buffer: &Entity<Buffer>,
22976        buffer_position: text::Anchor,
22977        trigger: CompletionContext,
22978        window: &mut Window,
22979        cx: &mut Context<Editor>,
22980    ) -> Task<Result<Vec<CompletionResponse>>>;
22981
22982    fn resolve_completions(
22983        &self,
22984        _buffer: Entity<Buffer>,
22985        _completion_indices: Vec<usize>,
22986        _completions: Rc<RefCell<Box<[Completion]>>>,
22987        _cx: &mut Context<Editor>,
22988    ) -> Task<Result<bool>> {
22989        Task::ready(Ok(false))
22990    }
22991
22992    fn apply_additional_edits_for_completion(
22993        &self,
22994        _buffer: Entity<Buffer>,
22995        _completions: Rc<RefCell<Box<[Completion]>>>,
22996        _completion_index: usize,
22997        _push_to_history: bool,
22998        _cx: &mut Context<Editor>,
22999    ) -> Task<Result<Option<language::Transaction>>> {
23000        Task::ready(Ok(None))
23001    }
23002
23003    fn is_completion_trigger(
23004        &self,
23005        buffer: &Entity<Buffer>,
23006        position: language::Anchor,
23007        text: &str,
23008        trigger_in_words: bool,
23009        menu_is_open: bool,
23010        cx: &mut Context<Editor>,
23011    ) -> bool;
23012
23013    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
23014
23015    fn sort_completions(&self) -> bool {
23016        true
23017    }
23018
23019    fn filter_completions(&self) -> bool {
23020        true
23021    }
23022}
23023
23024pub trait CodeActionProvider {
23025    fn id(&self) -> Arc<str>;
23026
23027    fn code_actions(
23028        &self,
23029        buffer: &Entity<Buffer>,
23030        range: Range<text::Anchor>,
23031        window: &mut Window,
23032        cx: &mut App,
23033    ) -> Task<Result<Vec<CodeAction>>>;
23034
23035    fn apply_code_action(
23036        &self,
23037        buffer_handle: Entity<Buffer>,
23038        action: CodeAction,
23039        excerpt_id: ExcerptId,
23040        push_to_history: bool,
23041        window: &mut Window,
23042        cx: &mut App,
23043    ) -> Task<Result<ProjectTransaction>>;
23044}
23045
23046impl CodeActionProvider for Entity<Project> {
23047    fn id(&self) -> Arc<str> {
23048        "project".into()
23049    }
23050
23051    fn code_actions(
23052        &self,
23053        buffer: &Entity<Buffer>,
23054        range: Range<text::Anchor>,
23055        _window: &mut Window,
23056        cx: &mut App,
23057    ) -> Task<Result<Vec<CodeAction>>> {
23058        self.update(cx, |project, cx| {
23059            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
23060            let code_actions = project.code_actions(buffer, range, None, cx);
23061            cx.background_spawn(async move {
23062                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
23063                Ok(code_lens_actions
23064                    .context("code lens fetch")?
23065                    .into_iter()
23066                    .flatten()
23067                    .chain(
23068                        code_actions
23069                            .context("code action fetch")?
23070                            .into_iter()
23071                            .flatten(),
23072                    )
23073                    .collect())
23074            })
23075        })
23076    }
23077
23078    fn apply_code_action(
23079        &self,
23080        buffer_handle: Entity<Buffer>,
23081        action: CodeAction,
23082        _excerpt_id: ExcerptId,
23083        push_to_history: bool,
23084        _window: &mut Window,
23085        cx: &mut App,
23086    ) -> Task<Result<ProjectTransaction>> {
23087        self.update(cx, |project, cx| {
23088            project.apply_code_action(buffer_handle, action, push_to_history, cx)
23089        })
23090    }
23091}
23092
23093fn snippet_completions(
23094    project: &Project,
23095    buffer: &Entity<Buffer>,
23096    buffer_position: text::Anchor,
23097    cx: &mut App,
23098) -> Task<Result<CompletionResponse>> {
23099    let languages = buffer.read(cx).languages_at(buffer_position);
23100    let snippet_store = project.snippets().read(cx);
23101
23102    let scopes: Vec<_> = languages
23103        .iter()
23104        .filter_map(|language| {
23105            let language_name = language.lsp_id();
23106            let snippets = snippet_store.snippets_for(Some(language_name), cx);
23107
23108            if snippets.is_empty() {
23109                None
23110            } else {
23111                Some((language.default_scope(), snippets))
23112            }
23113        })
23114        .collect();
23115
23116    if scopes.is_empty() {
23117        return Task::ready(Ok(CompletionResponse {
23118            completions: vec![],
23119            display_options: CompletionDisplayOptions::default(),
23120            is_incomplete: false,
23121        }));
23122    }
23123
23124    let snapshot = buffer.read(cx).text_snapshot();
23125    let executor = cx.background_executor().clone();
23126
23127    cx.background_spawn(async move {
23128        let mut is_incomplete = false;
23129        let mut completions: Vec<Completion> = Vec::new();
23130        for (scope, snippets) in scopes.into_iter() {
23131            let classifier =
23132                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
23133
23134            const MAX_WORD_PREFIX_LEN: usize = 128;
23135            let last_word: String = snapshot
23136                .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
23137                .take(MAX_WORD_PREFIX_LEN)
23138                .take_while(|c| classifier.is_word(*c))
23139                .collect::<String>()
23140                .chars()
23141                .rev()
23142                .collect();
23143
23144            if last_word.is_empty() {
23145                return Ok(CompletionResponse {
23146                    completions: vec![],
23147                    display_options: CompletionDisplayOptions::default(),
23148                    is_incomplete: true,
23149                });
23150            }
23151
23152            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
23153            let to_lsp = |point: &text::Anchor| {
23154                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
23155                point_to_lsp(end)
23156            };
23157            let lsp_end = to_lsp(&buffer_position);
23158
23159            let candidates = snippets
23160                .iter()
23161                .enumerate()
23162                .flat_map(|(ix, snippet)| {
23163                    snippet
23164                        .prefix
23165                        .iter()
23166                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
23167                })
23168                .collect::<Vec<StringMatchCandidate>>();
23169
23170            const MAX_RESULTS: usize = 100;
23171            let mut matches = fuzzy::match_strings(
23172                &candidates,
23173                &last_word,
23174                last_word.chars().any(|c| c.is_uppercase()),
23175                true,
23176                MAX_RESULTS,
23177                &Default::default(),
23178                executor.clone(),
23179            )
23180            .await;
23181
23182            if matches.len() >= MAX_RESULTS {
23183                is_incomplete = true;
23184            }
23185
23186            // Remove all candidates where the query's start does not match the start of any word in the candidate
23187            if let Some(query_start) = last_word.chars().next() {
23188                matches.retain(|string_match| {
23189                    split_words(&string_match.string).any(|word| {
23190                        // Check that the first codepoint of the word as lowercase matches the first
23191                        // codepoint of the query as lowercase
23192                        word.chars()
23193                            .flat_map(|codepoint| codepoint.to_lowercase())
23194                            .zip(query_start.to_lowercase())
23195                            .all(|(word_cp, query_cp)| word_cp == query_cp)
23196                    })
23197                });
23198            }
23199
23200            let matched_strings = matches
23201                .into_iter()
23202                .map(|m| m.string)
23203                .collect::<HashSet<_>>();
23204
23205            completions.extend(snippets.iter().filter_map(|snippet| {
23206                let matching_prefix = snippet
23207                    .prefix
23208                    .iter()
23209                    .find(|prefix| matched_strings.contains(*prefix))?;
23210                let start = as_offset - last_word.len();
23211                let start = snapshot.anchor_before(start);
23212                let range = start..buffer_position;
23213                let lsp_start = to_lsp(&start);
23214                let lsp_range = lsp::Range {
23215                    start: lsp_start,
23216                    end: lsp_end,
23217                };
23218                Some(Completion {
23219                    replace_range: range,
23220                    new_text: snippet.body.clone(),
23221                    source: CompletionSource::Lsp {
23222                        insert_range: None,
23223                        server_id: LanguageServerId(usize::MAX),
23224                        resolved: true,
23225                        lsp_completion: Box::new(lsp::CompletionItem {
23226                            label: snippet.prefix.first().unwrap().clone(),
23227                            kind: Some(CompletionItemKind::SNIPPET),
23228                            label_details: snippet.description.as_ref().map(|description| {
23229                                lsp::CompletionItemLabelDetails {
23230                                    detail: Some(description.clone()),
23231                                    description: None,
23232                                }
23233                            }),
23234                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23235                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23236                                lsp::InsertReplaceEdit {
23237                                    new_text: snippet.body.clone(),
23238                                    insert: lsp_range,
23239                                    replace: lsp_range,
23240                                },
23241                            )),
23242                            filter_text: Some(snippet.body.clone()),
23243                            sort_text: Some(char::MAX.to_string()),
23244                            ..lsp::CompletionItem::default()
23245                        }),
23246                        lsp_defaults: None,
23247                    },
23248                    label: CodeLabel::plain(matching_prefix.clone(), None),
23249                    icon_path: None,
23250                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23251                        single_line: snippet.name.clone().into(),
23252                        plain_text: snippet
23253                            .description
23254                            .clone()
23255                            .map(|description| description.into()),
23256                    }),
23257                    insert_text_mode: None,
23258                    confirm: None,
23259                })
23260            }))
23261        }
23262
23263        Ok(CompletionResponse {
23264            completions,
23265            display_options: CompletionDisplayOptions::default(),
23266            is_incomplete,
23267        })
23268    })
23269}
23270
23271impl CompletionProvider for Entity<Project> {
23272    fn completions(
23273        &self,
23274        _excerpt_id: ExcerptId,
23275        buffer: &Entity<Buffer>,
23276        buffer_position: text::Anchor,
23277        options: CompletionContext,
23278        _window: &mut Window,
23279        cx: &mut Context<Editor>,
23280    ) -> Task<Result<Vec<CompletionResponse>>> {
23281        self.update(cx, |project, cx| {
23282            let snippets = snippet_completions(project, buffer, buffer_position, cx);
23283            let project_completions = project.completions(buffer, buffer_position, options, cx);
23284            cx.background_spawn(async move {
23285                let mut responses = project_completions.await?;
23286                let snippets = snippets.await?;
23287                if !snippets.completions.is_empty() {
23288                    responses.push(snippets);
23289                }
23290                Ok(responses)
23291            })
23292        })
23293    }
23294
23295    fn resolve_completions(
23296        &self,
23297        buffer: Entity<Buffer>,
23298        completion_indices: Vec<usize>,
23299        completions: Rc<RefCell<Box<[Completion]>>>,
23300        cx: &mut Context<Editor>,
23301    ) -> Task<Result<bool>> {
23302        self.update(cx, |project, cx| {
23303            project.lsp_store().update(cx, |lsp_store, cx| {
23304                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23305            })
23306        })
23307    }
23308
23309    fn apply_additional_edits_for_completion(
23310        &self,
23311        buffer: Entity<Buffer>,
23312        completions: Rc<RefCell<Box<[Completion]>>>,
23313        completion_index: usize,
23314        push_to_history: bool,
23315        cx: &mut Context<Editor>,
23316    ) -> Task<Result<Option<language::Transaction>>> {
23317        self.update(cx, |project, cx| {
23318            project.lsp_store().update(cx, |lsp_store, cx| {
23319                lsp_store.apply_additional_edits_for_completion(
23320                    buffer,
23321                    completions,
23322                    completion_index,
23323                    push_to_history,
23324                    cx,
23325                )
23326            })
23327        })
23328    }
23329
23330    fn is_completion_trigger(
23331        &self,
23332        buffer: &Entity<Buffer>,
23333        position: language::Anchor,
23334        text: &str,
23335        trigger_in_words: bool,
23336        menu_is_open: bool,
23337        cx: &mut Context<Editor>,
23338    ) -> bool {
23339        let mut chars = text.chars();
23340        let char = if let Some(char) = chars.next() {
23341            char
23342        } else {
23343            return false;
23344        };
23345        if chars.next().is_some() {
23346            return false;
23347        }
23348
23349        let buffer = buffer.read(cx);
23350        let snapshot = buffer.snapshot();
23351        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23352            return false;
23353        }
23354        let classifier = snapshot
23355            .char_classifier_at(position)
23356            .scope_context(Some(CharScopeContext::Completion));
23357        if trigger_in_words && classifier.is_word(char) {
23358            return true;
23359        }
23360
23361        buffer.completion_triggers().contains(text)
23362    }
23363}
23364
23365impl SemanticsProvider for Entity<Project> {
23366    fn hover(
23367        &self,
23368        buffer: &Entity<Buffer>,
23369        position: text::Anchor,
23370        cx: &mut App,
23371    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23372        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23373    }
23374
23375    fn document_highlights(
23376        &self,
23377        buffer: &Entity<Buffer>,
23378        position: text::Anchor,
23379        cx: &mut App,
23380    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23381        Some(self.update(cx, |project, cx| {
23382            project.document_highlights(buffer, position, cx)
23383        }))
23384    }
23385
23386    fn definitions(
23387        &self,
23388        buffer: &Entity<Buffer>,
23389        position: text::Anchor,
23390        kind: GotoDefinitionKind,
23391        cx: &mut App,
23392    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23393        Some(self.update(cx, |project, cx| match kind {
23394            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23395            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23396            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23397            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23398        }))
23399    }
23400
23401    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23402        self.update(cx, |project, cx| {
23403            if project
23404                .active_debug_session(cx)
23405                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23406            {
23407                return true;
23408            }
23409
23410            buffer.update(cx, |buffer, cx| {
23411                project.any_language_server_supports_inlay_hints(buffer, cx)
23412            })
23413        })
23414    }
23415
23416    fn inline_values(
23417        &self,
23418        buffer_handle: Entity<Buffer>,
23419        range: Range<text::Anchor>,
23420        cx: &mut App,
23421    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23422        self.update(cx, |project, cx| {
23423            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23424
23425            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23426        })
23427    }
23428
23429    fn applicable_inlay_chunks(
23430        &self,
23431        buffer: &Entity<Buffer>,
23432        ranges: &[Range<text::Anchor>],
23433        cx: &mut App,
23434    ) -> Vec<Range<BufferRow>> {
23435        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23436            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
23437        })
23438    }
23439
23440    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
23441        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
23442            lsp_store.invalidate_inlay_hints(for_buffers)
23443        });
23444    }
23445
23446    fn inlay_hints(
23447        &self,
23448        invalidate: InvalidationStrategy,
23449        buffer: Entity<Buffer>,
23450        ranges: Vec<Range<text::Anchor>>,
23451        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23452        cx: &mut App,
23453    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
23454        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23455            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
23456        }))
23457    }
23458
23459    fn range_for_rename(
23460        &self,
23461        buffer: &Entity<Buffer>,
23462        position: text::Anchor,
23463        cx: &mut App,
23464    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23465        Some(self.update(cx, |project, cx| {
23466            let buffer = buffer.clone();
23467            let task = project.prepare_rename(buffer.clone(), position, cx);
23468            cx.spawn(async move |_, cx| {
23469                Ok(match task.await? {
23470                    PrepareRenameResponse::Success(range) => Some(range),
23471                    PrepareRenameResponse::InvalidPosition => None,
23472                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23473                        // Fallback on using TreeSitter info to determine identifier range
23474                        buffer.read_with(cx, |buffer, _| {
23475                            let snapshot = buffer.snapshot();
23476                            let (range, kind) = snapshot.surrounding_word(position, None);
23477                            if kind != Some(CharKind::Word) {
23478                                return None;
23479                            }
23480                            Some(
23481                                snapshot.anchor_before(range.start)
23482                                    ..snapshot.anchor_after(range.end),
23483                            )
23484                        })?
23485                    }
23486                })
23487            })
23488        }))
23489    }
23490
23491    fn perform_rename(
23492        &self,
23493        buffer: &Entity<Buffer>,
23494        position: text::Anchor,
23495        new_name: String,
23496        cx: &mut App,
23497    ) -> Option<Task<Result<ProjectTransaction>>> {
23498        Some(self.update(cx, |project, cx| {
23499            project.perform_rename(buffer.clone(), position, new_name, cx)
23500        }))
23501    }
23502}
23503
23504fn consume_contiguous_rows(
23505    contiguous_row_selections: &mut Vec<Selection<Point>>,
23506    selection: &Selection<Point>,
23507    display_map: &DisplaySnapshot,
23508    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23509) -> (MultiBufferRow, MultiBufferRow) {
23510    contiguous_row_selections.push(selection.clone());
23511    let start_row = starting_row(selection, display_map);
23512    let mut end_row = ending_row(selection, display_map);
23513
23514    while let Some(next_selection) = selections.peek() {
23515        if next_selection.start.row <= end_row.0 {
23516            end_row = ending_row(next_selection, display_map);
23517            contiguous_row_selections.push(selections.next().unwrap().clone());
23518        } else {
23519            break;
23520        }
23521    }
23522    (start_row, end_row)
23523}
23524
23525fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23526    if selection.start.column > 0 {
23527        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23528    } else {
23529        MultiBufferRow(selection.start.row)
23530    }
23531}
23532
23533fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23534    if next_selection.end.column > 0 || next_selection.is_empty() {
23535        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23536    } else {
23537        MultiBufferRow(next_selection.end.row)
23538    }
23539}
23540
23541impl EditorSnapshot {
23542    pub fn remote_selections_in_range<'a>(
23543        &'a self,
23544        range: &'a Range<Anchor>,
23545        collaboration_hub: &dyn CollaborationHub,
23546        cx: &'a App,
23547    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23548        let participant_names = collaboration_hub.user_names(cx);
23549        let participant_indices = collaboration_hub.user_participant_indices(cx);
23550        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23551        let collaborators_by_replica_id = collaborators_by_peer_id
23552            .values()
23553            .map(|collaborator| (collaborator.replica_id, collaborator))
23554            .collect::<HashMap<_, _>>();
23555        self.buffer_snapshot()
23556            .selections_in_range(range, false)
23557            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23558                if replica_id == ReplicaId::AGENT {
23559                    Some(RemoteSelection {
23560                        replica_id,
23561                        selection,
23562                        cursor_shape,
23563                        line_mode,
23564                        collaborator_id: CollaboratorId::Agent,
23565                        user_name: Some("Agent".into()),
23566                        color: cx.theme().players().agent(),
23567                    })
23568                } else {
23569                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23570                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23571                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23572                    Some(RemoteSelection {
23573                        replica_id,
23574                        selection,
23575                        cursor_shape,
23576                        line_mode,
23577                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23578                        user_name,
23579                        color: if let Some(index) = participant_index {
23580                            cx.theme().players().color_for_participant(index.0)
23581                        } else {
23582                            cx.theme().players().absent()
23583                        },
23584                    })
23585                }
23586            })
23587    }
23588
23589    pub fn hunks_for_ranges(
23590        &self,
23591        ranges: impl IntoIterator<Item = Range<Point>>,
23592    ) -> Vec<MultiBufferDiffHunk> {
23593        let mut hunks = Vec::new();
23594        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23595            HashMap::default();
23596        for query_range in ranges {
23597            let query_rows =
23598                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23599            for hunk in self.buffer_snapshot().diff_hunks_in_range(
23600                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23601            ) {
23602                // Include deleted hunks that are adjacent to the query range, because
23603                // otherwise they would be missed.
23604                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23605                if hunk.status().is_deleted() {
23606                    intersects_range |= hunk.row_range.start == query_rows.end;
23607                    intersects_range |= hunk.row_range.end == query_rows.start;
23608                }
23609                if intersects_range {
23610                    if !processed_buffer_rows
23611                        .entry(hunk.buffer_id)
23612                        .or_default()
23613                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23614                    {
23615                        continue;
23616                    }
23617                    hunks.push(hunk);
23618                }
23619            }
23620        }
23621
23622        hunks
23623    }
23624
23625    fn display_diff_hunks_for_rows<'a>(
23626        &'a self,
23627        display_rows: Range<DisplayRow>,
23628        folded_buffers: &'a HashSet<BufferId>,
23629    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23630        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23631        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23632
23633        self.buffer_snapshot()
23634            .diff_hunks_in_range(buffer_start..buffer_end)
23635            .filter_map(|hunk| {
23636                if folded_buffers.contains(&hunk.buffer_id) {
23637                    return None;
23638                }
23639
23640                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23641                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23642
23643                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23644                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23645
23646                let display_hunk = if hunk_display_start.column() != 0 {
23647                    DisplayDiffHunk::Folded {
23648                        display_row: hunk_display_start.row(),
23649                    }
23650                } else {
23651                    let mut end_row = hunk_display_end.row();
23652                    if hunk_display_end.column() > 0 {
23653                        end_row.0 += 1;
23654                    }
23655                    let is_created_file = hunk.is_created_file();
23656                    DisplayDiffHunk::Unfolded {
23657                        status: hunk.status(),
23658                        diff_base_byte_range: hunk.diff_base_byte_range,
23659                        display_row_range: hunk_display_start.row()..end_row,
23660                        multi_buffer_range: Anchor::range_in_buffer(
23661                            hunk.excerpt_id,
23662                            hunk.buffer_id,
23663                            hunk.buffer_range,
23664                        ),
23665                        is_created_file,
23666                    }
23667                };
23668
23669                Some(display_hunk)
23670            })
23671    }
23672
23673    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23674        self.display_snapshot
23675            .buffer_snapshot()
23676            .language_at(position)
23677    }
23678
23679    pub fn is_focused(&self) -> bool {
23680        self.is_focused
23681    }
23682
23683    pub fn placeholder_text(&self) -> Option<String> {
23684        self.placeholder_display_snapshot
23685            .as_ref()
23686            .map(|display_map| display_map.text())
23687    }
23688
23689    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
23690        self.scroll_anchor.scroll_position(&self.display_snapshot)
23691    }
23692
23693    fn gutter_dimensions(
23694        &self,
23695        font_id: FontId,
23696        font_size: Pixels,
23697        max_line_number_width: Pixels,
23698        cx: &App,
23699    ) -> Option<GutterDimensions> {
23700        if !self.show_gutter {
23701            return None;
23702        }
23703
23704        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23705        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23706
23707        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23708            matches!(
23709                ProjectSettings::get_global(cx).git.git_gutter,
23710                GitGutterSetting::TrackedFiles
23711            )
23712        });
23713        let gutter_settings = EditorSettings::get_global(cx).gutter;
23714        let show_line_numbers = self
23715            .show_line_numbers
23716            .unwrap_or(gutter_settings.line_numbers);
23717        let line_gutter_width = if show_line_numbers {
23718            // Avoid flicker-like gutter resizes when the line number gains another digit by
23719            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23720            let min_width_for_number_on_gutter =
23721                ch_advance * gutter_settings.min_line_number_digits as f32;
23722            max_line_number_width.max(min_width_for_number_on_gutter)
23723        } else {
23724            0.0.into()
23725        };
23726
23727        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23728        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23729
23730        let git_blame_entries_width =
23731            self.git_blame_gutter_max_author_length
23732                .map(|max_author_length| {
23733                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23734                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23735
23736                    /// The number of characters to dedicate to gaps and margins.
23737                    const SPACING_WIDTH: usize = 4;
23738
23739                    let max_char_count = max_author_length.min(renderer.max_author_length())
23740                        + ::git::SHORT_SHA_LENGTH
23741                        + MAX_RELATIVE_TIMESTAMP.len()
23742                        + SPACING_WIDTH;
23743
23744                    ch_advance * max_char_count
23745                });
23746
23747        let is_singleton = self.buffer_snapshot().is_singleton();
23748
23749        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23750        left_padding += if !is_singleton {
23751            ch_width * 4.0
23752        } else if show_runnables || show_breakpoints {
23753            ch_width * 3.0
23754        } else if show_git_gutter && show_line_numbers {
23755            ch_width * 2.0
23756        } else if show_git_gutter || show_line_numbers {
23757            ch_width
23758        } else {
23759            px(0.)
23760        };
23761
23762        let shows_folds = is_singleton && gutter_settings.folds;
23763
23764        let right_padding = if shows_folds && show_line_numbers {
23765            ch_width * 4.0
23766        } else if shows_folds || (!is_singleton && show_line_numbers) {
23767            ch_width * 3.0
23768        } else if show_line_numbers {
23769            ch_width
23770        } else {
23771            px(0.)
23772        };
23773
23774        Some(GutterDimensions {
23775            left_padding,
23776            right_padding,
23777            width: line_gutter_width + left_padding + right_padding,
23778            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23779            git_blame_entries_width,
23780        })
23781    }
23782
23783    pub fn render_crease_toggle(
23784        &self,
23785        buffer_row: MultiBufferRow,
23786        row_contains_cursor: bool,
23787        editor: Entity<Editor>,
23788        window: &mut Window,
23789        cx: &mut App,
23790    ) -> Option<AnyElement> {
23791        let folded = self.is_line_folded(buffer_row);
23792        let mut is_foldable = false;
23793
23794        if let Some(crease) = self
23795            .crease_snapshot
23796            .query_row(buffer_row, self.buffer_snapshot())
23797        {
23798            is_foldable = true;
23799            match crease {
23800                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23801                    if let Some(render_toggle) = render_toggle {
23802                        let toggle_callback =
23803                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23804                                if folded {
23805                                    editor.update(cx, |editor, cx| {
23806                                        editor.fold_at(buffer_row, window, cx)
23807                                    });
23808                                } else {
23809                                    editor.update(cx, |editor, cx| {
23810                                        editor.unfold_at(buffer_row, window, cx)
23811                                    });
23812                                }
23813                            });
23814                        return Some((render_toggle)(
23815                            buffer_row,
23816                            folded,
23817                            toggle_callback,
23818                            window,
23819                            cx,
23820                        ));
23821                    }
23822                }
23823            }
23824        }
23825
23826        is_foldable |= self.starts_indent(buffer_row);
23827
23828        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23829            Some(
23830                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23831                    .toggle_state(folded)
23832                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23833                        if folded {
23834                            this.unfold_at(buffer_row, window, cx);
23835                        } else {
23836                            this.fold_at(buffer_row, window, cx);
23837                        }
23838                    }))
23839                    .into_any_element(),
23840            )
23841        } else {
23842            None
23843        }
23844    }
23845
23846    pub fn render_crease_trailer(
23847        &self,
23848        buffer_row: MultiBufferRow,
23849        window: &mut Window,
23850        cx: &mut App,
23851    ) -> Option<AnyElement> {
23852        let folded = self.is_line_folded(buffer_row);
23853        if let Crease::Inline { render_trailer, .. } = self
23854            .crease_snapshot
23855            .query_row(buffer_row, self.buffer_snapshot())?
23856        {
23857            let render_trailer = render_trailer.as_ref()?;
23858            Some(render_trailer(buffer_row, folded, window, cx))
23859        } else {
23860            None
23861        }
23862    }
23863}
23864
23865impl Deref for EditorSnapshot {
23866    type Target = DisplaySnapshot;
23867
23868    fn deref(&self) -> &Self::Target {
23869        &self.display_snapshot
23870    }
23871}
23872
23873#[derive(Clone, Debug, PartialEq, Eq)]
23874pub enum EditorEvent {
23875    InputIgnored {
23876        text: Arc<str>,
23877    },
23878    InputHandled {
23879        utf16_range_to_replace: Option<Range<isize>>,
23880        text: Arc<str>,
23881    },
23882    ExcerptsAdded {
23883        buffer: Entity<Buffer>,
23884        predecessor: ExcerptId,
23885        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23886    },
23887    ExcerptsRemoved {
23888        ids: Vec<ExcerptId>,
23889        removed_buffer_ids: Vec<BufferId>,
23890    },
23891    BufferFoldToggled {
23892        ids: Vec<ExcerptId>,
23893        folded: bool,
23894    },
23895    ExcerptsEdited {
23896        ids: Vec<ExcerptId>,
23897    },
23898    ExcerptsExpanded {
23899        ids: Vec<ExcerptId>,
23900    },
23901    BufferEdited,
23902    Edited {
23903        transaction_id: clock::Lamport,
23904    },
23905    Reparsed(BufferId),
23906    Focused,
23907    FocusedIn,
23908    Blurred,
23909    DirtyChanged,
23910    Saved,
23911    TitleChanged,
23912    SelectionsChanged {
23913        local: bool,
23914    },
23915    ScrollPositionChanged {
23916        local: bool,
23917        autoscroll: bool,
23918    },
23919    TransactionUndone {
23920        transaction_id: clock::Lamport,
23921    },
23922    TransactionBegun {
23923        transaction_id: clock::Lamport,
23924    },
23925    CursorShapeChanged,
23926    BreadcrumbsChanged,
23927    PushedToNavHistory {
23928        anchor: Anchor,
23929        is_deactivate: bool,
23930    },
23931}
23932
23933impl EventEmitter<EditorEvent> for Editor {}
23934
23935impl Focusable for Editor {
23936    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23937        self.focus_handle.clone()
23938    }
23939}
23940
23941impl Render for Editor {
23942    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23943        let settings = ThemeSettings::get_global(cx);
23944
23945        let mut text_style = match self.mode {
23946            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23947                color: cx.theme().colors().editor_foreground,
23948                font_family: settings.ui_font.family.clone(),
23949                font_features: settings.ui_font.features.clone(),
23950                font_fallbacks: settings.ui_font.fallbacks.clone(),
23951                font_size: rems(0.875).into(),
23952                font_weight: settings.ui_font.weight,
23953                line_height: relative(settings.buffer_line_height.value()),
23954                ..Default::default()
23955            },
23956            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23957                color: cx.theme().colors().editor_foreground,
23958                font_family: settings.buffer_font.family.clone(),
23959                font_features: settings.buffer_font.features.clone(),
23960                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23961                font_size: settings.buffer_font_size(cx).into(),
23962                font_weight: settings.buffer_font.weight,
23963                line_height: relative(settings.buffer_line_height.value()),
23964                ..Default::default()
23965            },
23966        };
23967        if let Some(text_style_refinement) = &self.text_style_refinement {
23968            text_style.refine(text_style_refinement)
23969        }
23970
23971        let background = match self.mode {
23972            EditorMode::SingleLine => cx.theme().system().transparent,
23973            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23974            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23975            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23976        };
23977
23978        EditorElement::new(
23979            &cx.entity(),
23980            EditorStyle {
23981                background,
23982                border: cx.theme().colors().border,
23983                local_player: cx.theme().players().local(),
23984                text: text_style,
23985                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23986                syntax: cx.theme().syntax().clone(),
23987                status: cx.theme().status().clone(),
23988                inlay_hints_style: make_inlay_hints_style(cx),
23989                edit_prediction_styles: make_suggestion_styles(cx),
23990                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23991                show_underlines: self.diagnostics_enabled(),
23992            },
23993        )
23994    }
23995}
23996
23997impl EntityInputHandler for Editor {
23998    fn text_for_range(
23999        &mut self,
24000        range_utf16: Range<usize>,
24001        adjusted_range: &mut Option<Range<usize>>,
24002        _: &mut Window,
24003        cx: &mut Context<Self>,
24004    ) -> Option<String> {
24005        let snapshot = self.buffer.read(cx).read(cx);
24006        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
24007        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
24008        if (start.0..end.0) != range_utf16 {
24009            adjusted_range.replace(start.0..end.0);
24010        }
24011        Some(snapshot.text_for_range(start..end).collect())
24012    }
24013
24014    fn selected_text_range(
24015        &mut self,
24016        ignore_disabled_input: bool,
24017        _: &mut Window,
24018        cx: &mut Context<Self>,
24019    ) -> Option<UTF16Selection> {
24020        // Prevent the IME menu from appearing when holding down an alphabetic key
24021        // while input is disabled.
24022        if !ignore_disabled_input && !self.input_enabled {
24023            return None;
24024        }
24025
24026        let selection = self
24027            .selections
24028            .newest::<OffsetUtf16>(&self.display_snapshot(cx));
24029        let range = selection.range();
24030
24031        Some(UTF16Selection {
24032            range: range.start.0..range.end.0,
24033            reversed: selection.reversed,
24034        })
24035    }
24036
24037    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
24038        let snapshot = self.buffer.read(cx).read(cx);
24039        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
24040        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
24041    }
24042
24043    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
24044        self.clear_highlights::<InputComposition>(cx);
24045        self.ime_transaction.take();
24046    }
24047
24048    fn replace_text_in_range(
24049        &mut self,
24050        range_utf16: Option<Range<usize>>,
24051        text: &str,
24052        window: &mut Window,
24053        cx: &mut Context<Self>,
24054    ) {
24055        if !self.input_enabled {
24056            cx.emit(EditorEvent::InputIgnored { text: text.into() });
24057            return;
24058        }
24059
24060        self.transact(window, cx, |this, window, cx| {
24061            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
24062                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
24063                Some(this.selection_replacement_ranges(range_utf16, cx))
24064            } else {
24065                this.marked_text_ranges(cx)
24066            };
24067
24068            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
24069                let newest_selection_id = this.selections.newest_anchor().id;
24070                this.selections
24071                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
24072                    .iter()
24073                    .zip(ranges_to_replace.iter())
24074                    .find_map(|(selection, range)| {
24075                        if selection.id == newest_selection_id {
24076                            Some(
24077                                (range.start.0 as isize - selection.head().0 as isize)
24078                                    ..(range.end.0 as isize - selection.head().0 as isize),
24079                            )
24080                        } else {
24081                            None
24082                        }
24083                    })
24084            });
24085
24086            cx.emit(EditorEvent::InputHandled {
24087                utf16_range_to_replace: range_to_replace,
24088                text: text.into(),
24089            });
24090
24091            if let Some(new_selected_ranges) = new_selected_ranges {
24092                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24093                    selections.select_ranges(new_selected_ranges)
24094                });
24095                this.backspace(&Default::default(), window, cx);
24096            }
24097
24098            this.handle_input(text, window, cx);
24099        });
24100
24101        if let Some(transaction) = self.ime_transaction {
24102            self.buffer.update(cx, |buffer, cx| {
24103                buffer.group_until_transaction(transaction, cx);
24104            });
24105        }
24106
24107        self.unmark_text(window, cx);
24108    }
24109
24110    fn replace_and_mark_text_in_range(
24111        &mut self,
24112        range_utf16: Option<Range<usize>>,
24113        text: &str,
24114        new_selected_range_utf16: Option<Range<usize>>,
24115        window: &mut Window,
24116        cx: &mut Context<Self>,
24117    ) {
24118        if !self.input_enabled {
24119            return;
24120        }
24121
24122        let transaction = self.transact(window, cx, |this, window, cx| {
24123            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
24124                let snapshot = this.buffer.read(cx).read(cx);
24125                if let Some(relative_range_utf16) = range_utf16.as_ref() {
24126                    for marked_range in &mut marked_ranges {
24127                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
24128                        marked_range.start.0 += relative_range_utf16.start;
24129                        marked_range.start =
24130                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
24131                        marked_range.end =
24132                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
24133                    }
24134                }
24135                Some(marked_ranges)
24136            } else if let Some(range_utf16) = range_utf16 {
24137                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
24138                Some(this.selection_replacement_ranges(range_utf16, cx))
24139            } else {
24140                None
24141            };
24142
24143            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
24144                let newest_selection_id = this.selections.newest_anchor().id;
24145                this.selections
24146                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
24147                    .iter()
24148                    .zip(ranges_to_replace.iter())
24149                    .find_map(|(selection, range)| {
24150                        if selection.id == newest_selection_id {
24151                            Some(
24152                                (range.start.0 as isize - selection.head().0 as isize)
24153                                    ..(range.end.0 as isize - selection.head().0 as isize),
24154                            )
24155                        } else {
24156                            None
24157                        }
24158                    })
24159            });
24160
24161            cx.emit(EditorEvent::InputHandled {
24162                utf16_range_to_replace: range_to_replace,
24163                text: text.into(),
24164            });
24165
24166            if let Some(ranges) = ranges_to_replace {
24167                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24168                    s.select_ranges(ranges)
24169                });
24170            }
24171
24172            let marked_ranges = {
24173                let snapshot = this.buffer.read(cx).read(cx);
24174                this.selections
24175                    .disjoint_anchors_arc()
24176                    .iter()
24177                    .map(|selection| {
24178                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
24179                    })
24180                    .collect::<Vec<_>>()
24181            };
24182
24183            if text.is_empty() {
24184                this.unmark_text(window, cx);
24185            } else {
24186                this.highlight_text::<InputComposition>(
24187                    marked_ranges.clone(),
24188                    HighlightStyle {
24189                        underline: Some(UnderlineStyle {
24190                            thickness: px(1.),
24191                            color: None,
24192                            wavy: false,
24193                        }),
24194                        ..Default::default()
24195                    },
24196                    cx,
24197                );
24198            }
24199
24200            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
24201            let use_autoclose = this.use_autoclose;
24202            let use_auto_surround = this.use_auto_surround;
24203            this.set_use_autoclose(false);
24204            this.set_use_auto_surround(false);
24205            this.handle_input(text, window, cx);
24206            this.set_use_autoclose(use_autoclose);
24207            this.set_use_auto_surround(use_auto_surround);
24208
24209            if let Some(new_selected_range) = new_selected_range_utf16 {
24210                let snapshot = this.buffer.read(cx).read(cx);
24211                let new_selected_ranges = marked_ranges
24212                    .into_iter()
24213                    .map(|marked_range| {
24214                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24215                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
24216                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
24217                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24218                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24219                    })
24220                    .collect::<Vec<_>>();
24221
24222                drop(snapshot);
24223                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24224                    selections.select_ranges(new_selected_ranges)
24225                });
24226            }
24227        });
24228
24229        self.ime_transaction = self.ime_transaction.or(transaction);
24230        if let Some(transaction) = self.ime_transaction {
24231            self.buffer.update(cx, |buffer, cx| {
24232                buffer.group_until_transaction(transaction, cx);
24233            });
24234        }
24235
24236        if self.text_highlights::<InputComposition>(cx).is_none() {
24237            self.ime_transaction.take();
24238        }
24239    }
24240
24241    fn bounds_for_range(
24242        &mut self,
24243        range_utf16: Range<usize>,
24244        element_bounds: gpui::Bounds<Pixels>,
24245        window: &mut Window,
24246        cx: &mut Context<Self>,
24247    ) -> Option<gpui::Bounds<Pixels>> {
24248        let text_layout_details = self.text_layout_details(window);
24249        let CharacterDimensions {
24250            em_width,
24251            em_advance,
24252            line_height,
24253        } = self.character_dimensions(window);
24254
24255        let snapshot = self.snapshot(window, cx);
24256        let scroll_position = snapshot.scroll_position();
24257        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24258
24259        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
24260        let x = Pixels::from(
24261            ScrollOffset::from(
24262                snapshot.x_for_display_point(start, &text_layout_details)
24263                    + self.gutter_dimensions.full_width(),
24264            ) - scroll_left,
24265        );
24266        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24267
24268        Some(Bounds {
24269            origin: element_bounds.origin + point(x, y),
24270            size: size(em_width, line_height),
24271        })
24272    }
24273
24274    fn character_index_for_point(
24275        &mut self,
24276        point: gpui::Point<Pixels>,
24277        _window: &mut Window,
24278        _cx: &mut Context<Self>,
24279    ) -> Option<usize> {
24280        let position_map = self.last_position_map.as_ref()?;
24281        if !position_map.text_hitbox.contains(&point) {
24282            return None;
24283        }
24284        let display_point = position_map.point_for_position(point).previous_valid;
24285        let anchor = position_map
24286            .snapshot
24287            .display_point_to_anchor(display_point, Bias::Left);
24288        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24289        Some(utf16_offset.0)
24290    }
24291
24292    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
24293        self.input_enabled
24294    }
24295}
24296
24297trait SelectionExt {
24298    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24299    fn spanned_rows(
24300        &self,
24301        include_end_if_at_line_start: bool,
24302        map: &DisplaySnapshot,
24303    ) -> Range<MultiBufferRow>;
24304}
24305
24306impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24307    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24308        let start = self
24309            .start
24310            .to_point(map.buffer_snapshot())
24311            .to_display_point(map);
24312        let end = self
24313            .end
24314            .to_point(map.buffer_snapshot())
24315            .to_display_point(map);
24316        if self.reversed {
24317            end..start
24318        } else {
24319            start..end
24320        }
24321    }
24322
24323    fn spanned_rows(
24324        &self,
24325        include_end_if_at_line_start: bool,
24326        map: &DisplaySnapshot,
24327    ) -> Range<MultiBufferRow> {
24328        let start = self.start.to_point(map.buffer_snapshot());
24329        let mut end = self.end.to_point(map.buffer_snapshot());
24330        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24331            end.row -= 1;
24332        }
24333
24334        let buffer_start = map.prev_line_boundary(start).0;
24335        let buffer_end = map.next_line_boundary(end).0;
24336        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24337    }
24338}
24339
24340impl<T: InvalidationRegion> InvalidationStack<T> {
24341    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24342    where
24343        S: Clone + ToOffset,
24344    {
24345        while let Some(region) = self.last() {
24346            let all_selections_inside_invalidation_ranges =
24347                if selections.len() == region.ranges().len() {
24348                    selections
24349                        .iter()
24350                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24351                        .all(|(selection, invalidation_range)| {
24352                            let head = selection.head().to_offset(buffer);
24353                            invalidation_range.start <= head && invalidation_range.end >= head
24354                        })
24355                } else {
24356                    false
24357                };
24358
24359            if all_selections_inside_invalidation_ranges {
24360                break;
24361            } else {
24362                self.pop();
24363            }
24364        }
24365    }
24366}
24367
24368impl<T> Default for InvalidationStack<T> {
24369    fn default() -> Self {
24370        Self(Default::default())
24371    }
24372}
24373
24374impl<T> Deref for InvalidationStack<T> {
24375    type Target = Vec<T>;
24376
24377    fn deref(&self) -> &Self::Target {
24378        &self.0
24379    }
24380}
24381
24382impl<T> DerefMut for InvalidationStack<T> {
24383    fn deref_mut(&mut self) -> &mut Self::Target {
24384        &mut self.0
24385    }
24386}
24387
24388impl InvalidationRegion for SnippetState {
24389    fn ranges(&self) -> &[Range<Anchor>] {
24390        &self.ranges[self.active_index]
24391    }
24392}
24393
24394fn edit_prediction_edit_text(
24395    current_snapshot: &BufferSnapshot,
24396    edits: &[(Range<Anchor>, impl AsRef<str>)],
24397    edit_preview: &EditPreview,
24398    include_deletions: bool,
24399    cx: &App,
24400) -> HighlightedText {
24401    let edits = edits
24402        .iter()
24403        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
24404        .collect::<Vec<_>>();
24405
24406    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24407}
24408
24409fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
24410    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24411    // Just show the raw edit text with basic styling
24412    let mut text = String::new();
24413    let mut highlights = Vec::new();
24414
24415    let insertion_highlight_style = HighlightStyle {
24416        color: Some(cx.theme().colors().text),
24417        ..Default::default()
24418    };
24419
24420    for (_, edit_text) in edits {
24421        let start_offset = text.len();
24422        text.push_str(edit_text);
24423        let end_offset = text.len();
24424
24425        if start_offset < end_offset {
24426            highlights.push((start_offset..end_offset, insertion_highlight_style));
24427        }
24428    }
24429
24430    HighlightedText {
24431        text: text.into(),
24432        highlights,
24433    }
24434}
24435
24436pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24437    match severity {
24438        lsp::DiagnosticSeverity::ERROR => colors.error,
24439        lsp::DiagnosticSeverity::WARNING => colors.warning,
24440        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24441        lsp::DiagnosticSeverity::HINT => colors.info,
24442        _ => colors.ignored,
24443    }
24444}
24445
24446pub fn styled_runs_for_code_label<'a>(
24447    label: &'a CodeLabel,
24448    syntax_theme: &'a theme::SyntaxTheme,
24449) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24450    let fade_out = HighlightStyle {
24451        fade_out: Some(0.35),
24452        ..Default::default()
24453    };
24454
24455    let mut prev_end = label.filter_range.end;
24456    label
24457        .runs
24458        .iter()
24459        .enumerate()
24460        .flat_map(move |(ix, (range, highlight_id))| {
24461            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24462                style
24463            } else {
24464                return Default::default();
24465            };
24466            let muted_style = style.highlight(fade_out);
24467
24468            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24469            if range.start >= label.filter_range.end {
24470                if range.start > prev_end {
24471                    runs.push((prev_end..range.start, fade_out));
24472                }
24473                runs.push((range.clone(), muted_style));
24474            } else if range.end <= label.filter_range.end {
24475                runs.push((range.clone(), style));
24476            } else {
24477                runs.push((range.start..label.filter_range.end, style));
24478                runs.push((label.filter_range.end..range.end, muted_style));
24479            }
24480            prev_end = cmp::max(prev_end, range.end);
24481
24482            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24483                runs.push((prev_end..label.text.len(), fade_out));
24484            }
24485
24486            runs
24487        })
24488}
24489
24490pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24491    let mut prev_index = 0;
24492    let mut prev_codepoint: Option<char> = None;
24493    text.char_indices()
24494        .chain([(text.len(), '\0')])
24495        .filter_map(move |(index, codepoint)| {
24496            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24497            let is_boundary = index == text.len()
24498                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24499                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24500            if is_boundary {
24501                let chunk = &text[prev_index..index];
24502                prev_index = index;
24503                Some(chunk)
24504            } else {
24505                None
24506            }
24507        })
24508}
24509
24510pub trait RangeToAnchorExt: Sized {
24511    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24512
24513    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24514        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
24515        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24516    }
24517}
24518
24519impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24520    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24521        let start_offset = self.start.to_offset(snapshot);
24522        let end_offset = self.end.to_offset(snapshot);
24523        if start_offset == end_offset {
24524            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24525        } else {
24526            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24527        }
24528    }
24529}
24530
24531pub trait RowExt {
24532    fn as_f64(&self) -> f64;
24533
24534    fn next_row(&self) -> Self;
24535
24536    fn previous_row(&self) -> Self;
24537
24538    fn minus(&self, other: Self) -> u32;
24539}
24540
24541impl RowExt for DisplayRow {
24542    fn as_f64(&self) -> f64 {
24543        self.0 as _
24544    }
24545
24546    fn next_row(&self) -> Self {
24547        Self(self.0 + 1)
24548    }
24549
24550    fn previous_row(&self) -> Self {
24551        Self(self.0.saturating_sub(1))
24552    }
24553
24554    fn minus(&self, other: Self) -> u32 {
24555        self.0 - other.0
24556    }
24557}
24558
24559impl RowExt for MultiBufferRow {
24560    fn as_f64(&self) -> f64 {
24561        self.0 as _
24562    }
24563
24564    fn next_row(&self) -> Self {
24565        Self(self.0 + 1)
24566    }
24567
24568    fn previous_row(&self) -> Self {
24569        Self(self.0.saturating_sub(1))
24570    }
24571
24572    fn minus(&self, other: Self) -> u32 {
24573        self.0 - other.0
24574    }
24575}
24576
24577trait RowRangeExt {
24578    type Row;
24579
24580    fn len(&self) -> usize;
24581
24582    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24583}
24584
24585impl RowRangeExt for Range<MultiBufferRow> {
24586    type Row = MultiBufferRow;
24587
24588    fn len(&self) -> usize {
24589        (self.end.0 - self.start.0) as usize
24590    }
24591
24592    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24593        (self.start.0..self.end.0).map(MultiBufferRow)
24594    }
24595}
24596
24597impl RowRangeExt for Range<DisplayRow> {
24598    type Row = DisplayRow;
24599
24600    fn len(&self) -> usize {
24601        (self.end.0 - self.start.0) as usize
24602    }
24603
24604    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24605        (self.start.0..self.end.0).map(DisplayRow)
24606    }
24607}
24608
24609/// If select range has more than one line, we
24610/// just point the cursor to range.start.
24611fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24612    if range.start.row == range.end.row {
24613        range
24614    } else {
24615        range.start..range.start
24616    }
24617}
24618pub struct KillRing(ClipboardItem);
24619impl Global for KillRing {}
24620
24621const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24622
24623enum BreakpointPromptEditAction {
24624    Log,
24625    Condition,
24626    HitCondition,
24627}
24628
24629struct BreakpointPromptEditor {
24630    pub(crate) prompt: Entity<Editor>,
24631    editor: WeakEntity<Editor>,
24632    breakpoint_anchor: Anchor,
24633    breakpoint: Breakpoint,
24634    edit_action: BreakpointPromptEditAction,
24635    block_ids: HashSet<CustomBlockId>,
24636    editor_margins: Arc<Mutex<EditorMargins>>,
24637    _subscriptions: Vec<Subscription>,
24638}
24639
24640impl BreakpointPromptEditor {
24641    const MAX_LINES: u8 = 4;
24642
24643    fn new(
24644        editor: WeakEntity<Editor>,
24645        breakpoint_anchor: Anchor,
24646        breakpoint: Breakpoint,
24647        edit_action: BreakpointPromptEditAction,
24648        window: &mut Window,
24649        cx: &mut Context<Self>,
24650    ) -> Self {
24651        let base_text = match edit_action {
24652            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24653            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24654            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24655        }
24656        .map(|msg| msg.to_string())
24657        .unwrap_or_default();
24658
24659        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24660        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24661
24662        let prompt = cx.new(|cx| {
24663            let mut prompt = Editor::new(
24664                EditorMode::AutoHeight {
24665                    min_lines: 1,
24666                    max_lines: Some(Self::MAX_LINES as usize),
24667                },
24668                buffer,
24669                None,
24670                window,
24671                cx,
24672            );
24673            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24674            prompt.set_show_cursor_when_unfocused(false, cx);
24675            prompt.set_placeholder_text(
24676                match edit_action {
24677                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24678                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24679                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24680                },
24681                window,
24682                cx,
24683            );
24684
24685            prompt
24686        });
24687
24688        Self {
24689            prompt,
24690            editor,
24691            breakpoint_anchor,
24692            breakpoint,
24693            edit_action,
24694            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24695            block_ids: Default::default(),
24696            _subscriptions: vec![],
24697        }
24698    }
24699
24700    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24701        self.block_ids.extend(block_ids)
24702    }
24703
24704    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24705        if let Some(editor) = self.editor.upgrade() {
24706            let message = self
24707                .prompt
24708                .read(cx)
24709                .buffer
24710                .read(cx)
24711                .as_singleton()
24712                .expect("A multi buffer in breakpoint prompt isn't possible")
24713                .read(cx)
24714                .as_rope()
24715                .to_string();
24716
24717            editor.update(cx, |editor, cx| {
24718                editor.edit_breakpoint_at_anchor(
24719                    self.breakpoint_anchor,
24720                    self.breakpoint.clone(),
24721                    match self.edit_action {
24722                        BreakpointPromptEditAction::Log => {
24723                            BreakpointEditAction::EditLogMessage(message.into())
24724                        }
24725                        BreakpointPromptEditAction::Condition => {
24726                            BreakpointEditAction::EditCondition(message.into())
24727                        }
24728                        BreakpointPromptEditAction::HitCondition => {
24729                            BreakpointEditAction::EditHitCondition(message.into())
24730                        }
24731                    },
24732                    cx,
24733                );
24734
24735                editor.remove_blocks(self.block_ids.clone(), None, cx);
24736                cx.focus_self(window);
24737            });
24738        }
24739    }
24740
24741    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24742        self.editor
24743            .update(cx, |editor, cx| {
24744                editor.remove_blocks(self.block_ids.clone(), None, cx);
24745                window.focus(&editor.focus_handle);
24746            })
24747            .log_err();
24748    }
24749
24750    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24751        let settings = ThemeSettings::get_global(cx);
24752        let text_style = TextStyle {
24753            color: if self.prompt.read(cx).read_only(cx) {
24754                cx.theme().colors().text_disabled
24755            } else {
24756                cx.theme().colors().text
24757            },
24758            font_family: settings.buffer_font.family.clone(),
24759            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24760            font_size: settings.buffer_font_size(cx).into(),
24761            font_weight: settings.buffer_font.weight,
24762            line_height: relative(settings.buffer_line_height.value()),
24763            ..Default::default()
24764        };
24765        EditorElement::new(
24766            &self.prompt,
24767            EditorStyle {
24768                background: cx.theme().colors().editor_background,
24769                local_player: cx.theme().players().local(),
24770                text: text_style,
24771                ..Default::default()
24772            },
24773        )
24774    }
24775}
24776
24777impl Render for BreakpointPromptEditor {
24778    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24779        let editor_margins = *self.editor_margins.lock();
24780        let gutter_dimensions = editor_margins.gutter;
24781        h_flex()
24782            .key_context("Editor")
24783            .bg(cx.theme().colors().editor_background)
24784            .border_y_1()
24785            .border_color(cx.theme().status().info_border)
24786            .size_full()
24787            .py(window.line_height() / 2.5)
24788            .on_action(cx.listener(Self::confirm))
24789            .on_action(cx.listener(Self::cancel))
24790            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24791            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24792    }
24793}
24794
24795impl Focusable for BreakpointPromptEditor {
24796    fn focus_handle(&self, cx: &App) -> FocusHandle {
24797        self.prompt.focus_handle(cx)
24798    }
24799}
24800
24801fn all_edits_insertions_or_deletions(
24802    edits: &Vec<(Range<Anchor>, Arc<str>)>,
24803    snapshot: &MultiBufferSnapshot,
24804) -> bool {
24805    let mut all_insertions = true;
24806    let mut all_deletions = true;
24807
24808    for (range, new_text) in edits.iter() {
24809        let range_is_empty = range.to_offset(snapshot).is_empty();
24810        let text_is_empty = new_text.is_empty();
24811
24812        if range_is_empty != text_is_empty {
24813            if range_is_empty {
24814                all_deletions = false;
24815            } else {
24816                all_insertions = false;
24817            }
24818        } else {
24819            return false;
24820        }
24821
24822        if !all_insertions && !all_deletions {
24823            return false;
24824        }
24825    }
24826    all_insertions || all_deletions
24827}
24828
24829struct MissingEditPredictionKeybindingTooltip;
24830
24831impl Render for MissingEditPredictionKeybindingTooltip {
24832    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24833        ui::tooltip_container(cx, |container, cx| {
24834            container
24835                .flex_shrink_0()
24836                .max_w_80()
24837                .min_h(rems_from_px(124.))
24838                .justify_between()
24839                .child(
24840                    v_flex()
24841                        .flex_1()
24842                        .text_ui_sm(cx)
24843                        .child(Label::new("Conflict with Accept Keybinding"))
24844                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24845                )
24846                .child(
24847                    h_flex()
24848                        .pb_1()
24849                        .gap_1()
24850                        .items_end()
24851                        .w_full()
24852                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24853                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
24854                        }))
24855                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24856                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24857                        })),
24858                )
24859        })
24860    }
24861}
24862
24863#[derive(Debug, Clone, Copy, PartialEq)]
24864pub struct LineHighlight {
24865    pub background: Background,
24866    pub border: Option<gpui::Hsla>,
24867    pub include_gutter: bool,
24868    pub type_id: Option<TypeId>,
24869}
24870
24871struct LineManipulationResult {
24872    pub new_text: String,
24873    pub line_count_before: usize,
24874    pub line_count_after: usize,
24875}
24876
24877fn render_diff_hunk_controls(
24878    row: u32,
24879    status: &DiffHunkStatus,
24880    hunk_range: Range<Anchor>,
24881    is_created_file: bool,
24882    line_height: Pixels,
24883    editor: &Entity<Editor>,
24884    _window: &mut Window,
24885    cx: &mut App,
24886) -> AnyElement {
24887    h_flex()
24888        .h(line_height)
24889        .mr_1()
24890        .gap_1()
24891        .px_0p5()
24892        .pb_1()
24893        .border_x_1()
24894        .border_b_1()
24895        .border_color(cx.theme().colors().border_variant)
24896        .rounded_b_lg()
24897        .bg(cx.theme().colors().editor_background)
24898        .gap_1()
24899        .block_mouse_except_scroll()
24900        .shadow_md()
24901        .child(if status.has_secondary_hunk() {
24902            Button::new(("stage", row as u64), "Stage")
24903                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24904                .tooltip({
24905                    let focus_handle = editor.focus_handle(cx);
24906                    move |_window, cx| {
24907                        Tooltip::for_action_in(
24908                            "Stage Hunk",
24909                            &::git::ToggleStaged,
24910                            &focus_handle,
24911                            cx,
24912                        )
24913                    }
24914                })
24915                .on_click({
24916                    let editor = editor.clone();
24917                    move |_event, _window, cx| {
24918                        editor.update(cx, |editor, cx| {
24919                            editor.stage_or_unstage_diff_hunks(
24920                                true,
24921                                vec![hunk_range.start..hunk_range.start],
24922                                cx,
24923                            );
24924                        });
24925                    }
24926                })
24927        } else {
24928            Button::new(("unstage", row as u64), "Unstage")
24929                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24930                .tooltip({
24931                    let focus_handle = editor.focus_handle(cx);
24932                    move |_window, cx| {
24933                        Tooltip::for_action_in(
24934                            "Unstage Hunk",
24935                            &::git::ToggleStaged,
24936                            &focus_handle,
24937                            cx,
24938                        )
24939                    }
24940                })
24941                .on_click({
24942                    let editor = editor.clone();
24943                    move |_event, _window, cx| {
24944                        editor.update(cx, |editor, cx| {
24945                            editor.stage_or_unstage_diff_hunks(
24946                                false,
24947                                vec![hunk_range.start..hunk_range.start],
24948                                cx,
24949                            );
24950                        });
24951                    }
24952                })
24953        })
24954        .child(
24955            Button::new(("restore", row as u64), "Restore")
24956                .tooltip({
24957                    let focus_handle = editor.focus_handle(cx);
24958                    move |_window, cx| {
24959                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
24960                    }
24961                })
24962                .on_click({
24963                    let editor = editor.clone();
24964                    move |_event, window, cx| {
24965                        editor.update(cx, |editor, cx| {
24966                            let snapshot = editor.snapshot(window, cx);
24967                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
24968                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24969                        });
24970                    }
24971                })
24972                .disabled(is_created_file),
24973        )
24974        .when(
24975            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24976            |el| {
24977                el.child(
24978                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24979                        .shape(IconButtonShape::Square)
24980                        .icon_size(IconSize::Small)
24981                        // .disabled(!has_multiple_hunks)
24982                        .tooltip({
24983                            let focus_handle = editor.focus_handle(cx);
24984                            move |_window, cx| {
24985                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
24986                            }
24987                        })
24988                        .on_click({
24989                            let editor = editor.clone();
24990                            move |_event, window, cx| {
24991                                editor.update(cx, |editor, cx| {
24992                                    let snapshot = editor.snapshot(window, cx);
24993                                    let position =
24994                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
24995                                    editor.go_to_hunk_before_or_after_position(
24996                                        &snapshot,
24997                                        position,
24998                                        Direction::Next,
24999                                        window,
25000                                        cx,
25001                                    );
25002                                    editor.expand_selected_diff_hunks(cx);
25003                                });
25004                            }
25005                        }),
25006                )
25007                .child(
25008                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
25009                        .shape(IconButtonShape::Square)
25010                        .icon_size(IconSize::Small)
25011                        // .disabled(!has_multiple_hunks)
25012                        .tooltip({
25013                            let focus_handle = editor.focus_handle(cx);
25014                            move |_window, cx| {
25015                                Tooltip::for_action_in(
25016                                    "Previous Hunk",
25017                                    &GoToPreviousHunk,
25018                                    &focus_handle,
25019                                    cx,
25020                                )
25021                            }
25022                        })
25023                        .on_click({
25024                            let editor = editor.clone();
25025                            move |_event, window, cx| {
25026                                editor.update(cx, |editor, cx| {
25027                                    let snapshot = editor.snapshot(window, cx);
25028                                    let point =
25029                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
25030                                    editor.go_to_hunk_before_or_after_position(
25031                                        &snapshot,
25032                                        point,
25033                                        Direction::Prev,
25034                                        window,
25035                                        cx,
25036                                    );
25037                                    editor.expand_selected_diff_hunks(cx);
25038                                });
25039                            }
25040                        }),
25041                )
25042            },
25043        )
25044        .into_any_element()
25045}
25046
25047pub fn multibuffer_context_lines(cx: &App) -> u32 {
25048    EditorSettings::try_get(cx)
25049        .map(|settings| settings.excerpt_context_lines)
25050        .unwrap_or(2)
25051        .min(32)
25052}