editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//!
   11//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   12//!
   13//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   14pub mod actions;
   15mod blink_manager;
   16mod bracket_colorization;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod element;
   22mod git;
   23mod highlight_matching_bracket;
   24mod hover_links;
   25pub mod hover_popover;
   26mod indent_guides;
   27mod inlays;
   28pub mod items;
   29mod jsx_tag_auto_close;
   30mod linked_editing_ranges;
   31mod lsp_colors;
   32mod lsp_ext;
   33mod mouse_context_menu;
   34pub mod movement;
   35mod persistence;
   36mod rust_analyzer_ext;
   37pub mod scroll;
   38mod selections_collection;
   39pub mod tasks;
   40
   41#[cfg(test)]
   42mod code_completion_tests;
   43#[cfg(test)]
   44mod edit_prediction_tests;
   45#[cfg(test)]
   46mod editor_tests;
   47mod signature_help;
   48#[cfg(any(test, feature = "test-support"))]
   49pub mod test;
   50
   51pub(crate) use actions::*;
   52pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   53pub use edit_prediction::Direction;
   54pub use editor_settings::{
   55    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   56    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
   57};
   58pub use element::{
   59    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   60};
   61pub use git::blame::BlameRenderer;
   62pub use hover_popover::hover_markdown_style;
   63pub use inlays::Inlay;
   64pub use items::MAX_TAB_TITLE_LEN;
   65pub use lsp::CompletionContext;
   66pub use lsp_ext::lsp_tasks;
   67pub use multi_buffer::{
   68    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
   69    RowInfo, ToOffset, ToPoint,
   70};
   71pub use text::Bias;
   72
   73use ::git::{
   74    Restore,
   75    blame::{BlameEntry, ParsedCommitMessage},
   76    status::FileStatus,
   77};
   78use aho_corasick::AhoCorasick;
   79use anyhow::{Context as _, Result, anyhow};
   80use blink_manager::BlinkManager;
   81use buffer_diff::DiffHunkStatus;
   82use client::{Collaborator, ParticipantIndex, parse_zed_link};
   83use clock::ReplicaId;
   84use code_context_menus::{
   85    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   86    CompletionsMenu, ContextMenuOrigin,
   87};
   88use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   89use convert_case::{Case, Casing};
   90use dap::TelemetrySpawnLocation;
   91use display_map::*;
   92use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};
   93use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   94use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   95use futures::{
   96    FutureExt, StreamExt as _,
   97    future::{self, Shared, join},
   98    stream::FuturesUnordered,
   99};
  100use fuzzy::{StringMatch, StringMatchCandidate};
  101use git::blame::{GitBlame, GlobalBlameRenderer};
  102use gpui::{
  103    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  104    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  105    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  106    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  107    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
  108    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
  109    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
  110    div, point, prelude::*, pulsating_between, px, relative, size,
  111};
  112use hover_links::{HoverLink, HoveredLinkState, find_file};
  113use hover_popover::{HoverState, hide_hover};
  114use indent_guides::ActiveIndentGuidesState;
  115use inlays::{InlaySplice, inlay_hints::InlayHintRefreshReason};
  116use itertools::{Either, Itertools};
  117use language::{
  118    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  119    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  120    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  121    IndentSize, Language, OffsetRangeExt, Point, Runnable, RunnableRange, Selection, SelectionGoal,
  122    TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  123    language_settings::{
  124        self, LspInsertMode, RewrapBehavior, WordsCompletionMode, all_language_settings,
  125        language_settings,
  126    },
  127    point_from_lsp, point_to_lsp, text_diff_with_options,
  128};
  129use linked_editing_ranges::refresh_linked_ranges;
  130use lsp::{
  131    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  132    LanguageServerId,
  133};
  134use lsp_colors::LspColorData;
  135use markdown::Markdown;
  136use mouse_context_menu::MouseContextMenu;
  137use movement::TextLayoutDetails;
  138use multi_buffer::{
  139    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  140};
  141use parking_lot::Mutex;
  142use persistence::DB;
  143use project::{
  144    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  145    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, InlayId,
  146    InvalidationStrategy, Location, LocationLink, PrepareRenameResponse, Project, ProjectItem,
  147    ProjectPath, ProjectTransaction, TaskSourceKind,
  148    debugger::{
  149        breakpoint_store::{
  150            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  151            BreakpointStore, BreakpointStoreEvent,
  152        },
  153        session::{Session, SessionEvent},
  154    },
  155    git_store::GitStoreEvent,
  156    lsp_store::{
  157        CacheInlayHints, CompletionDocumentation, FormatTrigger, LspFormatTarget,
  158        OpenLspBufferHandle,
  159    },
  160    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  161};
  162use rand::seq::SliceRandom;
  163use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  164use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  165use selections_collection::{MutableSelectionsCollection, SelectionsCollection};
  166use serde::{Deserialize, Serialize};
  167use settings::{
  168    GitGutterSetting, RelativeLineNumbers, Settings, SettingsLocation, SettingsStore,
  169    update_settings_file,
  170};
  171use smallvec::{SmallVec, smallvec};
  172use snippet::Snippet;
  173use std::{
  174    any::{Any, TypeId},
  175    borrow::Cow,
  176    cell::{OnceCell, RefCell},
  177    cmp::{self, Ordering, Reverse},
  178    iter::{self, Peekable},
  179    mem,
  180    num::NonZeroU32,
  181    ops::{Deref, DerefMut, Not, Range, RangeInclusive},
  182    path::{Path, PathBuf},
  183    rc::Rc,
  184    sync::Arc,
  185    time::{Duration, Instant},
  186};
  187use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  188use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
  189use theme::{
  190    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  191    observe_buffer_font_size_adjustment,
  192};
  193use ui::{
  194    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  195    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  196};
  197use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  198use workspace::{
  199    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  200    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  201    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  202    item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  203    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  204    searchable::SearchEvent,
  205};
  206
  207use crate::{
  208    code_context_menus::CompletionsMenuSource,
  209    editor_settings::MultiCursorModifier,
  210    hover_links::{find_url, find_url_from_range},
  211    inlays::{
  212        InlineValueCache,
  213        inlay_hints::{LspInlayHintData, inlay_hint_settings},
  214    },
  215    scroll::{ScrollOffset, ScrollPixelOffset},
  216    selections_collection::resolve_selections_wrapping_blocks,
  217    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  218};
  219
  220pub const FILE_HEADER_HEIGHT: u32 = 2;
  221pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  222const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  223const MAX_LINE_LEN: usize = 1024;
  224const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  225const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  226pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  227#[doc(hidden)]
  228pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  229pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  230
  231pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  232pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  233pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  234pub const FETCH_COLORS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(150);
  235
  236pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  237pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  238pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  239
  240pub type RenderDiffHunkControlsFn = Arc<
  241    dyn Fn(
  242        u32,
  243        &DiffHunkStatus,
  244        Range<Anchor>,
  245        bool,
  246        Pixels,
  247        &Entity<Editor>,
  248        &mut Window,
  249        &mut App,
  250    ) -> AnyElement,
  251>;
  252
  253enum ReportEditorEvent {
  254    Saved { auto_saved: bool },
  255    EditorOpened,
  256    Closed,
  257}
  258
  259impl ReportEditorEvent {
  260    pub fn event_type(&self) -> &'static str {
  261        match self {
  262            Self::Saved { .. } => "Editor Saved",
  263            Self::EditorOpened => "Editor Opened",
  264            Self::Closed => "Editor Closed",
  265        }
  266    }
  267}
  268
  269pub enum ActiveDebugLine {}
  270pub enum DebugStackFrameLine {}
  271enum DocumentHighlightRead {}
  272enum DocumentHighlightWrite {}
  273enum InputComposition {}
  274pub enum PendingInput {}
  275enum SelectedTextHighlight {}
  276
  277pub enum ConflictsOuter {}
  278pub enum ConflictsOurs {}
  279pub enum ConflictsTheirs {}
  280pub enum ConflictsOursMarker {}
  281pub enum ConflictsTheirsMarker {}
  282
  283#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  284pub enum Navigated {
  285    Yes,
  286    No,
  287}
  288
  289impl Navigated {
  290    pub fn from_bool(yes: bool) -> Navigated {
  291        if yes { Navigated::Yes } else { Navigated::No }
  292    }
  293}
  294
  295#[derive(Debug, Clone, PartialEq, Eq)]
  296enum DisplayDiffHunk {
  297    Folded {
  298        display_row: DisplayRow,
  299    },
  300    Unfolded {
  301        is_created_file: bool,
  302        diff_base_byte_range: Range<usize>,
  303        display_row_range: Range<DisplayRow>,
  304        multi_buffer_range: Range<Anchor>,
  305        status: DiffHunkStatus,
  306    },
  307}
  308
  309pub enum HideMouseCursorOrigin {
  310    TypingAction,
  311    MovementAction,
  312}
  313
  314pub fn init_settings(cx: &mut App) {
  315    EditorSettings::register(cx);
  316}
  317
  318pub fn init(cx: &mut App) {
  319    init_settings(cx);
  320
  321    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  322
  323    workspace::register_project_item::<Editor>(cx);
  324    workspace::FollowableViewRegistry::register::<Editor>(cx);
  325    workspace::register_serializable_item::<Editor>(cx);
  326
  327    cx.observe_new(
  328        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  329            workspace.register_action(Editor::new_file);
  330            workspace.register_action(Editor::new_file_split);
  331            workspace.register_action(Editor::new_file_vertical);
  332            workspace.register_action(Editor::new_file_horizontal);
  333            workspace.register_action(Editor::cancel_language_server_work);
  334            workspace.register_action(Editor::toggle_focus);
  335        },
  336    )
  337    .detach();
  338
  339    cx.on_action(move |_: &workspace::NewFile, cx| {
  340        let app_state = workspace::AppState::global(cx);
  341        if let Some(app_state) = app_state.upgrade() {
  342            workspace::open_new(
  343                Default::default(),
  344                app_state,
  345                cx,
  346                |workspace, window, cx| {
  347                    Editor::new_file(workspace, &Default::default(), window, cx)
  348                },
  349            )
  350            .detach();
  351        }
  352    });
  353    cx.on_action(move |_: &workspace::NewWindow, cx| {
  354        let app_state = workspace::AppState::global(cx);
  355        if let Some(app_state) = app_state.upgrade() {
  356            workspace::open_new(
  357                Default::default(),
  358                app_state,
  359                cx,
  360                |workspace, window, cx| {
  361                    cx.activate(true);
  362                    Editor::new_file(workspace, &Default::default(), window, cx)
  363                },
  364            )
  365            .detach();
  366        }
  367    });
  368}
  369
  370pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  371    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  372}
  373
  374pub trait DiagnosticRenderer {
  375    fn render_group(
  376        &self,
  377        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  378        buffer_id: BufferId,
  379        snapshot: EditorSnapshot,
  380        editor: WeakEntity<Editor>,
  381        cx: &mut App,
  382    ) -> Vec<BlockProperties<Anchor>>;
  383
  384    fn render_hover(
  385        &self,
  386        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  387        range: Range<Point>,
  388        buffer_id: BufferId,
  389        cx: &mut App,
  390    ) -> Option<Entity<markdown::Markdown>>;
  391
  392    fn open_link(
  393        &self,
  394        editor: &mut Editor,
  395        link: SharedString,
  396        window: &mut Window,
  397        cx: &mut Context<Editor>,
  398    );
  399}
  400
  401pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  402
  403impl GlobalDiagnosticRenderer {
  404    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  405        cx.try_global::<Self>().map(|g| g.0.clone())
  406    }
  407}
  408
  409impl gpui::Global for GlobalDiagnosticRenderer {}
  410pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  411    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  412}
  413
  414pub struct SearchWithinRange;
  415
  416trait InvalidationRegion {
  417    fn ranges(&self) -> &[Range<Anchor>];
  418}
  419
  420#[derive(Clone, Debug, PartialEq)]
  421pub enum SelectPhase {
  422    Begin {
  423        position: DisplayPoint,
  424        add: bool,
  425        click_count: usize,
  426    },
  427    BeginColumnar {
  428        position: DisplayPoint,
  429        reset: bool,
  430        mode: ColumnarMode,
  431        goal_column: u32,
  432    },
  433    Extend {
  434        position: DisplayPoint,
  435        click_count: usize,
  436    },
  437    Update {
  438        position: DisplayPoint,
  439        goal_column: u32,
  440        scroll_delta: gpui::Point<f32>,
  441    },
  442    End,
  443}
  444
  445#[derive(Clone, Debug, PartialEq)]
  446pub enum ColumnarMode {
  447    FromMouse,
  448    FromSelection,
  449}
  450
  451#[derive(Clone, Debug)]
  452pub enum SelectMode {
  453    Character,
  454    Word(Range<Anchor>),
  455    Line(Range<Anchor>),
  456    All,
  457}
  458
  459#[derive(Copy, Clone, Default, PartialEq, Eq, Debug)]
  460pub enum SizingBehavior {
  461    /// The editor will layout itself using `size_full` and will include the vertical
  462    /// scroll margin as requested by user settings.
  463    #[default]
  464    Default,
  465    /// The editor will layout itself using `size_full`, but will not have any
  466    /// vertical overscroll.
  467    ExcludeOverscrollMargin,
  468    /// The editor will request a vertical size according to its content and will be
  469    /// layouted without a vertical scroll margin.
  470    SizeByContent,
  471}
  472
  473#[derive(Clone, PartialEq, Eq, Debug)]
  474pub enum EditorMode {
  475    SingleLine,
  476    AutoHeight {
  477        min_lines: usize,
  478        max_lines: Option<usize>,
  479    },
  480    Full {
  481        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  482        scale_ui_elements_with_buffer_font_size: bool,
  483        /// When set to `true`, the editor will render a background for the active line.
  484        show_active_line_background: bool,
  485        /// Determines the sizing behavior for this editor
  486        sizing_behavior: SizingBehavior,
  487    },
  488    Minimap {
  489        parent: WeakEntity<Editor>,
  490    },
  491}
  492
  493impl EditorMode {
  494    pub fn full() -> Self {
  495        Self::Full {
  496            scale_ui_elements_with_buffer_font_size: true,
  497            show_active_line_background: true,
  498            sizing_behavior: SizingBehavior::Default,
  499        }
  500    }
  501
  502    #[inline]
  503    pub fn is_full(&self) -> bool {
  504        matches!(self, Self::Full { .. })
  505    }
  506
  507    #[inline]
  508    pub fn is_single_line(&self) -> bool {
  509        matches!(self, Self::SingleLine { .. })
  510    }
  511
  512    #[inline]
  513    fn is_minimap(&self) -> bool {
  514        matches!(self, Self::Minimap { .. })
  515    }
  516}
  517
  518#[derive(Copy, Clone, Debug)]
  519pub enum SoftWrap {
  520    /// Prefer not to wrap at all.
  521    ///
  522    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  523    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  524    GitDiff,
  525    /// Prefer a single line generally, unless an overly long line is encountered.
  526    None,
  527    /// Soft wrap lines that exceed the editor width.
  528    EditorWidth,
  529    /// Soft wrap lines at the preferred line length.
  530    Column(u32),
  531    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  532    Bounded(u32),
  533}
  534
  535#[derive(Clone)]
  536pub struct EditorStyle {
  537    pub background: Hsla,
  538    pub border: Hsla,
  539    pub local_player: PlayerColor,
  540    pub text: TextStyle,
  541    pub scrollbar_width: Pixels,
  542    pub syntax: Arc<SyntaxTheme>,
  543    pub status: StatusColors,
  544    pub inlay_hints_style: HighlightStyle,
  545    pub edit_prediction_styles: EditPredictionStyles,
  546    pub unnecessary_code_fade: f32,
  547    pub show_underlines: bool,
  548}
  549
  550impl Default for EditorStyle {
  551    fn default() -> Self {
  552        Self {
  553            background: Hsla::default(),
  554            border: Hsla::default(),
  555            local_player: PlayerColor::default(),
  556            text: TextStyle::default(),
  557            scrollbar_width: Pixels::default(),
  558            syntax: Default::default(),
  559            // HACK: Status colors don't have a real default.
  560            // We should look into removing the status colors from the editor
  561            // style and retrieve them directly from the theme.
  562            status: StatusColors::dark(),
  563            inlay_hints_style: HighlightStyle::default(),
  564            edit_prediction_styles: EditPredictionStyles {
  565                insertion: HighlightStyle::default(),
  566                whitespace: HighlightStyle::default(),
  567            },
  568            unnecessary_code_fade: Default::default(),
  569            show_underlines: true,
  570        }
  571    }
  572}
  573
  574pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  575    let show_background = language_settings::language_settings(None, None, cx)
  576        .inlay_hints
  577        .show_background;
  578
  579    let mut style = cx.theme().syntax().get("hint");
  580
  581    if style.color.is_none() {
  582        style.color = Some(cx.theme().status().hint);
  583    }
  584
  585    if !show_background {
  586        style.background_color = None;
  587        return style;
  588    }
  589
  590    if style.background_color.is_none() {
  591        style.background_color = Some(cx.theme().status().hint_background);
  592    }
  593
  594    style
  595}
  596
  597pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  598    EditPredictionStyles {
  599        insertion: HighlightStyle {
  600            color: Some(cx.theme().status().predictive),
  601            ..HighlightStyle::default()
  602        },
  603        whitespace: HighlightStyle {
  604            background_color: Some(cx.theme().status().created_background),
  605            ..HighlightStyle::default()
  606        },
  607    }
  608}
  609
  610type CompletionId = usize;
  611
  612pub(crate) enum EditDisplayMode {
  613    TabAccept,
  614    DiffPopover,
  615    Inline,
  616}
  617
  618enum EditPrediction {
  619    Edit {
  620        edits: Vec<(Range<Anchor>, String)>,
  621        edit_preview: Option<EditPreview>,
  622        display_mode: EditDisplayMode,
  623        snapshot: BufferSnapshot,
  624    },
  625    /// Move to a specific location in the active editor
  626    MoveWithin {
  627        target: Anchor,
  628        snapshot: BufferSnapshot,
  629    },
  630    /// Move to a specific location in a different editor (not the active one)
  631    MoveOutside {
  632        target: language::Anchor,
  633        snapshot: BufferSnapshot,
  634    },
  635}
  636
  637struct EditPredictionState {
  638    inlay_ids: Vec<InlayId>,
  639    completion: EditPrediction,
  640    completion_id: Option<SharedString>,
  641    invalidation_range: Option<Range<Anchor>>,
  642}
  643
  644enum EditPredictionSettings {
  645    Disabled,
  646    Enabled {
  647        show_in_menu: bool,
  648        preview_requires_modifier: bool,
  649    },
  650}
  651
  652enum EditPredictionHighlight {}
  653
  654#[derive(Debug, Clone)]
  655struct InlineDiagnostic {
  656    message: SharedString,
  657    group_id: usize,
  658    is_primary: bool,
  659    start: Point,
  660    severity: lsp::DiagnosticSeverity,
  661}
  662
  663pub enum MenuEditPredictionsPolicy {
  664    Never,
  665    ByProvider,
  666}
  667
  668pub enum EditPredictionPreview {
  669    /// Modifier is not pressed
  670    Inactive { released_too_fast: bool },
  671    /// Modifier pressed
  672    Active {
  673        since: Instant,
  674        previous_scroll_position: Option<ScrollAnchor>,
  675    },
  676}
  677
  678impl EditPredictionPreview {
  679    pub fn released_too_fast(&self) -> bool {
  680        match self {
  681            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  682            EditPredictionPreview::Active { .. } => false,
  683        }
  684    }
  685
  686    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  687        if let EditPredictionPreview::Active {
  688            previous_scroll_position,
  689            ..
  690        } = self
  691        {
  692            *previous_scroll_position = scroll_position;
  693        }
  694    }
  695}
  696
  697pub struct ContextMenuOptions {
  698    pub min_entries_visible: usize,
  699    pub max_entries_visible: usize,
  700    pub placement: Option<ContextMenuPlacement>,
  701}
  702
  703#[derive(Debug, Clone, PartialEq, Eq)]
  704pub enum ContextMenuPlacement {
  705    Above,
  706    Below,
  707}
  708
  709#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  710struct EditorActionId(usize);
  711
  712impl EditorActionId {
  713    pub fn post_inc(&mut self) -> Self {
  714        let answer = self.0;
  715
  716        *self = Self(answer + 1);
  717
  718        Self(answer)
  719    }
  720}
  721
  722// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  723// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  724
  725type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  726type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  727
  728#[derive(Default)]
  729struct ScrollbarMarkerState {
  730    scrollbar_size: Size<Pixels>,
  731    dirty: bool,
  732    markers: Arc<[PaintQuad]>,
  733    pending_refresh: Option<Task<Result<()>>>,
  734}
  735
  736impl ScrollbarMarkerState {
  737    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  738        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  739    }
  740}
  741
  742#[derive(Clone, Copy, PartialEq, Eq)]
  743pub enum MinimapVisibility {
  744    Disabled,
  745    Enabled {
  746        /// The configuration currently present in the users settings.
  747        setting_configuration: bool,
  748        /// Whether to override the currently set visibility from the users setting.
  749        toggle_override: bool,
  750    },
  751}
  752
  753impl MinimapVisibility {
  754    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  755        if mode.is_full() {
  756            Self::Enabled {
  757                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  758                toggle_override: false,
  759            }
  760        } else {
  761            Self::Disabled
  762        }
  763    }
  764
  765    fn hidden(&self) -> Self {
  766        match *self {
  767            Self::Enabled {
  768                setting_configuration,
  769                ..
  770            } => Self::Enabled {
  771                setting_configuration,
  772                toggle_override: setting_configuration,
  773            },
  774            Self::Disabled => Self::Disabled,
  775        }
  776    }
  777
  778    fn disabled(&self) -> bool {
  779        matches!(*self, Self::Disabled)
  780    }
  781
  782    fn settings_visibility(&self) -> bool {
  783        match *self {
  784            Self::Enabled {
  785                setting_configuration,
  786                ..
  787            } => setting_configuration,
  788            _ => false,
  789        }
  790    }
  791
  792    fn visible(&self) -> bool {
  793        match *self {
  794            Self::Enabled {
  795                setting_configuration,
  796                toggle_override,
  797            } => setting_configuration ^ toggle_override,
  798            _ => false,
  799        }
  800    }
  801
  802    fn toggle_visibility(&self) -> Self {
  803        match *self {
  804            Self::Enabled {
  805                toggle_override,
  806                setting_configuration,
  807            } => Self::Enabled {
  808                setting_configuration,
  809                toggle_override: !toggle_override,
  810            },
  811            Self::Disabled => Self::Disabled,
  812        }
  813    }
  814}
  815
  816#[derive(Debug, Clone, Copy, PartialEq, Eq)]
  817pub enum BufferSerialization {
  818    All,
  819    NonDirtyBuffers,
  820}
  821
  822impl BufferSerialization {
  823    fn new(restore_unsaved_buffers: bool) -> Self {
  824        if restore_unsaved_buffers {
  825            Self::All
  826        } else {
  827            Self::NonDirtyBuffers
  828        }
  829    }
  830}
  831
  832#[derive(Clone, Debug)]
  833struct RunnableTasks {
  834    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  835    offset: multi_buffer::Anchor,
  836    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  837    column: u32,
  838    // Values of all named captures, including those starting with '_'
  839    extra_variables: HashMap<String, String>,
  840    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  841    context_range: Range<BufferOffset>,
  842}
  843
  844impl RunnableTasks {
  845    fn resolve<'a>(
  846        &'a self,
  847        cx: &'a task::TaskContext,
  848    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  849        self.templates.iter().filter_map(|(kind, template)| {
  850            template
  851                .resolve_task(&kind.to_id_base(), cx)
  852                .map(|task| (kind.clone(), task))
  853        })
  854    }
  855}
  856
  857#[derive(Clone)]
  858pub struct ResolvedTasks {
  859    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  860    position: Anchor,
  861}
  862
  863#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  864struct BufferOffset(usize);
  865
  866/// Addons allow storing per-editor state in other crates (e.g. Vim)
  867pub trait Addon: 'static {
  868    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  869
  870    fn render_buffer_header_controls(
  871        &self,
  872        _: &ExcerptInfo,
  873        _: &Window,
  874        _: &App,
  875    ) -> Option<AnyElement> {
  876        None
  877    }
  878
  879    fn override_status_for_buffer_id(&self, _: BufferId, _: &App) -> Option<FileStatus> {
  880        None
  881    }
  882
  883    fn to_any(&self) -> &dyn std::any::Any;
  884
  885    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  886        None
  887    }
  888}
  889
  890struct ChangeLocation {
  891    current: Option<Vec<Anchor>>,
  892    original: Vec<Anchor>,
  893}
  894impl ChangeLocation {
  895    fn locations(&self) -> &[Anchor] {
  896        self.current.as_ref().unwrap_or(&self.original)
  897    }
  898}
  899
  900/// A set of caret positions, registered when the editor was edited.
  901pub struct ChangeList {
  902    changes: Vec<ChangeLocation>,
  903    /// Currently "selected" change.
  904    position: Option<usize>,
  905}
  906
  907impl ChangeList {
  908    pub fn new() -> Self {
  909        Self {
  910            changes: Vec::new(),
  911            position: None,
  912        }
  913    }
  914
  915    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  916    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  917    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  918        if self.changes.is_empty() {
  919            return None;
  920        }
  921
  922        let prev = self.position.unwrap_or(self.changes.len());
  923        let next = if direction == Direction::Prev {
  924            prev.saturating_sub(count)
  925        } else {
  926            (prev + count).min(self.changes.len() - 1)
  927        };
  928        self.position = Some(next);
  929        self.changes.get(next).map(|change| change.locations())
  930    }
  931
  932    /// Adds a new change to the list, resetting the change list position.
  933    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  934        self.position.take();
  935        if let Some(last) = self.changes.last_mut()
  936            && group
  937        {
  938            last.current = Some(new_positions)
  939        } else {
  940            self.changes.push(ChangeLocation {
  941                original: new_positions,
  942                current: None,
  943            });
  944        }
  945    }
  946
  947    pub fn last(&self) -> Option<&[Anchor]> {
  948        self.changes.last().map(|change| change.locations())
  949    }
  950
  951    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  952        self.changes.last().map(|change| change.original.as_slice())
  953    }
  954
  955    pub fn invert_last_group(&mut self) {
  956        if let Some(last) = self.changes.last_mut()
  957            && let Some(current) = last.current.as_mut()
  958        {
  959            mem::swap(&mut last.original, current);
  960        }
  961    }
  962}
  963
  964#[derive(Clone)]
  965struct InlineBlamePopoverState {
  966    scroll_handle: ScrollHandle,
  967    commit_message: Option<ParsedCommitMessage>,
  968    markdown: Entity<Markdown>,
  969}
  970
  971struct InlineBlamePopover {
  972    position: gpui::Point<Pixels>,
  973    hide_task: Option<Task<()>>,
  974    popover_bounds: Option<Bounds<Pixels>>,
  975    popover_state: InlineBlamePopoverState,
  976    keyboard_grace: bool,
  977}
  978
  979enum SelectionDragState {
  980    /// State when no drag related activity is detected.
  981    None,
  982    /// State when the mouse is down on a selection that is about to be dragged.
  983    ReadyToDrag {
  984        selection: Selection<Anchor>,
  985        click_position: gpui::Point<Pixels>,
  986        mouse_down_time: Instant,
  987    },
  988    /// State when the mouse is dragging the selection in the editor.
  989    Dragging {
  990        selection: Selection<Anchor>,
  991        drop_cursor: Selection<Anchor>,
  992        hide_drop_cursor: bool,
  993    },
  994}
  995
  996enum ColumnarSelectionState {
  997    FromMouse {
  998        selection_tail: Anchor,
  999        display_point: Option<DisplayPoint>,
 1000    },
 1001    FromSelection {
 1002        selection_tail: Anchor,
 1003    },
 1004}
 1005
 1006/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1007/// a breakpoint on them.
 1008#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1009struct PhantomBreakpointIndicator {
 1010    display_row: DisplayRow,
 1011    /// There's a small debounce between hovering over the line and showing the indicator.
 1012    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1013    is_active: bool,
 1014    collides_with_existing_breakpoint: bool,
 1015}
 1016
 1017/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1018///
 1019/// See the [module level documentation](self) for more information.
 1020pub struct Editor {
 1021    focus_handle: FocusHandle,
 1022    last_focused_descendant: Option<WeakFocusHandle>,
 1023    /// The text buffer being edited
 1024    buffer: Entity<MultiBuffer>,
 1025    /// Map of how text in the buffer should be displayed.
 1026    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1027    pub display_map: Entity<DisplayMap>,
 1028    placeholder_display_map: Option<Entity<DisplayMap>>,
 1029    pub selections: SelectionsCollection,
 1030    pub scroll_manager: ScrollManager,
 1031    /// When inline assist editors are linked, they all render cursors because
 1032    /// typing enters text into each of them, even the ones that aren't focused.
 1033    pub(crate) show_cursor_when_unfocused: bool,
 1034    columnar_selection_state: Option<ColumnarSelectionState>,
 1035    add_selections_state: Option<AddSelectionsState>,
 1036    select_next_state: Option<SelectNextState>,
 1037    select_prev_state: Option<SelectNextState>,
 1038    selection_history: SelectionHistory,
 1039    defer_selection_effects: bool,
 1040    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1041    autoclose_regions: Vec<AutocloseRegion>,
 1042    snippet_stack: InvalidationStack<SnippetState>,
 1043    select_syntax_node_history: SelectSyntaxNodeHistory,
 1044    ime_transaction: Option<TransactionId>,
 1045    pub diagnostics_max_severity: DiagnosticSeverity,
 1046    active_diagnostics: ActiveDiagnostic,
 1047    show_inline_diagnostics: bool,
 1048    inline_diagnostics_update: Task<()>,
 1049    inline_diagnostics_enabled: bool,
 1050    diagnostics_enabled: bool,
 1051    word_completions_enabled: bool,
 1052    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1053    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1054    hard_wrap: Option<usize>,
 1055    project: Option<Entity<Project>>,
 1056    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1057    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1058    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1059    blink_manager: Entity<BlinkManager>,
 1060    show_cursor_names: bool,
 1061    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1062    pub show_local_selections: bool,
 1063    mode: EditorMode,
 1064    show_breadcrumbs: bool,
 1065    show_gutter: bool,
 1066    show_scrollbars: ScrollbarAxes,
 1067    minimap_visibility: MinimapVisibility,
 1068    offset_content: bool,
 1069    disable_expand_excerpt_buttons: bool,
 1070    show_line_numbers: Option<bool>,
 1071    use_relative_line_numbers: Option<bool>,
 1072    show_git_diff_gutter: Option<bool>,
 1073    show_code_actions: Option<bool>,
 1074    show_runnables: Option<bool>,
 1075    show_breakpoints: Option<bool>,
 1076    show_wrap_guides: Option<bool>,
 1077    show_indent_guides: Option<bool>,
 1078    highlight_order: usize,
 1079    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1080    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1081    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1082    scrollbar_marker_state: ScrollbarMarkerState,
 1083    active_indent_guides_state: ActiveIndentGuidesState,
 1084    nav_history: Option<ItemNavHistory>,
 1085    context_menu: RefCell<Option<CodeContextMenu>>,
 1086    context_menu_options: Option<ContextMenuOptions>,
 1087    mouse_context_menu: Option<MouseContextMenu>,
 1088    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1089    inline_blame_popover: Option<InlineBlamePopover>,
 1090    inline_blame_popover_show_task: Option<Task<()>>,
 1091    signature_help_state: SignatureHelpState,
 1092    auto_signature_help: Option<bool>,
 1093    find_all_references_task_sources: Vec<Anchor>,
 1094    next_completion_id: CompletionId,
 1095    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1096    code_actions_task: Option<Task<Result<()>>>,
 1097    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1098    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1099    document_highlights_task: Option<Task<()>>,
 1100    linked_editing_range_task: Option<Task<Option<()>>>,
 1101    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1102    pending_rename: Option<RenameState>,
 1103    searchable: bool,
 1104    cursor_shape: CursorShape,
 1105    current_line_highlight: Option<CurrentLineHighlight>,
 1106    autoindent_mode: Option<AutoindentMode>,
 1107    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1108    input_enabled: bool,
 1109    use_modal_editing: bool,
 1110    read_only: bool,
 1111    leader_id: Option<CollaboratorId>,
 1112    remote_id: Option<ViewId>,
 1113    pub hover_state: HoverState,
 1114    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1115    gutter_hovered: bool,
 1116    hovered_link_state: Option<HoveredLinkState>,
 1117    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1118    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1119    active_edit_prediction: Option<EditPredictionState>,
 1120    /// Used to prevent flickering as the user types while the menu is open
 1121    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1122    edit_prediction_settings: EditPredictionSettings,
 1123    edit_predictions_hidden_for_vim_mode: bool,
 1124    show_edit_predictions_override: Option<bool>,
 1125    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1126    edit_prediction_preview: EditPredictionPreview,
 1127    edit_prediction_indent_conflict: bool,
 1128    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1129    next_inlay_id: usize,
 1130    next_color_inlay_id: usize,
 1131    _subscriptions: Vec<Subscription>,
 1132    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1133    gutter_dimensions: GutterDimensions,
 1134    style: Option<EditorStyle>,
 1135    text_style_refinement: Option<TextStyleRefinement>,
 1136    next_editor_action_id: EditorActionId,
 1137    editor_actions: Rc<
 1138        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1139    >,
 1140    use_autoclose: bool,
 1141    use_auto_surround: bool,
 1142    auto_replace_emoji_shortcode: bool,
 1143    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1144    show_git_blame_gutter: bool,
 1145    show_git_blame_inline: bool,
 1146    show_git_blame_inline_delay_task: Option<Task<()>>,
 1147    git_blame_inline_enabled: bool,
 1148    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1149    buffer_serialization: Option<BufferSerialization>,
 1150    show_selection_menu: Option<bool>,
 1151    blame: Option<Entity<GitBlame>>,
 1152    blame_subscription: Option<Subscription>,
 1153    custom_context_menu: Option<
 1154        Box<
 1155            dyn 'static
 1156                + Fn(
 1157                    &mut Self,
 1158                    DisplayPoint,
 1159                    &mut Window,
 1160                    &mut Context<Self>,
 1161                ) -> Option<Entity<ui::ContextMenu>>,
 1162        >,
 1163    >,
 1164    last_bounds: Option<Bounds<Pixels>>,
 1165    last_position_map: Option<Rc<PositionMap>>,
 1166    expect_bounds_change: Option<Bounds<Pixels>>,
 1167    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1168    tasks_update_task: Option<Task<()>>,
 1169    breakpoint_store: Option<Entity<BreakpointStore>>,
 1170    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1171    hovered_diff_hunk_row: Option<DisplayRow>,
 1172    pull_diagnostics_task: Task<()>,
 1173    in_project_search: bool,
 1174    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1175    breadcrumb_header: Option<String>,
 1176    focused_block: Option<FocusedBlock>,
 1177    next_scroll_position: NextScrollCursorCenterTopBottom,
 1178    addons: HashMap<TypeId, Box<dyn Addon>>,
 1179    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1180    load_diff_task: Option<Shared<Task<()>>>,
 1181    /// Whether we are temporarily displaying a diff other than git's
 1182    temporary_diff_override: bool,
 1183    selection_mark_mode: bool,
 1184    toggle_fold_multiple_buffers: Task<()>,
 1185    _scroll_cursor_center_top_bottom_task: Task<()>,
 1186    serialize_selections: Task<()>,
 1187    serialize_folds: Task<()>,
 1188    mouse_cursor_hidden: bool,
 1189    minimap: Option<Entity<Self>>,
 1190    hide_mouse_mode: HideMouseMode,
 1191    pub change_list: ChangeList,
 1192    inline_value_cache: InlineValueCache,
 1193    selection_drag_state: SelectionDragState,
 1194    colors: Option<LspColorData>,
 1195    post_scroll_update: Task<()>,
 1196    refresh_colors_task: Task<()>,
 1197    inlay_hints: Option<LspInlayHintData>,
 1198    folding_newlines: Task<()>,
 1199    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1200}
 1201
 1202fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1203    if debounce_ms > 0 {
 1204        Some(Duration::from_millis(debounce_ms))
 1205    } else {
 1206        None
 1207    }
 1208}
 1209
 1210#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1211enum NextScrollCursorCenterTopBottom {
 1212    #[default]
 1213    Center,
 1214    Top,
 1215    Bottom,
 1216}
 1217
 1218impl NextScrollCursorCenterTopBottom {
 1219    fn next(&self) -> Self {
 1220        match self {
 1221            Self::Center => Self::Top,
 1222            Self::Top => Self::Bottom,
 1223            Self::Bottom => Self::Center,
 1224        }
 1225    }
 1226}
 1227
 1228#[derive(Clone)]
 1229pub struct EditorSnapshot {
 1230    pub mode: EditorMode,
 1231    show_gutter: bool,
 1232    show_line_numbers: Option<bool>,
 1233    show_git_diff_gutter: Option<bool>,
 1234    show_code_actions: Option<bool>,
 1235    show_runnables: Option<bool>,
 1236    show_breakpoints: Option<bool>,
 1237    git_blame_gutter_max_author_length: Option<usize>,
 1238    pub display_snapshot: DisplaySnapshot,
 1239    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1240    is_focused: bool,
 1241    scroll_anchor: ScrollAnchor,
 1242    ongoing_scroll: OngoingScroll,
 1243    current_line_highlight: CurrentLineHighlight,
 1244    gutter_hovered: bool,
 1245}
 1246
 1247#[derive(Default, Debug, Clone, Copy)]
 1248pub struct GutterDimensions {
 1249    pub left_padding: Pixels,
 1250    pub right_padding: Pixels,
 1251    pub width: Pixels,
 1252    pub margin: Pixels,
 1253    pub git_blame_entries_width: Option<Pixels>,
 1254}
 1255
 1256impl GutterDimensions {
 1257    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1258        Self {
 1259            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1260            ..Default::default()
 1261        }
 1262    }
 1263
 1264    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1265        -cx.text_system().descent(font_id, font_size)
 1266    }
 1267    /// The full width of the space taken up by the gutter.
 1268    pub fn full_width(&self) -> Pixels {
 1269        self.margin + self.width
 1270    }
 1271
 1272    /// The width of the space reserved for the fold indicators,
 1273    /// use alongside 'justify_end' and `gutter_width` to
 1274    /// right align content with the line numbers
 1275    pub fn fold_area_width(&self) -> Pixels {
 1276        self.margin + self.right_padding
 1277    }
 1278}
 1279
 1280struct CharacterDimensions {
 1281    em_width: Pixels,
 1282    em_advance: Pixels,
 1283    line_height: Pixels,
 1284}
 1285
 1286#[derive(Debug)]
 1287pub struct RemoteSelection {
 1288    pub replica_id: ReplicaId,
 1289    pub selection: Selection<Anchor>,
 1290    pub cursor_shape: CursorShape,
 1291    pub collaborator_id: CollaboratorId,
 1292    pub line_mode: bool,
 1293    pub user_name: Option<SharedString>,
 1294    pub color: PlayerColor,
 1295}
 1296
 1297#[derive(Clone, Debug)]
 1298struct SelectionHistoryEntry {
 1299    selections: Arc<[Selection<Anchor>]>,
 1300    select_next_state: Option<SelectNextState>,
 1301    select_prev_state: Option<SelectNextState>,
 1302    add_selections_state: Option<AddSelectionsState>,
 1303}
 1304
 1305#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1306enum SelectionHistoryMode {
 1307    Normal,
 1308    Undoing,
 1309    Redoing,
 1310    Skipping,
 1311}
 1312
 1313#[derive(Clone, PartialEq, Eq, Hash)]
 1314struct HoveredCursor {
 1315    replica_id: ReplicaId,
 1316    selection_id: usize,
 1317}
 1318
 1319impl Default for SelectionHistoryMode {
 1320    fn default() -> Self {
 1321        Self::Normal
 1322    }
 1323}
 1324
 1325#[derive(Debug)]
 1326/// SelectionEffects controls the side-effects of updating the selection.
 1327///
 1328/// The default behaviour does "what you mostly want":
 1329/// - it pushes to the nav history if the cursor moved by >10 lines
 1330/// - it re-triggers completion requests
 1331/// - it scrolls to fit
 1332///
 1333/// You might want to modify these behaviours. For example when doing a "jump"
 1334/// like go to definition, we always want to add to nav history; but when scrolling
 1335/// in vim mode we never do.
 1336///
 1337/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1338/// move.
 1339#[derive(Clone)]
 1340pub struct SelectionEffects {
 1341    nav_history: Option<bool>,
 1342    completions: bool,
 1343    scroll: Option<Autoscroll>,
 1344}
 1345
 1346impl Default for SelectionEffects {
 1347    fn default() -> Self {
 1348        Self {
 1349            nav_history: None,
 1350            completions: true,
 1351            scroll: Some(Autoscroll::fit()),
 1352        }
 1353    }
 1354}
 1355impl SelectionEffects {
 1356    pub fn scroll(scroll: Autoscroll) -> Self {
 1357        Self {
 1358            scroll: Some(scroll),
 1359            ..Default::default()
 1360        }
 1361    }
 1362
 1363    pub fn no_scroll() -> Self {
 1364        Self {
 1365            scroll: None,
 1366            ..Default::default()
 1367        }
 1368    }
 1369
 1370    pub fn completions(self, completions: bool) -> Self {
 1371        Self {
 1372            completions,
 1373            ..self
 1374        }
 1375    }
 1376
 1377    pub fn nav_history(self, nav_history: bool) -> Self {
 1378        Self {
 1379            nav_history: Some(nav_history),
 1380            ..self
 1381        }
 1382    }
 1383}
 1384
 1385struct DeferredSelectionEffectsState {
 1386    changed: bool,
 1387    effects: SelectionEffects,
 1388    old_cursor_position: Anchor,
 1389    history_entry: SelectionHistoryEntry,
 1390}
 1391
 1392#[derive(Default)]
 1393struct SelectionHistory {
 1394    #[allow(clippy::type_complexity)]
 1395    selections_by_transaction:
 1396        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1397    mode: SelectionHistoryMode,
 1398    undo_stack: VecDeque<SelectionHistoryEntry>,
 1399    redo_stack: VecDeque<SelectionHistoryEntry>,
 1400}
 1401
 1402impl SelectionHistory {
 1403    #[track_caller]
 1404    fn insert_transaction(
 1405        &mut self,
 1406        transaction_id: TransactionId,
 1407        selections: Arc<[Selection<Anchor>]>,
 1408    ) {
 1409        if selections.is_empty() {
 1410            log::error!(
 1411                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1412                std::panic::Location::caller()
 1413            );
 1414            return;
 1415        }
 1416        self.selections_by_transaction
 1417            .insert(transaction_id, (selections, None));
 1418    }
 1419
 1420    #[allow(clippy::type_complexity)]
 1421    fn transaction(
 1422        &self,
 1423        transaction_id: TransactionId,
 1424    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1425        self.selections_by_transaction.get(&transaction_id)
 1426    }
 1427
 1428    #[allow(clippy::type_complexity)]
 1429    fn transaction_mut(
 1430        &mut self,
 1431        transaction_id: TransactionId,
 1432    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1433        self.selections_by_transaction.get_mut(&transaction_id)
 1434    }
 1435
 1436    fn push(&mut self, entry: SelectionHistoryEntry) {
 1437        if !entry.selections.is_empty() {
 1438            match self.mode {
 1439                SelectionHistoryMode::Normal => {
 1440                    self.push_undo(entry);
 1441                    self.redo_stack.clear();
 1442                }
 1443                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1444                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1445                SelectionHistoryMode::Skipping => {}
 1446            }
 1447        }
 1448    }
 1449
 1450    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1451        if self
 1452            .undo_stack
 1453            .back()
 1454            .is_none_or(|e| e.selections != entry.selections)
 1455        {
 1456            self.undo_stack.push_back(entry);
 1457            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1458                self.undo_stack.pop_front();
 1459            }
 1460        }
 1461    }
 1462
 1463    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1464        if self
 1465            .redo_stack
 1466            .back()
 1467            .is_none_or(|e| e.selections != entry.selections)
 1468        {
 1469            self.redo_stack.push_back(entry);
 1470            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1471                self.redo_stack.pop_front();
 1472            }
 1473        }
 1474    }
 1475}
 1476
 1477#[derive(Clone, Copy)]
 1478pub struct RowHighlightOptions {
 1479    pub autoscroll: bool,
 1480    pub include_gutter: bool,
 1481}
 1482
 1483impl Default for RowHighlightOptions {
 1484    fn default() -> Self {
 1485        Self {
 1486            autoscroll: Default::default(),
 1487            include_gutter: true,
 1488        }
 1489    }
 1490}
 1491
 1492struct RowHighlight {
 1493    index: usize,
 1494    range: Range<Anchor>,
 1495    color: Hsla,
 1496    options: RowHighlightOptions,
 1497    type_id: TypeId,
 1498}
 1499
 1500#[derive(Clone, Debug)]
 1501struct AddSelectionsState {
 1502    groups: Vec<AddSelectionsGroup>,
 1503}
 1504
 1505#[derive(Clone, Debug)]
 1506struct AddSelectionsGroup {
 1507    above: bool,
 1508    stack: Vec<usize>,
 1509}
 1510
 1511#[derive(Clone)]
 1512struct SelectNextState {
 1513    query: AhoCorasick,
 1514    wordwise: bool,
 1515    done: bool,
 1516}
 1517
 1518impl std::fmt::Debug for SelectNextState {
 1519    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1520        f.debug_struct(std::any::type_name::<Self>())
 1521            .field("wordwise", &self.wordwise)
 1522            .field("done", &self.done)
 1523            .finish()
 1524    }
 1525}
 1526
 1527#[derive(Debug)]
 1528struct AutocloseRegion {
 1529    selection_id: usize,
 1530    range: Range<Anchor>,
 1531    pair: BracketPair,
 1532}
 1533
 1534#[derive(Debug)]
 1535struct SnippetState {
 1536    ranges: Vec<Vec<Range<Anchor>>>,
 1537    active_index: usize,
 1538    choices: Vec<Option<Vec<String>>>,
 1539}
 1540
 1541#[doc(hidden)]
 1542pub struct RenameState {
 1543    pub range: Range<Anchor>,
 1544    pub old_name: Arc<str>,
 1545    pub editor: Entity<Editor>,
 1546    block_id: CustomBlockId,
 1547}
 1548
 1549struct InvalidationStack<T>(Vec<T>);
 1550
 1551struct RegisteredEditPredictionProvider {
 1552    provider: Arc<dyn EditPredictionProviderHandle>,
 1553    _subscription: Subscription,
 1554}
 1555
 1556#[derive(Debug, PartialEq, Eq)]
 1557pub struct ActiveDiagnosticGroup {
 1558    pub active_range: Range<Anchor>,
 1559    pub active_message: String,
 1560    pub group_id: usize,
 1561    pub blocks: HashSet<CustomBlockId>,
 1562}
 1563
 1564#[derive(Debug, PartialEq, Eq)]
 1565
 1566pub(crate) enum ActiveDiagnostic {
 1567    None,
 1568    All,
 1569    Group(ActiveDiagnosticGroup),
 1570}
 1571
 1572#[derive(Serialize, Deserialize, Clone, Debug)]
 1573pub struct ClipboardSelection {
 1574    /// The number of bytes in this selection.
 1575    pub len: usize,
 1576    /// Whether this was a full-line selection.
 1577    pub is_entire_line: bool,
 1578    /// The indentation of the first line when this content was originally copied.
 1579    pub first_line_indent: u32,
 1580}
 1581
 1582// selections, scroll behavior, was newest selection reversed
 1583type SelectSyntaxNodeHistoryState = (
 1584    Box<[Selection<usize>]>,
 1585    SelectSyntaxNodeScrollBehavior,
 1586    bool,
 1587);
 1588
 1589#[derive(Default)]
 1590struct SelectSyntaxNodeHistory {
 1591    stack: Vec<SelectSyntaxNodeHistoryState>,
 1592    // disable temporarily to allow changing selections without losing the stack
 1593    pub disable_clearing: bool,
 1594}
 1595
 1596impl SelectSyntaxNodeHistory {
 1597    pub fn try_clear(&mut self) {
 1598        if !self.disable_clearing {
 1599            self.stack.clear();
 1600        }
 1601    }
 1602
 1603    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1604        self.stack.push(selection);
 1605    }
 1606
 1607    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1608        self.stack.pop()
 1609    }
 1610}
 1611
 1612enum SelectSyntaxNodeScrollBehavior {
 1613    CursorTop,
 1614    FitSelection,
 1615    CursorBottom,
 1616}
 1617
 1618#[derive(Debug)]
 1619pub(crate) struct NavigationData {
 1620    cursor_anchor: Anchor,
 1621    cursor_position: Point,
 1622    scroll_anchor: ScrollAnchor,
 1623    scroll_top_row: u32,
 1624}
 1625
 1626#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1627pub enum GotoDefinitionKind {
 1628    Symbol,
 1629    Declaration,
 1630    Type,
 1631    Implementation,
 1632}
 1633
 1634pub enum FormatTarget {
 1635    Buffers(HashSet<Entity<Buffer>>),
 1636    Ranges(Vec<Range<MultiBufferPoint>>),
 1637}
 1638
 1639pub(crate) struct FocusedBlock {
 1640    id: BlockId,
 1641    focus_handle: WeakFocusHandle,
 1642}
 1643
 1644#[derive(Clone)]
 1645enum JumpData {
 1646    MultiBufferRow {
 1647        row: MultiBufferRow,
 1648        line_offset_from_top: u32,
 1649    },
 1650    MultiBufferPoint {
 1651        excerpt_id: ExcerptId,
 1652        position: Point,
 1653        anchor: text::Anchor,
 1654        line_offset_from_top: u32,
 1655    },
 1656}
 1657
 1658pub enum MultibufferSelectionMode {
 1659    First,
 1660    All,
 1661}
 1662
 1663#[derive(Clone, Copy, Debug, Default)]
 1664pub struct RewrapOptions {
 1665    pub override_language_settings: bool,
 1666    pub preserve_existing_whitespace: bool,
 1667}
 1668
 1669impl Editor {
 1670    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1671        let buffer = cx.new(|cx| Buffer::local("", cx));
 1672        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1673        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1674    }
 1675
 1676    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1677        let buffer = cx.new(|cx| Buffer::local("", cx));
 1678        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1679        Self::new(EditorMode::full(), buffer, None, window, cx)
 1680    }
 1681
 1682    pub fn auto_height(
 1683        min_lines: usize,
 1684        max_lines: usize,
 1685        window: &mut Window,
 1686        cx: &mut Context<Self>,
 1687    ) -> Self {
 1688        let buffer = cx.new(|cx| Buffer::local("", cx));
 1689        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1690        Self::new(
 1691            EditorMode::AutoHeight {
 1692                min_lines,
 1693                max_lines: Some(max_lines),
 1694            },
 1695            buffer,
 1696            None,
 1697            window,
 1698            cx,
 1699        )
 1700    }
 1701
 1702    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1703    /// The editor grows as tall as needed to fit its content.
 1704    pub fn auto_height_unbounded(
 1705        min_lines: usize,
 1706        window: &mut Window,
 1707        cx: &mut Context<Self>,
 1708    ) -> Self {
 1709        let buffer = cx.new(|cx| Buffer::local("", cx));
 1710        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1711        Self::new(
 1712            EditorMode::AutoHeight {
 1713                min_lines,
 1714                max_lines: None,
 1715            },
 1716            buffer,
 1717            None,
 1718            window,
 1719            cx,
 1720        )
 1721    }
 1722
 1723    pub fn for_buffer(
 1724        buffer: Entity<Buffer>,
 1725        project: Option<Entity<Project>>,
 1726        window: &mut Window,
 1727        cx: &mut Context<Self>,
 1728    ) -> Self {
 1729        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1730        Self::new(EditorMode::full(), buffer, project, window, cx)
 1731    }
 1732
 1733    pub fn for_multibuffer(
 1734        buffer: Entity<MultiBuffer>,
 1735        project: Option<Entity<Project>>,
 1736        window: &mut Window,
 1737        cx: &mut Context<Self>,
 1738    ) -> Self {
 1739        Self::new(EditorMode::full(), buffer, project, window, cx)
 1740    }
 1741
 1742    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1743        let mut clone = Self::new(
 1744            self.mode.clone(),
 1745            self.buffer.clone(),
 1746            self.project.clone(),
 1747            window,
 1748            cx,
 1749        );
 1750        self.display_map.update(cx, |display_map, cx| {
 1751            let snapshot = display_map.snapshot(cx);
 1752            clone.display_map.update(cx, |display_map, cx| {
 1753                display_map.set_state(&snapshot, cx);
 1754            });
 1755        });
 1756        clone.folds_did_change(cx);
 1757        clone.selections.clone_state(&self.selections);
 1758        clone.scroll_manager.clone_state(&self.scroll_manager);
 1759        clone.searchable = self.searchable;
 1760        clone.read_only = self.read_only;
 1761        clone
 1762    }
 1763
 1764    pub fn new(
 1765        mode: EditorMode,
 1766        buffer: Entity<MultiBuffer>,
 1767        project: Option<Entity<Project>>,
 1768        window: &mut Window,
 1769        cx: &mut Context<Self>,
 1770    ) -> Self {
 1771        Editor::new_internal(mode, buffer, project, None, window, cx)
 1772    }
 1773
 1774    fn new_internal(
 1775        mode: EditorMode,
 1776        multi_buffer: Entity<MultiBuffer>,
 1777        project: Option<Entity<Project>>,
 1778        display_map: Option<Entity<DisplayMap>>,
 1779        window: &mut Window,
 1780        cx: &mut Context<Self>,
 1781    ) -> Self {
 1782        debug_assert!(
 1783            display_map.is_none() || mode.is_minimap(),
 1784            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1785        );
 1786
 1787        let full_mode = mode.is_full();
 1788        let is_minimap = mode.is_minimap();
 1789        let diagnostics_max_severity = if full_mode {
 1790            EditorSettings::get_global(cx)
 1791                .diagnostics_max_severity
 1792                .unwrap_or(DiagnosticSeverity::Hint)
 1793        } else {
 1794            DiagnosticSeverity::Off
 1795        };
 1796        let style = window.text_style();
 1797        let font_size = style.font_size.to_pixels(window.rem_size());
 1798        let editor = cx.entity().downgrade();
 1799        let fold_placeholder = FoldPlaceholder {
 1800            constrain_width: false,
 1801            render: Arc::new(move |fold_id, fold_range, cx| {
 1802                let editor = editor.clone();
 1803                div()
 1804                    .id(fold_id)
 1805                    .bg(cx.theme().colors().ghost_element_background)
 1806                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1807                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1808                    .rounded_xs()
 1809                    .size_full()
 1810                    .cursor_pointer()
 1811                    .child("")
 1812                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1813                    .on_click(move |_, _window, cx| {
 1814                        editor
 1815                            .update(cx, |editor, cx| {
 1816                                editor.unfold_ranges(
 1817                                    &[fold_range.start..fold_range.end],
 1818                                    true,
 1819                                    false,
 1820                                    cx,
 1821                                );
 1822                                cx.stop_propagation();
 1823                            })
 1824                            .ok();
 1825                    })
 1826                    .into_any()
 1827            }),
 1828            merge_adjacent: true,
 1829            ..FoldPlaceholder::default()
 1830        };
 1831        let display_map = display_map.unwrap_or_else(|| {
 1832            cx.new(|cx| {
 1833                DisplayMap::new(
 1834                    multi_buffer.clone(),
 1835                    style.font(),
 1836                    font_size,
 1837                    None,
 1838                    FILE_HEADER_HEIGHT,
 1839                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1840                    fold_placeholder,
 1841                    diagnostics_max_severity,
 1842                    cx,
 1843                )
 1844            })
 1845        });
 1846
 1847        let selections = SelectionsCollection::new(display_map.clone(), multi_buffer.clone());
 1848
 1849        let blink_manager = cx.new(|cx| {
 1850            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1851            if is_minimap {
 1852                blink_manager.disable(cx);
 1853            }
 1854            blink_manager
 1855        });
 1856
 1857        let soft_wrap_mode_override =
 1858            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1859
 1860        let mut project_subscriptions = Vec::new();
 1861        if full_mode && let Some(project) = project.as_ref() {
 1862            project_subscriptions.push(cx.subscribe_in(
 1863                project,
 1864                window,
 1865                |editor, _, event, window, cx| match event {
 1866                    project::Event::RefreshCodeLens => {
 1867                        // we always query lens with actions, without storing them, always refreshing them
 1868                    }
 1869                    project::Event::RefreshInlayHints {
 1870                        server_id,
 1871                        request_id,
 1872                    } => {
 1873                        editor.refresh_inlay_hints(
 1874                            InlayHintRefreshReason::RefreshRequested {
 1875                                server_id: *server_id,
 1876                                request_id: *request_id,
 1877                            },
 1878                            cx,
 1879                        );
 1880                    }
 1881                    project::Event::LanguageServerRemoved(..) => {
 1882                        if editor.tasks_update_task.is_none() {
 1883                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1884                        }
 1885                        editor.registered_buffers.clear();
 1886                        editor.register_visible_buffers(cx);
 1887                    }
 1888                    project::Event::LanguageServerAdded(..) => {
 1889                        if editor.tasks_update_task.is_none() {
 1890                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1891                        }
 1892                    }
 1893                    project::Event::SnippetEdit(id, snippet_edits) => {
 1894                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1895                            let focus_handle = editor.focus_handle(cx);
 1896                            if focus_handle.is_focused(window) {
 1897                                let snapshot = buffer.read(cx).snapshot();
 1898                                for (range, snippet) in snippet_edits {
 1899                                    let editor_range =
 1900                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1901                                    editor
 1902                                        .insert_snippet(
 1903                                            &[editor_range],
 1904                                            snippet.clone(),
 1905                                            window,
 1906                                            cx,
 1907                                        )
 1908                                        .ok();
 1909                                }
 1910                            }
 1911                        }
 1912                    }
 1913                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1914                        let buffer_id = *buffer_id;
 1915                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 1916                            editor.register_buffer(buffer_id, cx);
 1917                            editor.update_lsp_data(Some(buffer_id), window, cx);
 1918                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 1919                            refresh_linked_ranges(editor, window, cx);
 1920                            editor.refresh_code_actions(window, cx);
 1921                            editor.refresh_document_highlights(cx);
 1922                        }
 1923                    }
 1924
 1925                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 1926                        let Some(workspace) = editor.workspace() else {
 1927                            return;
 1928                        };
 1929                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1930                        else {
 1931                            return;
 1932                        };
 1933
 1934                        if active_editor.entity_id() == cx.entity_id() {
 1935                            let entity_id = cx.entity_id();
 1936                            workspace.update(cx, |this, cx| {
 1937                                this.panes_mut()
 1938                                    .iter_mut()
 1939                                    .filter(|pane| pane.entity_id() != entity_id)
 1940                                    .for_each(|p| {
 1941                                        p.update(cx, |pane, _| {
 1942                                            pane.nav_history_mut().rename_item(
 1943                                                entity_id,
 1944                                                project_path.clone(),
 1945                                                abs_path.clone().into(),
 1946                                            );
 1947                                        })
 1948                                    });
 1949                            });
 1950                            let edited_buffers_already_open = {
 1951                                let other_editors: Vec<Entity<Editor>> = workspace
 1952                                    .read(cx)
 1953                                    .panes()
 1954                                    .iter()
 1955                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1956                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1957                                    .collect();
 1958
 1959                                transaction.0.keys().all(|buffer| {
 1960                                    other_editors.iter().any(|editor| {
 1961                                        let multi_buffer = editor.read(cx).buffer();
 1962                                        multi_buffer.read(cx).is_singleton()
 1963                                            && multi_buffer.read(cx).as_singleton().map_or(
 1964                                                false,
 1965                                                |singleton| {
 1966                                                    singleton.entity_id() == buffer.entity_id()
 1967                                                },
 1968                                            )
 1969                                    })
 1970                                })
 1971                            };
 1972                            if !edited_buffers_already_open {
 1973                                let workspace = workspace.downgrade();
 1974                                let transaction = transaction.clone();
 1975                                cx.defer_in(window, move |_, window, cx| {
 1976                                    cx.spawn_in(window, async move |editor, cx| {
 1977                                        Self::open_project_transaction(
 1978                                            &editor,
 1979                                            workspace,
 1980                                            transaction,
 1981                                            "Rename".to_string(),
 1982                                            cx,
 1983                                        )
 1984                                        .await
 1985                                        .ok()
 1986                                    })
 1987                                    .detach();
 1988                                });
 1989                            }
 1990                        }
 1991                    }
 1992
 1993                    _ => {}
 1994                },
 1995            ));
 1996            if let Some(task_inventory) = project
 1997                .read(cx)
 1998                .task_store()
 1999                .read(cx)
 2000                .task_inventory()
 2001                .cloned()
 2002            {
 2003                project_subscriptions.push(cx.observe_in(
 2004                    &task_inventory,
 2005                    window,
 2006                    |editor, _, window, cx| {
 2007                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2008                    },
 2009                ));
 2010            };
 2011
 2012            project_subscriptions.push(cx.subscribe_in(
 2013                &project.read(cx).breakpoint_store(),
 2014                window,
 2015                |editor, _, event, window, cx| match event {
 2016                    BreakpointStoreEvent::ClearDebugLines => {
 2017                        editor.clear_row_highlights::<ActiveDebugLine>();
 2018                        editor.refresh_inline_values(cx);
 2019                    }
 2020                    BreakpointStoreEvent::SetDebugLine => {
 2021                        if editor.go_to_active_debug_line(window, cx) {
 2022                            cx.stop_propagation();
 2023                        }
 2024
 2025                        editor.refresh_inline_values(cx);
 2026                    }
 2027                    _ => {}
 2028                },
 2029            ));
 2030            let git_store = project.read(cx).git_store().clone();
 2031            let project = project.clone();
 2032            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2033                if let GitStoreEvent::RepositoryAdded = event {
 2034                    this.load_diff_task = Some(
 2035                        update_uncommitted_diff_for_buffer(
 2036                            cx.entity(),
 2037                            &project,
 2038                            this.buffer.read(cx).all_buffers(),
 2039                            this.buffer.clone(),
 2040                            cx,
 2041                        )
 2042                        .shared(),
 2043                    );
 2044                }
 2045            }));
 2046        }
 2047
 2048        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2049
 2050        let inlay_hint_settings =
 2051            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2052        let focus_handle = cx.focus_handle();
 2053        if !is_minimap {
 2054            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2055                .detach();
 2056            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2057                .detach();
 2058            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2059                .detach();
 2060            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2061                .detach();
 2062            cx.observe_pending_input(window, Self::observe_pending_input)
 2063                .detach();
 2064        }
 2065
 2066        let show_indent_guides =
 2067            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2068                Some(false)
 2069            } else {
 2070                None
 2071            };
 2072
 2073        let breakpoint_store = match (&mode, project.as_ref()) {
 2074            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2075            _ => None,
 2076        };
 2077
 2078        let mut code_action_providers = Vec::new();
 2079        let mut load_uncommitted_diff = None;
 2080        if let Some(project) = project.clone() {
 2081            load_uncommitted_diff = Some(
 2082                update_uncommitted_diff_for_buffer(
 2083                    cx.entity(),
 2084                    &project,
 2085                    multi_buffer.read(cx).all_buffers(),
 2086                    multi_buffer.clone(),
 2087                    cx,
 2088                )
 2089                .shared(),
 2090            );
 2091            code_action_providers.push(Rc::new(project) as Rc<_>);
 2092        }
 2093
 2094        let mut editor = Self {
 2095            focus_handle,
 2096            show_cursor_when_unfocused: false,
 2097            last_focused_descendant: None,
 2098            buffer: multi_buffer.clone(),
 2099            display_map: display_map.clone(),
 2100            placeholder_display_map: None,
 2101            selections,
 2102            scroll_manager: ScrollManager::new(cx),
 2103            columnar_selection_state: None,
 2104            add_selections_state: None,
 2105            select_next_state: None,
 2106            select_prev_state: None,
 2107            selection_history: SelectionHistory::default(),
 2108            defer_selection_effects: false,
 2109            deferred_selection_effects_state: None,
 2110            autoclose_regions: Vec::new(),
 2111            snippet_stack: InvalidationStack::default(),
 2112            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2113            ime_transaction: None,
 2114            active_diagnostics: ActiveDiagnostic::None,
 2115            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2116            inline_diagnostics_update: Task::ready(()),
 2117            inline_diagnostics: Vec::new(),
 2118            soft_wrap_mode_override,
 2119            diagnostics_max_severity,
 2120            hard_wrap: None,
 2121            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2122            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2123            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2124            project,
 2125            blink_manager: blink_manager.clone(),
 2126            show_local_selections: true,
 2127            show_scrollbars: ScrollbarAxes {
 2128                horizontal: full_mode,
 2129                vertical: full_mode,
 2130            },
 2131            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2132            offset_content: !matches!(mode, EditorMode::SingleLine),
 2133            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2134            show_gutter: full_mode,
 2135            show_line_numbers: (!full_mode).then_some(false),
 2136            use_relative_line_numbers: None,
 2137            disable_expand_excerpt_buttons: !full_mode,
 2138            show_git_diff_gutter: None,
 2139            show_code_actions: None,
 2140            show_runnables: None,
 2141            show_breakpoints: None,
 2142            show_wrap_guides: None,
 2143            show_indent_guides,
 2144            highlight_order: 0,
 2145            highlighted_rows: HashMap::default(),
 2146            background_highlights: HashMap::default(),
 2147            gutter_highlights: HashMap::default(),
 2148            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2149            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2150            nav_history: None,
 2151            context_menu: RefCell::new(None),
 2152            context_menu_options: None,
 2153            mouse_context_menu: None,
 2154            completion_tasks: Vec::new(),
 2155            inline_blame_popover: None,
 2156            inline_blame_popover_show_task: None,
 2157            signature_help_state: SignatureHelpState::default(),
 2158            auto_signature_help: None,
 2159            find_all_references_task_sources: Vec::new(),
 2160            next_completion_id: 0,
 2161            next_inlay_id: 0,
 2162            code_action_providers,
 2163            available_code_actions: None,
 2164            code_actions_task: None,
 2165            quick_selection_highlight_task: None,
 2166            debounced_selection_highlight_task: None,
 2167            document_highlights_task: None,
 2168            linked_editing_range_task: None,
 2169            pending_rename: None,
 2170            searchable: !is_minimap,
 2171            cursor_shape: EditorSettings::get_global(cx)
 2172                .cursor_shape
 2173                .unwrap_or_default(),
 2174            current_line_highlight: None,
 2175            autoindent_mode: Some(AutoindentMode::EachLine),
 2176
 2177            workspace: None,
 2178            input_enabled: !is_minimap,
 2179            use_modal_editing: full_mode,
 2180            read_only: is_minimap,
 2181            use_autoclose: true,
 2182            use_auto_surround: true,
 2183            auto_replace_emoji_shortcode: false,
 2184            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2185            leader_id: None,
 2186            remote_id: None,
 2187            hover_state: HoverState::default(),
 2188            pending_mouse_down: None,
 2189            hovered_link_state: None,
 2190            edit_prediction_provider: None,
 2191            active_edit_prediction: None,
 2192            stale_edit_prediction_in_menu: None,
 2193            edit_prediction_preview: EditPredictionPreview::Inactive {
 2194                released_too_fast: false,
 2195            },
 2196            inline_diagnostics_enabled: full_mode,
 2197            diagnostics_enabled: full_mode,
 2198            word_completions_enabled: full_mode,
 2199            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2200            gutter_hovered: false,
 2201            pixel_position_of_newest_cursor: None,
 2202            last_bounds: None,
 2203            last_position_map: None,
 2204            expect_bounds_change: None,
 2205            gutter_dimensions: GutterDimensions::default(),
 2206            style: None,
 2207            show_cursor_names: false,
 2208            hovered_cursors: HashMap::default(),
 2209            next_editor_action_id: EditorActionId::default(),
 2210            editor_actions: Rc::default(),
 2211            edit_predictions_hidden_for_vim_mode: false,
 2212            show_edit_predictions_override: None,
 2213            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2214            edit_prediction_settings: EditPredictionSettings::Disabled,
 2215            edit_prediction_indent_conflict: false,
 2216            edit_prediction_requires_modifier_in_indent_conflict: true,
 2217            custom_context_menu: None,
 2218            show_git_blame_gutter: false,
 2219            show_git_blame_inline: false,
 2220            show_selection_menu: None,
 2221            show_git_blame_inline_delay_task: None,
 2222            git_blame_inline_enabled: full_mode
 2223                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2224            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2225            buffer_serialization: is_minimap.not().then(|| {
 2226                BufferSerialization::new(
 2227                    ProjectSettings::get_global(cx)
 2228                        .session
 2229                        .restore_unsaved_buffers,
 2230                )
 2231            }),
 2232            blame: None,
 2233            blame_subscription: None,
 2234            tasks: BTreeMap::default(),
 2235
 2236            breakpoint_store,
 2237            gutter_breakpoint_indicator: (None, None),
 2238            hovered_diff_hunk_row: None,
 2239            _subscriptions: (!is_minimap)
 2240                .then(|| {
 2241                    vec![
 2242                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2243                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2244                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2245                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2246                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2247                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2248                        cx.observe_window_activation(window, |editor, window, cx| {
 2249                            let active = window.is_window_active();
 2250                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2251                                if active {
 2252                                    blink_manager.enable(cx);
 2253                                } else {
 2254                                    blink_manager.disable(cx);
 2255                                }
 2256                            });
 2257                            if active {
 2258                                editor.show_mouse_cursor(cx);
 2259                            }
 2260                        }),
 2261                    ]
 2262                })
 2263                .unwrap_or_default(),
 2264            tasks_update_task: None,
 2265            pull_diagnostics_task: Task::ready(()),
 2266            colors: None,
 2267            refresh_colors_task: Task::ready(()),
 2268            inlay_hints: None,
 2269            next_color_inlay_id: 0,
 2270            post_scroll_update: Task::ready(()),
 2271            linked_edit_ranges: Default::default(),
 2272            in_project_search: false,
 2273            previous_search_ranges: None,
 2274            breadcrumb_header: None,
 2275            focused_block: None,
 2276            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2277            addons: HashMap::default(),
 2278            registered_buffers: HashMap::default(),
 2279            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2280            selection_mark_mode: false,
 2281            toggle_fold_multiple_buffers: Task::ready(()),
 2282            serialize_selections: Task::ready(()),
 2283            serialize_folds: Task::ready(()),
 2284            text_style_refinement: None,
 2285            load_diff_task: load_uncommitted_diff,
 2286            temporary_diff_override: false,
 2287            mouse_cursor_hidden: false,
 2288            minimap: None,
 2289            hide_mouse_mode: EditorSettings::get_global(cx)
 2290                .hide_mouse
 2291                .unwrap_or_default(),
 2292            change_list: ChangeList::new(),
 2293            mode,
 2294            selection_drag_state: SelectionDragState::None,
 2295            folding_newlines: Task::ready(()),
 2296            lookup_key: None,
 2297        };
 2298
 2299        if is_minimap {
 2300            return editor;
 2301        }
 2302
 2303        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2304            editor
 2305                ._subscriptions
 2306                .push(cx.observe(breakpoints, |_, _, cx| {
 2307                    cx.notify();
 2308                }));
 2309        }
 2310        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2311        editor._subscriptions.extend(project_subscriptions);
 2312
 2313        editor._subscriptions.push(cx.subscribe_in(
 2314            &cx.entity(),
 2315            window,
 2316            |editor, _, e: &EditorEvent, window, cx| match e {
 2317                EditorEvent::ScrollPositionChanged { local, .. } => {
 2318                    if *local {
 2319                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2320                        editor.inline_blame_popover.take();
 2321                        let new_anchor = editor.scroll_manager.anchor();
 2322                        let snapshot = editor.snapshot(window, cx);
 2323                        editor.update_restoration_data(cx, move |data| {
 2324                            data.scroll_position = (
 2325                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2326                                new_anchor.offset,
 2327                            );
 2328                        });
 2329
 2330                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2331                            cx.background_executor()
 2332                                .timer(Duration::from_millis(50))
 2333                                .await;
 2334                            editor
 2335                                .update_in(cx, |editor, window, cx| {
 2336                                    editor.register_visible_buffers(cx);
 2337                                    editor.refresh_colors_for_visible_range(None, window, cx);
 2338                                    editor.refresh_inlay_hints(
 2339                                        InlayHintRefreshReason::NewLinesShown,
 2340                                        cx,
 2341                                    );
 2342                                })
 2343                                .ok();
 2344                        });
 2345                    }
 2346                    editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2347                        cx.background_executor()
 2348                            .timer(Duration::from_millis(50))
 2349                            .await;
 2350                        editor
 2351                            .update_in(cx, |editor, window, cx| {
 2352                                editor.register_visible_buffers(cx);
 2353                                editor.refresh_colors_for_visible_range(None, window, cx);
 2354                                editor
 2355                                    .refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 2356                                editor.colorize_brackets(cx);
 2357                            })
 2358                            .ok();
 2359                    });
 2360                }
 2361                EditorEvent::Edited { .. } => {
 2362                    if vim_flavor(cx).is_none() {
 2363                        let display_map = editor.display_snapshot(cx);
 2364                        let selections = editor.selections.all_adjusted_display(&display_map);
 2365                        let pop_state = editor
 2366                            .change_list
 2367                            .last()
 2368                            .map(|previous| {
 2369                                previous.len() == selections.len()
 2370                                    && previous.iter().enumerate().all(|(ix, p)| {
 2371                                        p.to_display_point(&display_map).row()
 2372                                            == selections[ix].head().row()
 2373                                    })
 2374                            })
 2375                            .unwrap_or(false);
 2376                        let new_positions = selections
 2377                            .into_iter()
 2378                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2379                            .collect();
 2380                        editor
 2381                            .change_list
 2382                            .push_to_change_list(pop_state, new_positions);
 2383                    }
 2384                }
 2385                _ => (),
 2386            },
 2387        ));
 2388
 2389        if let Some(dap_store) = editor
 2390            .project
 2391            .as_ref()
 2392            .map(|project| project.read(cx).dap_store())
 2393        {
 2394            let weak_editor = cx.weak_entity();
 2395
 2396            editor
 2397                ._subscriptions
 2398                .push(
 2399                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2400                        let session_entity = cx.entity();
 2401                        weak_editor
 2402                            .update(cx, |editor, cx| {
 2403                                editor._subscriptions.push(
 2404                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2405                                );
 2406                            })
 2407                            .ok();
 2408                    }),
 2409                );
 2410
 2411            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2412                editor
 2413                    ._subscriptions
 2414                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2415            }
 2416        }
 2417
 2418        // skip adding the initial selection to selection history
 2419        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2420        editor.end_selection(window, cx);
 2421        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2422
 2423        editor.scroll_manager.show_scrollbars(window, cx);
 2424        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2425
 2426        if full_mode {
 2427            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2428            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2429
 2430            if editor.git_blame_inline_enabled {
 2431                editor.start_git_blame_inline(false, window, cx);
 2432            }
 2433
 2434            editor.go_to_active_debug_line(window, cx);
 2435
 2436            editor.minimap =
 2437                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2438            editor.colors = Some(LspColorData::new(cx));
 2439            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2440
 2441            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2442                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2443            }
 2444            editor.update_lsp_data(None, window, cx);
 2445            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2446        }
 2447
 2448        editor
 2449    }
 2450
 2451    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2452        self.selections.display_map(cx)
 2453    }
 2454
 2455    pub fn deploy_mouse_context_menu(
 2456        &mut self,
 2457        position: gpui::Point<Pixels>,
 2458        context_menu: Entity<ContextMenu>,
 2459        window: &mut Window,
 2460        cx: &mut Context<Self>,
 2461    ) {
 2462        self.mouse_context_menu = Some(MouseContextMenu::new(
 2463            self,
 2464            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2465            context_menu,
 2466            window,
 2467            cx,
 2468        ));
 2469    }
 2470
 2471    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2472        self.mouse_context_menu
 2473            .as_ref()
 2474            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2475    }
 2476
 2477    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2478        if self
 2479            .selections
 2480            .pending_anchor()
 2481            .is_some_and(|pending_selection| {
 2482                let snapshot = self.buffer().read(cx).snapshot(cx);
 2483                pending_selection.range().includes(range, &snapshot)
 2484            })
 2485        {
 2486            return true;
 2487        }
 2488
 2489        self.selections
 2490            .disjoint_in_range::<usize>(range.clone(), &self.display_snapshot(cx))
 2491            .into_iter()
 2492            .any(|selection| {
 2493                // This is needed to cover a corner case, if we just check for an existing
 2494                // selection in the fold range, having a cursor at the start of the fold
 2495                // marks it as selected. Non-empty selections don't cause this.
 2496                let length = selection.end - selection.start;
 2497                length > 0
 2498            })
 2499    }
 2500
 2501    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2502        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2503    }
 2504
 2505    fn key_context_internal(
 2506        &self,
 2507        has_active_edit_prediction: bool,
 2508        window: &mut Window,
 2509        cx: &mut App,
 2510    ) -> KeyContext {
 2511        let mut key_context = KeyContext::new_with_defaults();
 2512        key_context.add("Editor");
 2513        let mode = match self.mode {
 2514            EditorMode::SingleLine => "single_line",
 2515            EditorMode::AutoHeight { .. } => "auto_height",
 2516            EditorMode::Minimap { .. } => "minimap",
 2517            EditorMode::Full { .. } => "full",
 2518        };
 2519
 2520        if EditorSettings::jupyter_enabled(cx) {
 2521            key_context.add("jupyter");
 2522        }
 2523
 2524        key_context.set("mode", mode);
 2525        if self.pending_rename.is_some() {
 2526            key_context.add("renaming");
 2527        }
 2528
 2529        match self.context_menu.borrow().as_ref() {
 2530            Some(CodeContextMenu::Completions(menu)) => {
 2531                if menu.visible() {
 2532                    key_context.add("menu");
 2533                    key_context.add("showing_completions");
 2534                }
 2535            }
 2536            Some(CodeContextMenu::CodeActions(menu)) => {
 2537                if menu.visible() {
 2538                    key_context.add("menu");
 2539                    key_context.add("showing_code_actions")
 2540                }
 2541            }
 2542            None => {}
 2543        }
 2544
 2545        if self.signature_help_state.has_multiple_signatures() {
 2546            key_context.add("showing_signature_help");
 2547        }
 2548
 2549        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2550        if !self.focus_handle(cx).contains_focused(window, cx)
 2551            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2552        {
 2553            for addon in self.addons.values() {
 2554                addon.extend_key_context(&mut key_context, cx)
 2555            }
 2556        }
 2557
 2558        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2559            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2560                Some(
 2561                    file.full_path(cx)
 2562                        .extension()?
 2563                        .to_string_lossy()
 2564                        .into_owned(),
 2565                )
 2566            }) {
 2567                key_context.set("extension", extension);
 2568            }
 2569        } else {
 2570            key_context.add("multibuffer");
 2571        }
 2572
 2573        if has_active_edit_prediction {
 2574            if self.edit_prediction_in_conflict() {
 2575                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2576            } else {
 2577                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2578                key_context.add("copilot_suggestion");
 2579            }
 2580        }
 2581
 2582        if self.selection_mark_mode {
 2583            key_context.add("selection_mode");
 2584        }
 2585
 2586        let disjoint = self.selections.disjoint_anchors();
 2587        let snapshot = self.snapshot(window, cx);
 2588        let snapshot = snapshot.buffer_snapshot();
 2589        if self.mode == EditorMode::SingleLine
 2590            && let [selection] = disjoint
 2591            && selection.start == selection.end
 2592            && selection.end.to_offset(snapshot) == snapshot.len()
 2593        {
 2594            key_context.add("end_of_input");
 2595        }
 2596
 2597        key_context
 2598    }
 2599
 2600    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2601        self.last_bounds.as_ref()
 2602    }
 2603
 2604    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2605        if self.mouse_cursor_hidden {
 2606            self.mouse_cursor_hidden = false;
 2607            cx.notify();
 2608        }
 2609    }
 2610
 2611    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2612        let hide_mouse_cursor = match origin {
 2613            HideMouseCursorOrigin::TypingAction => {
 2614                matches!(
 2615                    self.hide_mouse_mode,
 2616                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2617                )
 2618            }
 2619            HideMouseCursorOrigin::MovementAction => {
 2620                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2621            }
 2622        };
 2623        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2624            self.mouse_cursor_hidden = hide_mouse_cursor;
 2625            cx.notify();
 2626        }
 2627    }
 2628
 2629    pub fn edit_prediction_in_conflict(&self) -> bool {
 2630        if !self.show_edit_predictions_in_menu() {
 2631            return false;
 2632        }
 2633
 2634        let showing_completions = self
 2635            .context_menu
 2636            .borrow()
 2637            .as_ref()
 2638            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2639
 2640        showing_completions
 2641            || self.edit_prediction_requires_modifier()
 2642            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2643            // bindings to insert tab characters.
 2644            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2645    }
 2646
 2647    pub fn accept_edit_prediction_keybind(
 2648        &self,
 2649        accept_partial: bool,
 2650        window: &mut Window,
 2651        cx: &mut App,
 2652    ) -> AcceptEditPredictionBinding {
 2653        let key_context = self.key_context_internal(true, window, cx);
 2654        let in_conflict = self.edit_prediction_in_conflict();
 2655
 2656        let bindings = if accept_partial {
 2657            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2658        } else {
 2659            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2660        };
 2661
 2662        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2663        // just the first one.
 2664        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2665            !in_conflict
 2666                || binding
 2667                    .keystrokes()
 2668                    .first()
 2669                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2670        }))
 2671    }
 2672
 2673    pub fn new_file(
 2674        workspace: &mut Workspace,
 2675        _: &workspace::NewFile,
 2676        window: &mut Window,
 2677        cx: &mut Context<Workspace>,
 2678    ) {
 2679        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2680            "Failed to create buffer",
 2681            window,
 2682            cx,
 2683            |e, _, _| match e.error_code() {
 2684                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2685                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2686                e.error_tag("required").unwrap_or("the latest version")
 2687            )),
 2688                _ => None,
 2689            },
 2690        );
 2691    }
 2692
 2693    pub fn new_in_workspace(
 2694        workspace: &mut Workspace,
 2695        window: &mut Window,
 2696        cx: &mut Context<Workspace>,
 2697    ) -> Task<Result<Entity<Editor>>> {
 2698        let project = workspace.project().clone();
 2699        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2700
 2701        cx.spawn_in(window, async move |workspace, cx| {
 2702            let buffer = create.await?;
 2703            workspace.update_in(cx, |workspace, window, cx| {
 2704                let editor =
 2705                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2706                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2707                editor
 2708            })
 2709        })
 2710    }
 2711
 2712    fn new_file_vertical(
 2713        workspace: &mut Workspace,
 2714        _: &workspace::NewFileSplitVertical,
 2715        window: &mut Window,
 2716        cx: &mut Context<Workspace>,
 2717    ) {
 2718        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2719    }
 2720
 2721    fn new_file_horizontal(
 2722        workspace: &mut Workspace,
 2723        _: &workspace::NewFileSplitHorizontal,
 2724        window: &mut Window,
 2725        cx: &mut Context<Workspace>,
 2726    ) {
 2727        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2728    }
 2729
 2730    fn new_file_split(
 2731        workspace: &mut Workspace,
 2732        action: &workspace::NewFileSplit,
 2733        window: &mut Window,
 2734        cx: &mut Context<Workspace>,
 2735    ) {
 2736        Self::new_file_in_direction(workspace, action.0, window, cx)
 2737    }
 2738
 2739    fn new_file_in_direction(
 2740        workspace: &mut Workspace,
 2741        direction: SplitDirection,
 2742        window: &mut Window,
 2743        cx: &mut Context<Workspace>,
 2744    ) {
 2745        let project = workspace.project().clone();
 2746        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2747
 2748        cx.spawn_in(window, async move |workspace, cx| {
 2749            let buffer = create.await?;
 2750            workspace.update_in(cx, move |workspace, window, cx| {
 2751                workspace.split_item(
 2752                    direction,
 2753                    Box::new(
 2754                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2755                    ),
 2756                    window,
 2757                    cx,
 2758                )
 2759            })?;
 2760            anyhow::Ok(())
 2761        })
 2762        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2763            match e.error_code() {
 2764                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2765                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2766                e.error_tag("required").unwrap_or("the latest version")
 2767            )),
 2768                _ => None,
 2769            }
 2770        });
 2771    }
 2772
 2773    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2774        self.leader_id
 2775    }
 2776
 2777    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2778        &self.buffer
 2779    }
 2780
 2781    pub fn project(&self) -> Option<&Entity<Project>> {
 2782        self.project.as_ref()
 2783    }
 2784
 2785    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2786        self.workspace.as_ref()?.0.upgrade()
 2787    }
 2788
 2789    /// Returns the workspace serialization ID if this editor should be serialized.
 2790    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 2791        self.workspace
 2792            .as_ref()
 2793            .filter(|_| self.should_serialize_buffer())
 2794            .and_then(|workspace| workspace.1)
 2795    }
 2796
 2797    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2798        self.buffer().read(cx).title(cx)
 2799    }
 2800
 2801    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2802        let git_blame_gutter_max_author_length = self
 2803            .render_git_blame_gutter(cx)
 2804            .then(|| {
 2805                if let Some(blame) = self.blame.as_ref() {
 2806                    let max_author_length =
 2807                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2808                    Some(max_author_length)
 2809                } else {
 2810                    None
 2811                }
 2812            })
 2813            .flatten();
 2814
 2815        EditorSnapshot {
 2816            mode: self.mode.clone(),
 2817            show_gutter: self.show_gutter,
 2818            show_line_numbers: self.show_line_numbers,
 2819            show_git_diff_gutter: self.show_git_diff_gutter,
 2820            show_code_actions: self.show_code_actions,
 2821            show_runnables: self.show_runnables,
 2822            show_breakpoints: self.show_breakpoints,
 2823            git_blame_gutter_max_author_length,
 2824            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2825            placeholder_display_snapshot: self
 2826                .placeholder_display_map
 2827                .as_ref()
 2828                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2829            scroll_anchor: self.scroll_manager.anchor(),
 2830            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2831            is_focused: self.focus_handle.is_focused(window),
 2832            current_line_highlight: self
 2833                .current_line_highlight
 2834                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2835            gutter_hovered: self.gutter_hovered,
 2836        }
 2837    }
 2838
 2839    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2840        self.buffer.read(cx).language_at(point, cx)
 2841    }
 2842
 2843    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2844        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2845    }
 2846
 2847    pub fn active_excerpt(
 2848        &self,
 2849        cx: &App,
 2850    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2851        self.buffer
 2852            .read(cx)
 2853            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2854    }
 2855
 2856    pub fn mode(&self) -> &EditorMode {
 2857        &self.mode
 2858    }
 2859
 2860    pub fn set_mode(&mut self, mode: EditorMode) {
 2861        self.mode = mode;
 2862    }
 2863
 2864    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2865        self.collaboration_hub.as_deref()
 2866    }
 2867
 2868    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2869        self.collaboration_hub = Some(hub);
 2870    }
 2871
 2872    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2873        self.in_project_search = in_project_search;
 2874    }
 2875
 2876    pub fn set_custom_context_menu(
 2877        &mut self,
 2878        f: impl 'static
 2879        + Fn(
 2880            &mut Self,
 2881            DisplayPoint,
 2882            &mut Window,
 2883            &mut Context<Self>,
 2884        ) -> Option<Entity<ui::ContextMenu>>,
 2885    ) {
 2886        self.custom_context_menu = Some(Box::new(f))
 2887    }
 2888
 2889    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2890        self.completion_provider = provider;
 2891    }
 2892
 2893    #[cfg(any(test, feature = "test-support"))]
 2894    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2895        self.completion_provider.clone()
 2896    }
 2897
 2898    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2899        self.semantics_provider.clone()
 2900    }
 2901
 2902    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2903        self.semantics_provider = provider;
 2904    }
 2905
 2906    pub fn set_edit_prediction_provider<T>(
 2907        &mut self,
 2908        provider: Option<Entity<T>>,
 2909        window: &mut Window,
 2910        cx: &mut Context<Self>,
 2911    ) where
 2912        T: EditPredictionProvider,
 2913    {
 2914        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2915            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2916                if this.focus_handle.is_focused(window) {
 2917                    this.update_visible_edit_prediction(window, cx);
 2918                }
 2919            }),
 2920            provider: Arc::new(provider),
 2921        });
 2922        self.update_edit_prediction_settings(cx);
 2923        self.refresh_edit_prediction(false, false, window, cx);
 2924    }
 2925
 2926    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2927        self.placeholder_display_map
 2928            .as_ref()
 2929            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2930    }
 2931
 2932    pub fn set_placeholder_text(
 2933        &mut self,
 2934        placeholder_text: &str,
 2935        window: &mut Window,
 2936        cx: &mut Context<Self>,
 2937    ) {
 2938        let multibuffer = cx
 2939            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2940
 2941        let style = window.text_style();
 2942
 2943        self.placeholder_display_map = Some(cx.new(|cx| {
 2944            DisplayMap::new(
 2945                multibuffer,
 2946                style.font(),
 2947                style.font_size.to_pixels(window.rem_size()),
 2948                None,
 2949                FILE_HEADER_HEIGHT,
 2950                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2951                Default::default(),
 2952                DiagnosticSeverity::Off,
 2953                cx,
 2954            )
 2955        }));
 2956        cx.notify();
 2957    }
 2958
 2959    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2960        self.cursor_shape = cursor_shape;
 2961
 2962        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2963        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2964
 2965        cx.notify();
 2966    }
 2967
 2968    pub fn set_current_line_highlight(
 2969        &mut self,
 2970        current_line_highlight: Option<CurrentLineHighlight>,
 2971    ) {
 2972        self.current_line_highlight = current_line_highlight;
 2973    }
 2974
 2975    pub fn range_for_match<T: std::marker::Copy>(
 2976        &self,
 2977        range: &Range<T>,
 2978        collapse: bool,
 2979    ) -> Range<T> {
 2980        if collapse {
 2981            return range.start..range.start;
 2982        }
 2983        range.clone()
 2984    }
 2985
 2986    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2987        if self.display_map.read(cx).clip_at_line_ends != clip {
 2988            self.display_map
 2989                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2990        }
 2991    }
 2992
 2993    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2994        self.input_enabled = input_enabled;
 2995    }
 2996
 2997    pub fn set_edit_predictions_hidden_for_vim_mode(
 2998        &mut self,
 2999        hidden: bool,
 3000        window: &mut Window,
 3001        cx: &mut Context<Self>,
 3002    ) {
 3003        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3004            self.edit_predictions_hidden_for_vim_mode = hidden;
 3005            if hidden {
 3006                self.update_visible_edit_prediction(window, cx);
 3007            } else {
 3008                self.refresh_edit_prediction(true, false, window, cx);
 3009            }
 3010        }
 3011    }
 3012
 3013    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3014        self.menu_edit_predictions_policy = value;
 3015    }
 3016
 3017    pub fn set_autoindent(&mut self, autoindent: bool) {
 3018        if autoindent {
 3019            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3020        } else {
 3021            self.autoindent_mode = None;
 3022        }
 3023    }
 3024
 3025    pub fn read_only(&self, cx: &App) -> bool {
 3026        self.read_only || self.buffer.read(cx).read_only()
 3027    }
 3028
 3029    pub fn set_read_only(&mut self, read_only: bool) {
 3030        self.read_only = read_only;
 3031    }
 3032
 3033    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3034        self.use_autoclose = autoclose;
 3035    }
 3036
 3037    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3038        self.use_auto_surround = auto_surround;
 3039    }
 3040
 3041    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3042        self.auto_replace_emoji_shortcode = auto_replace;
 3043    }
 3044
 3045    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3046        self.buffer_serialization = should_serialize.then(|| {
 3047            BufferSerialization::new(
 3048                ProjectSettings::get_global(cx)
 3049                    .session
 3050                    .restore_unsaved_buffers,
 3051            )
 3052        })
 3053    }
 3054
 3055    fn should_serialize_buffer(&self) -> bool {
 3056        self.buffer_serialization.is_some()
 3057    }
 3058
 3059    pub fn toggle_edit_predictions(
 3060        &mut self,
 3061        _: &ToggleEditPrediction,
 3062        window: &mut Window,
 3063        cx: &mut Context<Self>,
 3064    ) {
 3065        if self.show_edit_predictions_override.is_some() {
 3066            self.set_show_edit_predictions(None, window, cx);
 3067        } else {
 3068            let show_edit_predictions = !self.edit_predictions_enabled();
 3069            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3070        }
 3071    }
 3072
 3073    pub fn set_show_edit_predictions(
 3074        &mut self,
 3075        show_edit_predictions: Option<bool>,
 3076        window: &mut Window,
 3077        cx: &mut Context<Self>,
 3078    ) {
 3079        self.show_edit_predictions_override = show_edit_predictions;
 3080        self.update_edit_prediction_settings(cx);
 3081
 3082        if let Some(false) = show_edit_predictions {
 3083            self.discard_edit_prediction(false, cx);
 3084        } else {
 3085            self.refresh_edit_prediction(false, true, window, cx);
 3086        }
 3087    }
 3088
 3089    fn edit_predictions_disabled_in_scope(
 3090        &self,
 3091        buffer: &Entity<Buffer>,
 3092        buffer_position: language::Anchor,
 3093        cx: &App,
 3094    ) -> bool {
 3095        let snapshot = buffer.read(cx).snapshot();
 3096        let settings = snapshot.settings_at(buffer_position, cx);
 3097
 3098        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3099            return false;
 3100        };
 3101
 3102        scope.override_name().is_some_and(|scope_name| {
 3103            settings
 3104                .edit_predictions_disabled_in
 3105                .iter()
 3106                .any(|s| s == scope_name)
 3107        })
 3108    }
 3109
 3110    pub fn set_use_modal_editing(&mut self, to: bool) {
 3111        self.use_modal_editing = to;
 3112    }
 3113
 3114    pub fn use_modal_editing(&self) -> bool {
 3115        self.use_modal_editing
 3116    }
 3117
 3118    fn selections_did_change(
 3119        &mut self,
 3120        local: bool,
 3121        old_cursor_position: &Anchor,
 3122        effects: SelectionEffects,
 3123        window: &mut Window,
 3124        cx: &mut Context<Self>,
 3125    ) {
 3126        window.invalidate_character_coordinates();
 3127
 3128        // Copy selections to primary selection buffer
 3129        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3130        if local {
 3131            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3132            let buffer_handle = self.buffer.read(cx).read(cx);
 3133
 3134            let mut text = String::new();
 3135            for (index, selection) in selections.iter().enumerate() {
 3136                let text_for_selection = buffer_handle
 3137                    .text_for_range(selection.start..selection.end)
 3138                    .collect::<String>();
 3139
 3140                text.push_str(&text_for_selection);
 3141                if index != selections.len() - 1 {
 3142                    text.push('\n');
 3143                }
 3144            }
 3145
 3146            if !text.is_empty() {
 3147                cx.write_to_primary(ClipboardItem::new_string(text));
 3148            }
 3149        }
 3150
 3151        let selection_anchors = self.selections.disjoint_anchors_arc();
 3152
 3153        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3154            self.buffer.update(cx, |buffer, cx| {
 3155                buffer.set_active_selections(
 3156                    &selection_anchors,
 3157                    self.selections.line_mode(),
 3158                    self.cursor_shape,
 3159                    cx,
 3160                )
 3161            });
 3162        }
 3163        let display_map = self
 3164            .display_map
 3165            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3166        let buffer = display_map.buffer_snapshot();
 3167        if self.selections.count() == 1 {
 3168            self.add_selections_state = None;
 3169        }
 3170        self.select_next_state = None;
 3171        self.select_prev_state = None;
 3172        self.select_syntax_node_history.try_clear();
 3173        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3174        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3175        self.take_rename(false, window, cx);
 3176
 3177        let newest_selection = self.selections.newest_anchor();
 3178        let new_cursor_position = newest_selection.head();
 3179        let selection_start = newest_selection.start;
 3180
 3181        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3182            self.push_to_nav_history(
 3183                *old_cursor_position,
 3184                Some(new_cursor_position.to_point(buffer)),
 3185                false,
 3186                effects.nav_history == Some(true),
 3187                cx,
 3188            );
 3189        }
 3190
 3191        if local {
 3192            if let Some(buffer_id) = new_cursor_position.buffer_id {
 3193                self.register_buffer(buffer_id, cx);
 3194            }
 3195
 3196            let mut context_menu = self.context_menu.borrow_mut();
 3197            let completion_menu = match context_menu.as_ref() {
 3198                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3199                Some(CodeContextMenu::CodeActions(_)) => {
 3200                    *context_menu = None;
 3201                    None
 3202                }
 3203                None => None,
 3204            };
 3205            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3206            drop(context_menu);
 3207
 3208            if effects.completions
 3209                && let Some(completion_position) = completion_position
 3210            {
 3211                let start_offset = selection_start.to_offset(buffer);
 3212                let position_matches = start_offset == completion_position.to_offset(buffer);
 3213                let continue_showing = if position_matches {
 3214                    if self.snippet_stack.is_empty() {
 3215                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3216                            == Some(CharKind::Word)
 3217                    } else {
 3218                        // Snippet choices can be shown even when the cursor is in whitespace.
 3219                        // Dismissing the menu with actions like backspace is handled by
 3220                        // invalidation regions.
 3221                        true
 3222                    }
 3223                } else {
 3224                    false
 3225                };
 3226
 3227                if continue_showing {
 3228                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3229                } else {
 3230                    self.hide_context_menu(window, cx);
 3231                }
 3232            }
 3233
 3234            hide_hover(self, cx);
 3235
 3236            if old_cursor_position.to_display_point(&display_map).row()
 3237                != new_cursor_position.to_display_point(&display_map).row()
 3238            {
 3239                self.available_code_actions.take();
 3240            }
 3241            self.refresh_code_actions(window, cx);
 3242            self.refresh_document_highlights(cx);
 3243            refresh_linked_ranges(self, window, cx);
 3244
 3245            self.refresh_selected_text_highlights(false, window, cx);
 3246            self.colorize_brackets(cx);
 3247            self.refresh_matching_bracket_highlights(window, cx);
 3248            self.update_visible_edit_prediction(window, cx);
 3249            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3250            self.inline_blame_popover.take();
 3251            if self.git_blame_inline_enabled {
 3252                self.start_inline_blame_timer(window, cx);
 3253            }
 3254        }
 3255
 3256        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3257        cx.emit(EditorEvent::SelectionsChanged { local });
 3258
 3259        let selections = &self.selections.disjoint_anchors_arc();
 3260        if selections.len() == 1 {
 3261            cx.emit(SearchEvent::ActiveMatchChanged)
 3262        }
 3263        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3264            let inmemory_selections = selections
 3265                .iter()
 3266                .map(|s| {
 3267                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3268                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3269                })
 3270                .collect();
 3271            self.update_restoration_data(cx, |data| {
 3272                data.selections = inmemory_selections;
 3273            });
 3274
 3275            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3276                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3277            {
 3278                let snapshot = self.buffer().read(cx).snapshot(cx);
 3279                let selections = selections.clone();
 3280                let background_executor = cx.background_executor().clone();
 3281                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3282                self.serialize_selections = cx.background_spawn(async move {
 3283                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3284                    let db_selections = selections
 3285                        .iter()
 3286                        .map(|selection| {
 3287                            (
 3288                                selection.start.to_offset(&snapshot),
 3289                                selection.end.to_offset(&snapshot),
 3290                            )
 3291                        })
 3292                        .collect();
 3293
 3294                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3295                        .await
 3296                        .with_context(|| {
 3297                            format!(
 3298                                "persisting editor selections for editor {editor_id}, \
 3299                                workspace {workspace_id:?}"
 3300                            )
 3301                        })
 3302                        .log_err();
 3303                });
 3304            }
 3305        }
 3306
 3307        cx.notify();
 3308    }
 3309
 3310    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3311        use text::ToOffset as _;
 3312        use text::ToPoint as _;
 3313
 3314        if self.mode.is_minimap()
 3315            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3316        {
 3317            return;
 3318        }
 3319
 3320        if !self.buffer().read(cx).is_singleton() {
 3321            return;
 3322        }
 3323
 3324        let display_snapshot = self
 3325            .display_map
 3326            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3327        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3328            return;
 3329        };
 3330        let inmemory_folds = display_snapshot
 3331            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3332            .map(|fold| {
 3333                fold.range.start.text_anchor.to_point(&snapshot)
 3334                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3335            })
 3336            .collect();
 3337        self.update_restoration_data(cx, |data| {
 3338            data.folds = inmemory_folds;
 3339        });
 3340
 3341        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3342            return;
 3343        };
 3344        let background_executor = cx.background_executor().clone();
 3345        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3346        let db_folds = display_snapshot
 3347            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3348            .map(|fold| {
 3349                (
 3350                    fold.range.start.text_anchor.to_offset(&snapshot),
 3351                    fold.range.end.text_anchor.to_offset(&snapshot),
 3352                )
 3353            })
 3354            .collect();
 3355        self.serialize_folds = cx.background_spawn(async move {
 3356            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3357            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3358                .await
 3359                .with_context(|| {
 3360                    format!(
 3361                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3362                    )
 3363                })
 3364                .log_err();
 3365        });
 3366    }
 3367
 3368    pub fn sync_selections(
 3369        &mut self,
 3370        other: Entity<Editor>,
 3371        cx: &mut Context<Self>,
 3372    ) -> gpui::Subscription {
 3373        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3374        if !other_selections.is_empty() {
 3375            self.selections.change_with(cx, |selections| {
 3376                selections.select_anchors(other_selections);
 3377            });
 3378        }
 3379
 3380        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3381            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3382                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3383                if other_selections.is_empty() {
 3384                    return;
 3385                }
 3386                this.selections.change_with(cx, |selections| {
 3387                    selections.select_anchors(other_selections);
 3388                });
 3389            }
 3390        });
 3391
 3392        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3393            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3394                let these_selections = this.selections.disjoint_anchors().to_vec();
 3395                if these_selections.is_empty() {
 3396                    return;
 3397                }
 3398                other.update(cx, |other_editor, cx| {
 3399                    other_editor.selections.change_with(cx, |selections| {
 3400                        selections.select_anchors(these_selections);
 3401                    })
 3402                });
 3403            }
 3404        });
 3405
 3406        Subscription::join(other_subscription, this_subscription)
 3407    }
 3408
 3409    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3410    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3411    /// effects of selection change occur at the end of the transaction.
 3412    pub fn change_selections<R>(
 3413        &mut self,
 3414        effects: SelectionEffects,
 3415        window: &mut Window,
 3416        cx: &mut Context<Self>,
 3417        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3418    ) -> R {
 3419        if let Some(state) = &mut self.deferred_selection_effects_state {
 3420            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3421            state.effects.completions = effects.completions;
 3422            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3423            let (changed, result) = self.selections.change_with(cx, change);
 3424            state.changed |= changed;
 3425            return result;
 3426        }
 3427        let mut state = DeferredSelectionEffectsState {
 3428            changed: false,
 3429            effects,
 3430            old_cursor_position: self.selections.newest_anchor().head(),
 3431            history_entry: SelectionHistoryEntry {
 3432                selections: self.selections.disjoint_anchors_arc(),
 3433                select_next_state: self.select_next_state.clone(),
 3434                select_prev_state: self.select_prev_state.clone(),
 3435                add_selections_state: self.add_selections_state.clone(),
 3436            },
 3437        };
 3438        let (changed, result) = self.selections.change_with(cx, change);
 3439        state.changed = state.changed || changed;
 3440        if self.defer_selection_effects {
 3441            self.deferred_selection_effects_state = Some(state);
 3442        } else {
 3443            self.apply_selection_effects(state, window, cx);
 3444        }
 3445        result
 3446    }
 3447
 3448    /// Defers the effects of selection change, so that the effects of multiple calls to
 3449    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3450    /// to selection history and the state of popovers based on selection position aren't
 3451    /// erroneously updated.
 3452    pub fn with_selection_effects_deferred<R>(
 3453        &mut self,
 3454        window: &mut Window,
 3455        cx: &mut Context<Self>,
 3456        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3457    ) -> R {
 3458        let already_deferred = self.defer_selection_effects;
 3459        self.defer_selection_effects = true;
 3460        let result = update(self, window, cx);
 3461        if !already_deferred {
 3462            self.defer_selection_effects = false;
 3463            if let Some(state) = self.deferred_selection_effects_state.take() {
 3464                self.apply_selection_effects(state, window, cx);
 3465            }
 3466        }
 3467        result
 3468    }
 3469
 3470    fn apply_selection_effects(
 3471        &mut self,
 3472        state: DeferredSelectionEffectsState,
 3473        window: &mut Window,
 3474        cx: &mut Context<Self>,
 3475    ) {
 3476        if state.changed {
 3477            self.selection_history.push(state.history_entry);
 3478
 3479            if let Some(autoscroll) = state.effects.scroll {
 3480                self.request_autoscroll(autoscroll, cx);
 3481            }
 3482
 3483            let old_cursor_position = &state.old_cursor_position;
 3484
 3485            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3486
 3487            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3488                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3489            }
 3490        }
 3491    }
 3492
 3493    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3494    where
 3495        I: IntoIterator<Item = (Range<S>, T)>,
 3496        S: ToOffset,
 3497        T: Into<Arc<str>>,
 3498    {
 3499        if self.read_only(cx) {
 3500            return;
 3501        }
 3502
 3503        self.buffer
 3504            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3505    }
 3506
 3507    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3508    where
 3509        I: IntoIterator<Item = (Range<S>, T)>,
 3510        S: ToOffset,
 3511        T: Into<Arc<str>>,
 3512    {
 3513        if self.read_only(cx) {
 3514            return;
 3515        }
 3516
 3517        self.buffer.update(cx, |buffer, cx| {
 3518            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3519        });
 3520    }
 3521
 3522    pub fn edit_with_block_indent<I, S, T>(
 3523        &mut self,
 3524        edits: I,
 3525        original_indent_columns: Vec<Option<u32>>,
 3526        cx: &mut Context<Self>,
 3527    ) where
 3528        I: IntoIterator<Item = (Range<S>, T)>,
 3529        S: ToOffset,
 3530        T: Into<Arc<str>>,
 3531    {
 3532        if self.read_only(cx) {
 3533            return;
 3534        }
 3535
 3536        self.buffer.update(cx, |buffer, cx| {
 3537            buffer.edit(
 3538                edits,
 3539                Some(AutoindentMode::Block {
 3540                    original_indent_columns,
 3541                }),
 3542                cx,
 3543            )
 3544        });
 3545    }
 3546
 3547    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3548        self.hide_context_menu(window, cx);
 3549
 3550        match phase {
 3551            SelectPhase::Begin {
 3552                position,
 3553                add,
 3554                click_count,
 3555            } => self.begin_selection(position, add, click_count, window, cx),
 3556            SelectPhase::BeginColumnar {
 3557                position,
 3558                goal_column,
 3559                reset,
 3560                mode,
 3561            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3562            SelectPhase::Extend {
 3563                position,
 3564                click_count,
 3565            } => self.extend_selection(position, click_count, window, cx),
 3566            SelectPhase::Update {
 3567                position,
 3568                goal_column,
 3569                scroll_delta,
 3570            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3571            SelectPhase::End => self.end_selection(window, cx),
 3572        }
 3573    }
 3574
 3575    fn extend_selection(
 3576        &mut self,
 3577        position: DisplayPoint,
 3578        click_count: usize,
 3579        window: &mut Window,
 3580        cx: &mut Context<Self>,
 3581    ) {
 3582        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3583        let tail = self.selections.newest::<usize>(&display_map).tail();
 3584        let click_count = click_count.max(match self.selections.select_mode() {
 3585            SelectMode::Character => 1,
 3586            SelectMode::Word(_) => 2,
 3587            SelectMode::Line(_) => 3,
 3588            SelectMode::All => 4,
 3589        });
 3590        self.begin_selection(position, false, click_count, window, cx);
 3591
 3592        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3593
 3594        let current_selection = match self.selections.select_mode() {
 3595            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3596            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3597        };
 3598
 3599        let mut pending_selection = self
 3600            .selections
 3601            .pending_anchor()
 3602            .cloned()
 3603            .expect("extend_selection not called with pending selection");
 3604
 3605        if pending_selection
 3606            .start
 3607            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3608            == Ordering::Greater
 3609        {
 3610            pending_selection.start = current_selection.start;
 3611        }
 3612        if pending_selection
 3613            .end
 3614            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3615            == Ordering::Less
 3616        {
 3617            pending_selection.end = current_selection.end;
 3618            pending_selection.reversed = true;
 3619        }
 3620
 3621        let mut pending_mode = self.selections.pending_mode().unwrap();
 3622        match &mut pending_mode {
 3623            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3624            _ => {}
 3625        }
 3626
 3627        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3628            SelectionEffects::scroll(Autoscroll::fit())
 3629        } else {
 3630            SelectionEffects::no_scroll()
 3631        };
 3632
 3633        self.change_selections(effects, window, cx, |s| {
 3634            s.set_pending(pending_selection.clone(), pending_mode);
 3635            s.set_is_extending(true);
 3636        });
 3637    }
 3638
 3639    fn begin_selection(
 3640        &mut self,
 3641        position: DisplayPoint,
 3642        add: bool,
 3643        click_count: usize,
 3644        window: &mut Window,
 3645        cx: &mut Context<Self>,
 3646    ) {
 3647        if !self.focus_handle.is_focused(window) {
 3648            self.last_focused_descendant = None;
 3649            window.focus(&self.focus_handle);
 3650        }
 3651
 3652        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3653        let buffer = display_map.buffer_snapshot();
 3654        let position = display_map.clip_point(position, Bias::Left);
 3655
 3656        let start;
 3657        let end;
 3658        let mode;
 3659        let mut auto_scroll;
 3660        match click_count {
 3661            1 => {
 3662                start = buffer.anchor_before(position.to_point(&display_map));
 3663                end = start;
 3664                mode = SelectMode::Character;
 3665                auto_scroll = true;
 3666            }
 3667            2 => {
 3668                let position = display_map
 3669                    .clip_point(position, Bias::Left)
 3670                    .to_offset(&display_map, Bias::Left);
 3671                let (range, _) = buffer.surrounding_word(position, None);
 3672                start = buffer.anchor_before(range.start);
 3673                end = buffer.anchor_before(range.end);
 3674                mode = SelectMode::Word(start..end);
 3675                auto_scroll = true;
 3676            }
 3677            3 => {
 3678                let position = display_map
 3679                    .clip_point(position, Bias::Left)
 3680                    .to_point(&display_map);
 3681                let line_start = display_map.prev_line_boundary(position).0;
 3682                let next_line_start = buffer.clip_point(
 3683                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3684                    Bias::Left,
 3685                );
 3686                start = buffer.anchor_before(line_start);
 3687                end = buffer.anchor_before(next_line_start);
 3688                mode = SelectMode::Line(start..end);
 3689                auto_scroll = true;
 3690            }
 3691            _ => {
 3692                start = buffer.anchor_before(0);
 3693                end = buffer.anchor_before(buffer.len());
 3694                mode = SelectMode::All;
 3695                auto_scroll = false;
 3696            }
 3697        }
 3698        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3699
 3700        let point_to_delete: Option<usize> = {
 3701            let selected_points: Vec<Selection<Point>> =
 3702                self.selections.disjoint_in_range(start..end, &display_map);
 3703
 3704            if !add || click_count > 1 {
 3705                None
 3706            } else if !selected_points.is_empty() {
 3707                Some(selected_points[0].id)
 3708            } else {
 3709                let clicked_point_already_selected =
 3710                    self.selections.disjoint_anchors().iter().find(|selection| {
 3711                        selection.start.to_point(buffer) == start.to_point(buffer)
 3712                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3713                    });
 3714
 3715                clicked_point_already_selected.map(|selection| selection.id)
 3716            }
 3717        };
 3718
 3719        let selections_count = self.selections.count();
 3720        let effects = if auto_scroll {
 3721            SelectionEffects::default()
 3722        } else {
 3723            SelectionEffects::no_scroll()
 3724        };
 3725
 3726        self.change_selections(effects, window, cx, |s| {
 3727            if let Some(point_to_delete) = point_to_delete {
 3728                s.delete(point_to_delete);
 3729
 3730                if selections_count == 1 {
 3731                    s.set_pending_anchor_range(start..end, mode);
 3732                }
 3733            } else {
 3734                if !add {
 3735                    s.clear_disjoint();
 3736                }
 3737
 3738                s.set_pending_anchor_range(start..end, mode);
 3739            }
 3740        });
 3741    }
 3742
 3743    fn begin_columnar_selection(
 3744        &mut self,
 3745        position: DisplayPoint,
 3746        goal_column: u32,
 3747        reset: bool,
 3748        mode: ColumnarMode,
 3749        window: &mut Window,
 3750        cx: &mut Context<Self>,
 3751    ) {
 3752        if !self.focus_handle.is_focused(window) {
 3753            self.last_focused_descendant = None;
 3754            window.focus(&self.focus_handle);
 3755        }
 3756
 3757        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3758
 3759        if reset {
 3760            let pointer_position = display_map
 3761                .buffer_snapshot()
 3762                .anchor_before(position.to_point(&display_map));
 3763
 3764            self.change_selections(
 3765                SelectionEffects::scroll(Autoscroll::newest()),
 3766                window,
 3767                cx,
 3768                |s| {
 3769                    s.clear_disjoint();
 3770                    s.set_pending_anchor_range(
 3771                        pointer_position..pointer_position,
 3772                        SelectMode::Character,
 3773                    );
 3774                },
 3775            );
 3776        };
 3777
 3778        let tail = self.selections.newest::<Point>(&display_map).tail();
 3779        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3780        self.columnar_selection_state = match mode {
 3781            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3782                selection_tail: selection_anchor,
 3783                display_point: if reset {
 3784                    if position.column() != goal_column {
 3785                        Some(DisplayPoint::new(position.row(), goal_column))
 3786                    } else {
 3787                        None
 3788                    }
 3789                } else {
 3790                    None
 3791                },
 3792            }),
 3793            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3794                selection_tail: selection_anchor,
 3795            }),
 3796        };
 3797
 3798        if !reset {
 3799            self.select_columns(position, goal_column, &display_map, window, cx);
 3800        }
 3801    }
 3802
 3803    fn update_selection(
 3804        &mut self,
 3805        position: DisplayPoint,
 3806        goal_column: u32,
 3807        scroll_delta: gpui::Point<f32>,
 3808        window: &mut Window,
 3809        cx: &mut Context<Self>,
 3810    ) {
 3811        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3812
 3813        if self.columnar_selection_state.is_some() {
 3814            self.select_columns(position, goal_column, &display_map, window, cx);
 3815        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3816            let buffer = display_map.buffer_snapshot();
 3817            let head;
 3818            let tail;
 3819            let mode = self.selections.pending_mode().unwrap();
 3820            match &mode {
 3821                SelectMode::Character => {
 3822                    head = position.to_point(&display_map);
 3823                    tail = pending.tail().to_point(buffer);
 3824                }
 3825                SelectMode::Word(original_range) => {
 3826                    let offset = display_map
 3827                        .clip_point(position, Bias::Left)
 3828                        .to_offset(&display_map, Bias::Left);
 3829                    let original_range = original_range.to_offset(buffer);
 3830
 3831                    let head_offset = if buffer.is_inside_word(offset, None)
 3832                        || original_range.contains(&offset)
 3833                    {
 3834                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3835                        if word_range.start < original_range.start {
 3836                            word_range.start
 3837                        } else {
 3838                            word_range.end
 3839                        }
 3840                    } else {
 3841                        offset
 3842                    };
 3843
 3844                    head = head_offset.to_point(buffer);
 3845                    if head_offset <= original_range.start {
 3846                        tail = original_range.end.to_point(buffer);
 3847                    } else {
 3848                        tail = original_range.start.to_point(buffer);
 3849                    }
 3850                }
 3851                SelectMode::Line(original_range) => {
 3852                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3853
 3854                    let position = display_map
 3855                        .clip_point(position, Bias::Left)
 3856                        .to_point(&display_map);
 3857                    let line_start = display_map.prev_line_boundary(position).0;
 3858                    let next_line_start = buffer.clip_point(
 3859                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3860                        Bias::Left,
 3861                    );
 3862
 3863                    if line_start < original_range.start {
 3864                        head = line_start
 3865                    } else {
 3866                        head = next_line_start
 3867                    }
 3868
 3869                    if head <= original_range.start {
 3870                        tail = original_range.end;
 3871                    } else {
 3872                        tail = original_range.start;
 3873                    }
 3874                }
 3875                SelectMode::All => {
 3876                    return;
 3877                }
 3878            };
 3879
 3880            if head < tail {
 3881                pending.start = buffer.anchor_before(head);
 3882                pending.end = buffer.anchor_before(tail);
 3883                pending.reversed = true;
 3884            } else {
 3885                pending.start = buffer.anchor_before(tail);
 3886                pending.end = buffer.anchor_before(head);
 3887                pending.reversed = false;
 3888            }
 3889
 3890            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3891                s.set_pending(pending.clone(), mode);
 3892            });
 3893        } else {
 3894            log::error!("update_selection dispatched with no pending selection");
 3895            return;
 3896        }
 3897
 3898        self.apply_scroll_delta(scroll_delta, window, cx);
 3899        cx.notify();
 3900    }
 3901
 3902    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3903        self.columnar_selection_state.take();
 3904        if let Some(pending_mode) = self.selections.pending_mode() {
 3905            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3906            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3907                s.select(selections);
 3908                s.clear_pending();
 3909                if s.is_extending() {
 3910                    s.set_is_extending(false);
 3911                } else {
 3912                    s.set_select_mode(pending_mode);
 3913                }
 3914            });
 3915        }
 3916    }
 3917
 3918    fn select_columns(
 3919        &mut self,
 3920        head: DisplayPoint,
 3921        goal_column: u32,
 3922        display_map: &DisplaySnapshot,
 3923        window: &mut Window,
 3924        cx: &mut Context<Self>,
 3925    ) {
 3926        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3927            return;
 3928        };
 3929
 3930        let tail = match columnar_state {
 3931            ColumnarSelectionState::FromMouse {
 3932                selection_tail,
 3933                display_point,
 3934            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3935            ColumnarSelectionState::FromSelection { selection_tail } => {
 3936                selection_tail.to_display_point(display_map)
 3937            }
 3938        };
 3939
 3940        let start_row = cmp::min(tail.row(), head.row());
 3941        let end_row = cmp::max(tail.row(), head.row());
 3942        let start_column = cmp::min(tail.column(), goal_column);
 3943        let end_column = cmp::max(tail.column(), goal_column);
 3944        let reversed = start_column < tail.column();
 3945
 3946        let selection_ranges = (start_row.0..=end_row.0)
 3947            .map(DisplayRow)
 3948            .filter_map(|row| {
 3949                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3950                    || start_column <= display_map.line_len(row))
 3951                    && !display_map.is_block_line(row)
 3952                {
 3953                    let start = display_map
 3954                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3955                        .to_point(display_map);
 3956                    let end = display_map
 3957                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3958                        .to_point(display_map);
 3959                    if reversed {
 3960                        Some(end..start)
 3961                    } else {
 3962                        Some(start..end)
 3963                    }
 3964                } else {
 3965                    None
 3966                }
 3967            })
 3968            .collect::<Vec<_>>();
 3969        if selection_ranges.is_empty() {
 3970            return;
 3971        }
 3972
 3973        let ranges = match columnar_state {
 3974            ColumnarSelectionState::FromMouse { .. } => {
 3975                let mut non_empty_ranges = selection_ranges
 3976                    .iter()
 3977                    .filter(|selection_range| selection_range.start != selection_range.end)
 3978                    .peekable();
 3979                if non_empty_ranges.peek().is_some() {
 3980                    non_empty_ranges.cloned().collect()
 3981                } else {
 3982                    selection_ranges
 3983                }
 3984            }
 3985            _ => selection_ranges,
 3986        };
 3987
 3988        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3989            s.select_ranges(ranges);
 3990        });
 3991        cx.notify();
 3992    }
 3993
 3994    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 3995        self.selections
 3996            .all_adjusted(snapshot)
 3997            .iter()
 3998            .any(|selection| !selection.is_empty())
 3999    }
 4000
 4001    pub fn has_pending_nonempty_selection(&self) -> bool {
 4002        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4003            Some(Selection { start, end, .. }) => start != end,
 4004            None => false,
 4005        };
 4006
 4007        pending_nonempty_selection
 4008            || (self.columnar_selection_state.is_some()
 4009                && self.selections.disjoint_anchors().len() > 1)
 4010    }
 4011
 4012    pub fn has_pending_selection(&self) -> bool {
 4013        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4014    }
 4015
 4016    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4017        self.selection_mark_mode = false;
 4018        self.selection_drag_state = SelectionDragState::None;
 4019
 4020        if self.clear_expanded_diff_hunks(cx) {
 4021            cx.notify();
 4022            return;
 4023        }
 4024        if self.dismiss_menus_and_popups(true, window, cx) {
 4025            return;
 4026        }
 4027
 4028        if self.mode.is_full()
 4029            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4030        {
 4031            return;
 4032        }
 4033
 4034        cx.propagate();
 4035    }
 4036
 4037    pub fn dismiss_menus_and_popups(
 4038        &mut self,
 4039        is_user_requested: bool,
 4040        window: &mut Window,
 4041        cx: &mut Context<Self>,
 4042    ) -> bool {
 4043        if self.take_rename(false, window, cx).is_some() {
 4044            return true;
 4045        }
 4046
 4047        if self.hide_blame_popover(true, cx) {
 4048            return true;
 4049        }
 4050
 4051        if hide_hover(self, cx) {
 4052            return true;
 4053        }
 4054
 4055        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 4056            return true;
 4057        }
 4058
 4059        if self.hide_context_menu(window, cx).is_some() {
 4060            return true;
 4061        }
 4062
 4063        if self.mouse_context_menu.take().is_some() {
 4064            return true;
 4065        }
 4066
 4067        if is_user_requested && self.discard_edit_prediction(true, cx) {
 4068            return true;
 4069        }
 4070
 4071        if self.snippet_stack.pop().is_some() {
 4072            return true;
 4073        }
 4074
 4075        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4076            self.dismiss_diagnostics(cx);
 4077            return true;
 4078        }
 4079
 4080        false
 4081    }
 4082
 4083    fn linked_editing_ranges_for(
 4084        &self,
 4085        selection: Range<text::Anchor>,
 4086        cx: &App,
 4087    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4088        if self.linked_edit_ranges.is_empty() {
 4089            return None;
 4090        }
 4091        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4092            selection.end.buffer_id.and_then(|end_buffer_id| {
 4093                if selection.start.buffer_id != Some(end_buffer_id) {
 4094                    return None;
 4095                }
 4096                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4097                let snapshot = buffer.read(cx).snapshot();
 4098                self.linked_edit_ranges
 4099                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4100                    .map(|ranges| (ranges, snapshot, buffer))
 4101            })?;
 4102        use text::ToOffset as TO;
 4103        // find offset from the start of current range to current cursor position
 4104        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4105
 4106        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4107        let start_difference = start_offset - start_byte_offset;
 4108        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4109        let end_difference = end_offset - start_byte_offset;
 4110        // Current range has associated linked ranges.
 4111        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4112        for range in linked_ranges.iter() {
 4113            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4114            let end_offset = start_offset + end_difference;
 4115            let start_offset = start_offset + start_difference;
 4116            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4117                continue;
 4118            }
 4119            if self.selections.disjoint_anchor_ranges().any(|s| {
 4120                if s.start.buffer_id != selection.start.buffer_id
 4121                    || s.end.buffer_id != selection.end.buffer_id
 4122                {
 4123                    return false;
 4124                }
 4125                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4126                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4127            }) {
 4128                continue;
 4129            }
 4130            let start = buffer_snapshot.anchor_after(start_offset);
 4131            let end = buffer_snapshot.anchor_after(end_offset);
 4132            linked_edits
 4133                .entry(buffer.clone())
 4134                .or_default()
 4135                .push(start..end);
 4136        }
 4137        Some(linked_edits)
 4138    }
 4139
 4140    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4141        let text: Arc<str> = text.into();
 4142
 4143        if self.read_only(cx) {
 4144            return;
 4145        }
 4146
 4147        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4148
 4149        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4150        let mut bracket_inserted = false;
 4151        let mut edits = Vec::new();
 4152        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4153        let mut new_selections = Vec::with_capacity(selections.len());
 4154        let mut new_autoclose_regions = Vec::new();
 4155        let snapshot = self.buffer.read(cx).read(cx);
 4156        let mut clear_linked_edit_ranges = false;
 4157
 4158        for (selection, autoclose_region) in
 4159            self.selections_with_autoclose_regions(selections, &snapshot)
 4160        {
 4161            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4162                // Determine if the inserted text matches the opening or closing
 4163                // bracket of any of this language's bracket pairs.
 4164                let mut bracket_pair = None;
 4165                let mut is_bracket_pair_start = false;
 4166                let mut is_bracket_pair_end = false;
 4167                if !text.is_empty() {
 4168                    let mut bracket_pair_matching_end = None;
 4169                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4170                    //  and they are removing the character that triggered IME popup.
 4171                    for (pair, enabled) in scope.brackets() {
 4172                        if !pair.close && !pair.surround {
 4173                            continue;
 4174                        }
 4175
 4176                        if enabled && pair.start.ends_with(text.as_ref()) {
 4177                            let prefix_len = pair.start.len() - text.len();
 4178                            let preceding_text_matches_prefix = prefix_len == 0
 4179                                || (selection.start.column >= (prefix_len as u32)
 4180                                    && snapshot.contains_str_at(
 4181                                        Point::new(
 4182                                            selection.start.row,
 4183                                            selection.start.column - (prefix_len as u32),
 4184                                        ),
 4185                                        &pair.start[..prefix_len],
 4186                                    ));
 4187                            if preceding_text_matches_prefix {
 4188                                bracket_pair = Some(pair.clone());
 4189                                is_bracket_pair_start = true;
 4190                                break;
 4191                            }
 4192                        }
 4193                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4194                        {
 4195                            // take first bracket pair matching end, but don't break in case a later bracket
 4196                            // pair matches start
 4197                            bracket_pair_matching_end = Some(pair.clone());
 4198                        }
 4199                    }
 4200                    if let Some(end) = bracket_pair_matching_end
 4201                        && bracket_pair.is_none()
 4202                    {
 4203                        bracket_pair = Some(end);
 4204                        is_bracket_pair_end = true;
 4205                    }
 4206                }
 4207
 4208                if let Some(bracket_pair) = bracket_pair {
 4209                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4210                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4211                    let auto_surround =
 4212                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4213                    if selection.is_empty() {
 4214                        if is_bracket_pair_start {
 4215                            // If the inserted text is a suffix of an opening bracket and the
 4216                            // selection is preceded by the rest of the opening bracket, then
 4217                            // insert the closing bracket.
 4218                            let following_text_allows_autoclose = snapshot
 4219                                .chars_at(selection.start)
 4220                                .next()
 4221                                .is_none_or(|c| scope.should_autoclose_before(c));
 4222
 4223                            let preceding_text_allows_autoclose = selection.start.column == 0
 4224                                || snapshot
 4225                                    .reversed_chars_at(selection.start)
 4226                                    .next()
 4227                                    .is_none_or(|c| {
 4228                                        bracket_pair.start != bracket_pair.end
 4229                                            || !snapshot
 4230                                                .char_classifier_at(selection.start)
 4231                                                .is_word(c)
 4232                                    });
 4233
 4234                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4235                                && bracket_pair.start.len() == 1
 4236                            {
 4237                                let target = bracket_pair.start.chars().next().unwrap();
 4238                                let current_line_count = snapshot
 4239                                    .reversed_chars_at(selection.start)
 4240                                    .take_while(|&c| c != '\n')
 4241                                    .filter(|&c| c == target)
 4242                                    .count();
 4243                                current_line_count % 2 == 1
 4244                            } else {
 4245                                false
 4246                            };
 4247
 4248                            if autoclose
 4249                                && bracket_pair.close
 4250                                && following_text_allows_autoclose
 4251                                && preceding_text_allows_autoclose
 4252                                && !is_closing_quote
 4253                            {
 4254                                let anchor = snapshot.anchor_before(selection.end);
 4255                                new_selections.push((selection.map(|_| anchor), text.len()));
 4256                                new_autoclose_regions.push((
 4257                                    anchor,
 4258                                    text.len(),
 4259                                    selection.id,
 4260                                    bracket_pair.clone(),
 4261                                ));
 4262                                edits.push((
 4263                                    selection.range(),
 4264                                    format!("{}{}", text, bracket_pair.end).into(),
 4265                                ));
 4266                                bracket_inserted = true;
 4267                                continue;
 4268                            }
 4269                        }
 4270
 4271                        if let Some(region) = autoclose_region {
 4272                            // If the selection is followed by an auto-inserted closing bracket,
 4273                            // then don't insert that closing bracket again; just move the selection
 4274                            // past the closing bracket.
 4275                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4276                                && text.as_ref() == region.pair.end.as_str()
 4277                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4278                            if should_skip {
 4279                                let anchor = snapshot.anchor_after(selection.end);
 4280                                new_selections
 4281                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4282                                continue;
 4283                            }
 4284                        }
 4285
 4286                        let always_treat_brackets_as_autoclosed = snapshot
 4287                            .language_settings_at(selection.start, cx)
 4288                            .always_treat_brackets_as_autoclosed;
 4289                        if always_treat_brackets_as_autoclosed
 4290                            && is_bracket_pair_end
 4291                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4292                        {
 4293                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4294                            // and the inserted text is a closing bracket and the selection is followed
 4295                            // by the closing bracket then move the selection past the closing bracket.
 4296                            let anchor = snapshot.anchor_after(selection.end);
 4297                            new_selections.push((selection.map(|_| anchor), text.len()));
 4298                            continue;
 4299                        }
 4300                    }
 4301                    // If an opening bracket is 1 character long and is typed while
 4302                    // text is selected, then surround that text with the bracket pair.
 4303                    else if auto_surround
 4304                        && bracket_pair.surround
 4305                        && is_bracket_pair_start
 4306                        && bracket_pair.start.chars().count() == 1
 4307                    {
 4308                        edits.push((selection.start..selection.start, text.clone()));
 4309                        edits.push((
 4310                            selection.end..selection.end,
 4311                            bracket_pair.end.as_str().into(),
 4312                        ));
 4313                        bracket_inserted = true;
 4314                        new_selections.push((
 4315                            Selection {
 4316                                id: selection.id,
 4317                                start: snapshot.anchor_after(selection.start),
 4318                                end: snapshot.anchor_before(selection.end),
 4319                                reversed: selection.reversed,
 4320                                goal: selection.goal,
 4321                            },
 4322                            0,
 4323                        ));
 4324                        continue;
 4325                    }
 4326                }
 4327            }
 4328
 4329            if self.auto_replace_emoji_shortcode
 4330                && selection.is_empty()
 4331                && text.as_ref().ends_with(':')
 4332                && let Some(possible_emoji_short_code) =
 4333                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4334                && !possible_emoji_short_code.is_empty()
 4335                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4336            {
 4337                let emoji_shortcode_start = Point::new(
 4338                    selection.start.row,
 4339                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4340                );
 4341
 4342                // Remove shortcode from buffer
 4343                edits.push((
 4344                    emoji_shortcode_start..selection.start,
 4345                    "".to_string().into(),
 4346                ));
 4347                new_selections.push((
 4348                    Selection {
 4349                        id: selection.id,
 4350                        start: snapshot.anchor_after(emoji_shortcode_start),
 4351                        end: snapshot.anchor_before(selection.start),
 4352                        reversed: selection.reversed,
 4353                        goal: selection.goal,
 4354                    },
 4355                    0,
 4356                ));
 4357
 4358                // Insert emoji
 4359                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4360                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4361                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4362
 4363                continue;
 4364            }
 4365
 4366            // If not handling any auto-close operation, then just replace the selected
 4367            // text with the given input and move the selection to the end of the
 4368            // newly inserted text.
 4369            let anchor = snapshot.anchor_after(selection.end);
 4370            if !self.linked_edit_ranges.is_empty() {
 4371                let start_anchor = snapshot.anchor_before(selection.start);
 4372
 4373                let is_word_char = text.chars().next().is_none_or(|char| {
 4374                    let classifier = snapshot
 4375                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4376                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4377                    classifier.is_word(char)
 4378                });
 4379
 4380                if is_word_char {
 4381                    if let Some(ranges) = self
 4382                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4383                    {
 4384                        for (buffer, edits) in ranges {
 4385                            linked_edits
 4386                                .entry(buffer.clone())
 4387                                .or_default()
 4388                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4389                        }
 4390                    }
 4391                } else {
 4392                    clear_linked_edit_ranges = true;
 4393                }
 4394            }
 4395
 4396            new_selections.push((selection.map(|_| anchor), 0));
 4397            edits.push((selection.start..selection.end, text.clone()));
 4398        }
 4399
 4400        drop(snapshot);
 4401
 4402        self.transact(window, cx, |this, window, cx| {
 4403            if clear_linked_edit_ranges {
 4404                this.linked_edit_ranges.clear();
 4405            }
 4406            let initial_buffer_versions =
 4407                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4408
 4409            this.buffer.update(cx, |buffer, cx| {
 4410                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4411            });
 4412            for (buffer, edits) in linked_edits {
 4413                buffer.update(cx, |buffer, cx| {
 4414                    let snapshot = buffer.snapshot();
 4415                    let edits = edits
 4416                        .into_iter()
 4417                        .map(|(range, text)| {
 4418                            use text::ToPoint as TP;
 4419                            let end_point = TP::to_point(&range.end, &snapshot);
 4420                            let start_point = TP::to_point(&range.start, &snapshot);
 4421                            (start_point..end_point, text)
 4422                        })
 4423                        .sorted_by_key(|(range, _)| range.start);
 4424                    buffer.edit(edits, None, cx);
 4425                })
 4426            }
 4427            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4428            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4429            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4430            let new_selections =
 4431                resolve_selections_wrapping_blocks::<usize, _>(new_anchor_selections, &map)
 4432                    .zip(new_selection_deltas)
 4433                    .map(|(selection, delta)| Selection {
 4434                        id: selection.id,
 4435                        start: selection.start + delta,
 4436                        end: selection.end + delta,
 4437                        reversed: selection.reversed,
 4438                        goal: SelectionGoal::None,
 4439                    })
 4440                    .collect::<Vec<_>>();
 4441
 4442            let mut i = 0;
 4443            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4444                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4445                let start = map.buffer_snapshot().anchor_before(position);
 4446                let end = map.buffer_snapshot().anchor_after(position);
 4447                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4448                    match existing_state
 4449                        .range
 4450                        .start
 4451                        .cmp(&start, map.buffer_snapshot())
 4452                    {
 4453                        Ordering::Less => i += 1,
 4454                        Ordering::Greater => break,
 4455                        Ordering::Equal => {
 4456                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4457                                Ordering::Less => i += 1,
 4458                                Ordering::Equal => break,
 4459                                Ordering::Greater => break,
 4460                            }
 4461                        }
 4462                    }
 4463                }
 4464                this.autoclose_regions.insert(
 4465                    i,
 4466                    AutocloseRegion {
 4467                        selection_id,
 4468                        range: start..end,
 4469                        pair,
 4470                    },
 4471                );
 4472            }
 4473
 4474            let had_active_edit_prediction = this.has_active_edit_prediction();
 4475            this.change_selections(
 4476                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4477                window,
 4478                cx,
 4479                |s| s.select(new_selections),
 4480            );
 4481
 4482            if !bracket_inserted
 4483                && let Some(on_type_format_task) =
 4484                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4485            {
 4486                on_type_format_task.detach_and_log_err(cx);
 4487            }
 4488
 4489            let editor_settings = EditorSettings::get_global(cx);
 4490            if bracket_inserted
 4491                && (editor_settings.auto_signature_help
 4492                    || editor_settings.show_signature_help_after_edits)
 4493            {
 4494                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4495            }
 4496
 4497            let trigger_in_words =
 4498                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4499            if this.hard_wrap.is_some() {
 4500                let latest: Range<Point> = this.selections.newest(&map).range();
 4501                if latest.is_empty()
 4502                    && this
 4503                        .buffer()
 4504                        .read(cx)
 4505                        .snapshot(cx)
 4506                        .line_len(MultiBufferRow(latest.start.row))
 4507                        == latest.start.column
 4508                {
 4509                    this.rewrap_impl(
 4510                        RewrapOptions {
 4511                            override_language_settings: true,
 4512                            preserve_existing_whitespace: true,
 4513                        },
 4514                        cx,
 4515                    )
 4516                }
 4517            }
 4518            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4519            refresh_linked_ranges(this, window, cx);
 4520            this.refresh_edit_prediction(true, false, window, cx);
 4521            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4522        });
 4523    }
 4524
 4525    fn find_possible_emoji_shortcode_at_position(
 4526        snapshot: &MultiBufferSnapshot,
 4527        position: Point,
 4528    ) -> Option<String> {
 4529        let mut chars = Vec::new();
 4530        let mut found_colon = false;
 4531        for char in snapshot.reversed_chars_at(position).take(100) {
 4532            // Found a possible emoji shortcode in the middle of the buffer
 4533            if found_colon {
 4534                if char.is_whitespace() {
 4535                    chars.reverse();
 4536                    return Some(chars.iter().collect());
 4537                }
 4538                // If the previous character is not a whitespace, we are in the middle of a word
 4539                // and we only want to complete the shortcode if the word is made up of other emojis
 4540                let mut containing_word = String::new();
 4541                for ch in snapshot
 4542                    .reversed_chars_at(position)
 4543                    .skip(chars.len() + 1)
 4544                    .take(100)
 4545                {
 4546                    if ch.is_whitespace() {
 4547                        break;
 4548                    }
 4549                    containing_word.push(ch);
 4550                }
 4551                let containing_word = containing_word.chars().rev().collect::<String>();
 4552                if util::word_consists_of_emojis(containing_word.as_str()) {
 4553                    chars.reverse();
 4554                    return Some(chars.iter().collect());
 4555                }
 4556            }
 4557
 4558            if char.is_whitespace() || !char.is_ascii() {
 4559                return None;
 4560            }
 4561            if char == ':' {
 4562                found_colon = true;
 4563            } else {
 4564                chars.push(char);
 4565            }
 4566        }
 4567        // Found a possible emoji shortcode at the beginning of the buffer
 4568        chars.reverse();
 4569        Some(chars.iter().collect())
 4570    }
 4571
 4572    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4573        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4574        self.transact(window, cx, |this, window, cx| {
 4575            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4576                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
 4577                let multi_buffer = this.buffer.read(cx);
 4578                let buffer = multi_buffer.snapshot(cx);
 4579                selections
 4580                    .iter()
 4581                    .map(|selection| {
 4582                        let start_point = selection.start.to_point(&buffer);
 4583                        let mut existing_indent =
 4584                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4585                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4586                        let start = selection.start;
 4587                        let end = selection.end;
 4588                        let selection_is_empty = start == end;
 4589                        let language_scope = buffer.language_scope_at(start);
 4590                        let (
 4591                            comment_delimiter,
 4592                            doc_delimiter,
 4593                            insert_extra_newline,
 4594                            indent_on_newline,
 4595                            indent_on_extra_newline,
 4596                        ) = if let Some(language) = &language_scope {
 4597                            let mut insert_extra_newline =
 4598                                insert_extra_newline_brackets(&buffer, start..end, language)
 4599                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4600
 4601                            // Comment extension on newline is allowed only for cursor selections
 4602                            let comment_delimiter = maybe!({
 4603                                if !selection_is_empty {
 4604                                    return None;
 4605                                }
 4606
 4607                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4608                                    return None;
 4609                                }
 4610
 4611                                let delimiters = language.line_comment_prefixes();
 4612                                let max_len_of_delimiter =
 4613                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4614                                let (snapshot, range) =
 4615                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4616
 4617                                let num_of_whitespaces = snapshot
 4618                                    .chars_for_range(range.clone())
 4619                                    .take_while(|c| c.is_whitespace())
 4620                                    .count();
 4621                                let comment_candidate = snapshot
 4622                                    .chars_for_range(range.clone())
 4623                                    .skip(num_of_whitespaces)
 4624                                    .take(max_len_of_delimiter)
 4625                                    .collect::<String>();
 4626                                let (delimiter, trimmed_len) = delimiters
 4627                                    .iter()
 4628                                    .filter_map(|delimiter| {
 4629                                        let prefix = delimiter.trim_end();
 4630                                        if comment_candidate.starts_with(prefix) {
 4631                                            Some((delimiter, prefix.len()))
 4632                                        } else {
 4633                                            None
 4634                                        }
 4635                                    })
 4636                                    .max_by_key(|(_, len)| *len)?;
 4637
 4638                                if let Some(BlockCommentConfig {
 4639                                    start: block_start, ..
 4640                                }) = language.block_comment()
 4641                                {
 4642                                    let block_start_trimmed = block_start.trim_end();
 4643                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4644                                        let line_content = snapshot
 4645                                            .chars_for_range(range)
 4646                                            .skip(num_of_whitespaces)
 4647                                            .take(block_start_trimmed.len())
 4648                                            .collect::<String>();
 4649
 4650                                        if line_content.starts_with(block_start_trimmed) {
 4651                                            return None;
 4652                                        }
 4653                                    }
 4654                                }
 4655
 4656                                let cursor_is_placed_after_comment_marker =
 4657                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4658                                if cursor_is_placed_after_comment_marker {
 4659                                    Some(delimiter.clone())
 4660                                } else {
 4661                                    None
 4662                                }
 4663                            });
 4664
 4665                            let mut indent_on_newline = IndentSize::spaces(0);
 4666                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4667
 4668                            let doc_delimiter = maybe!({
 4669                                if !selection_is_empty {
 4670                                    return None;
 4671                                }
 4672
 4673                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4674                                    return None;
 4675                                }
 4676
 4677                                let BlockCommentConfig {
 4678                                    start: start_tag,
 4679                                    end: end_tag,
 4680                                    prefix: delimiter,
 4681                                    tab_size: len,
 4682                                } = language.documentation_comment()?;
 4683                                let is_within_block_comment = buffer
 4684                                    .language_scope_at(start_point)
 4685                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4686                                if !is_within_block_comment {
 4687                                    return None;
 4688                                }
 4689
 4690                                let (snapshot, range) =
 4691                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4692
 4693                                let num_of_whitespaces = snapshot
 4694                                    .chars_for_range(range.clone())
 4695                                    .take_while(|c| c.is_whitespace())
 4696                                    .count();
 4697
 4698                                // 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.
 4699                                let column = start_point.column;
 4700                                let cursor_is_after_start_tag = {
 4701                                    let start_tag_len = start_tag.len();
 4702                                    let start_tag_line = snapshot
 4703                                        .chars_for_range(range.clone())
 4704                                        .skip(num_of_whitespaces)
 4705                                        .take(start_tag_len)
 4706                                        .collect::<String>();
 4707                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4708                                        num_of_whitespaces + start_tag_len <= column as usize
 4709                                    } else {
 4710                                        false
 4711                                    }
 4712                                };
 4713
 4714                                let cursor_is_after_delimiter = {
 4715                                    let delimiter_trim = delimiter.trim_end();
 4716                                    let delimiter_line = snapshot
 4717                                        .chars_for_range(range.clone())
 4718                                        .skip(num_of_whitespaces)
 4719                                        .take(delimiter_trim.len())
 4720                                        .collect::<String>();
 4721                                    if delimiter_line.starts_with(delimiter_trim) {
 4722                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4723                                    } else {
 4724                                        false
 4725                                    }
 4726                                };
 4727
 4728                                let cursor_is_before_end_tag_if_exists = {
 4729                                    let mut char_position = 0u32;
 4730                                    let mut end_tag_offset = None;
 4731
 4732                                    'outer: for chunk in snapshot.text_for_range(range) {
 4733                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4734                                            let chars_before_match =
 4735                                                chunk[..byte_pos].chars().count() as u32;
 4736                                            end_tag_offset =
 4737                                                Some(char_position + chars_before_match);
 4738                                            break 'outer;
 4739                                        }
 4740                                        char_position += chunk.chars().count() as u32;
 4741                                    }
 4742
 4743                                    if let Some(end_tag_offset) = end_tag_offset {
 4744                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4745                                        if cursor_is_after_start_tag {
 4746                                            if cursor_is_before_end_tag {
 4747                                                insert_extra_newline = true;
 4748                                            }
 4749                                            let cursor_is_at_start_of_end_tag =
 4750                                                column == end_tag_offset;
 4751                                            if cursor_is_at_start_of_end_tag {
 4752                                                indent_on_extra_newline.len = *len;
 4753                                            }
 4754                                        }
 4755                                        cursor_is_before_end_tag
 4756                                    } else {
 4757                                        true
 4758                                    }
 4759                                };
 4760
 4761                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4762                                    && cursor_is_before_end_tag_if_exists
 4763                                {
 4764                                    if cursor_is_after_start_tag {
 4765                                        indent_on_newline.len = *len;
 4766                                    }
 4767                                    Some(delimiter.clone())
 4768                                } else {
 4769                                    None
 4770                                }
 4771                            });
 4772
 4773                            (
 4774                                comment_delimiter,
 4775                                doc_delimiter,
 4776                                insert_extra_newline,
 4777                                indent_on_newline,
 4778                                indent_on_extra_newline,
 4779                            )
 4780                        } else {
 4781                            (
 4782                                None,
 4783                                None,
 4784                                false,
 4785                                IndentSize::default(),
 4786                                IndentSize::default(),
 4787                            )
 4788                        };
 4789
 4790                        let prevent_auto_indent = doc_delimiter.is_some();
 4791                        let delimiter = comment_delimiter.or(doc_delimiter);
 4792
 4793                        let capacity_for_delimiter =
 4794                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4795                        let mut new_text = String::with_capacity(
 4796                            1 + capacity_for_delimiter
 4797                                + existing_indent.len as usize
 4798                                + indent_on_newline.len as usize
 4799                                + indent_on_extra_newline.len as usize,
 4800                        );
 4801                        new_text.push('\n');
 4802                        new_text.extend(existing_indent.chars());
 4803                        new_text.extend(indent_on_newline.chars());
 4804
 4805                        if let Some(delimiter) = &delimiter {
 4806                            new_text.push_str(delimiter);
 4807                        }
 4808
 4809                        if insert_extra_newline {
 4810                            new_text.push('\n');
 4811                            new_text.extend(existing_indent.chars());
 4812                            new_text.extend(indent_on_extra_newline.chars());
 4813                        }
 4814
 4815                        let anchor = buffer.anchor_after(end);
 4816                        let new_selection = selection.map(|_| anchor);
 4817                        (
 4818                            ((start..end, new_text), prevent_auto_indent),
 4819                            (insert_extra_newline, new_selection),
 4820                        )
 4821                    })
 4822                    .unzip()
 4823            };
 4824
 4825            let mut auto_indent_edits = Vec::new();
 4826            let mut edits = Vec::new();
 4827            for (edit, prevent_auto_indent) in edits_with_flags {
 4828                if prevent_auto_indent {
 4829                    edits.push(edit);
 4830                } else {
 4831                    auto_indent_edits.push(edit);
 4832                }
 4833            }
 4834            if !edits.is_empty() {
 4835                this.edit(edits, cx);
 4836            }
 4837            if !auto_indent_edits.is_empty() {
 4838                this.edit_with_autoindent(auto_indent_edits, cx);
 4839            }
 4840
 4841            let buffer = this.buffer.read(cx).snapshot(cx);
 4842            let new_selections = selection_info
 4843                .into_iter()
 4844                .map(|(extra_newline_inserted, new_selection)| {
 4845                    let mut cursor = new_selection.end.to_point(&buffer);
 4846                    if extra_newline_inserted {
 4847                        cursor.row -= 1;
 4848                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4849                    }
 4850                    new_selection.map(|_| cursor)
 4851                })
 4852                .collect();
 4853
 4854            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4855            this.refresh_edit_prediction(true, false, window, cx);
 4856        });
 4857    }
 4858
 4859    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4860        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4861
 4862        let buffer = self.buffer.read(cx);
 4863        let snapshot = buffer.snapshot(cx);
 4864
 4865        let mut edits = Vec::new();
 4866        let mut rows = Vec::new();
 4867
 4868        for (rows_inserted, selection) in self
 4869            .selections
 4870            .all_adjusted(&self.display_snapshot(cx))
 4871            .into_iter()
 4872            .enumerate()
 4873        {
 4874            let cursor = selection.head();
 4875            let row = cursor.row;
 4876
 4877            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4878
 4879            let newline = "\n".to_string();
 4880            edits.push((start_of_line..start_of_line, newline));
 4881
 4882            rows.push(row + rows_inserted as u32);
 4883        }
 4884
 4885        self.transact(window, cx, |editor, window, cx| {
 4886            editor.edit(edits, cx);
 4887
 4888            editor.change_selections(Default::default(), window, cx, |s| {
 4889                let mut index = 0;
 4890                s.move_cursors_with(|map, _, _| {
 4891                    let row = rows[index];
 4892                    index += 1;
 4893
 4894                    let point = Point::new(row, 0);
 4895                    let boundary = map.next_line_boundary(point).1;
 4896                    let clipped = map.clip_point(boundary, Bias::Left);
 4897
 4898                    (clipped, SelectionGoal::None)
 4899                });
 4900            });
 4901
 4902            let mut indent_edits = Vec::new();
 4903            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4904            for row in rows {
 4905                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4906                for (row, indent) in indents {
 4907                    if indent.len == 0 {
 4908                        continue;
 4909                    }
 4910
 4911                    let text = match indent.kind {
 4912                        IndentKind::Space => " ".repeat(indent.len as usize),
 4913                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4914                    };
 4915                    let point = Point::new(row.0, 0);
 4916                    indent_edits.push((point..point, text));
 4917                }
 4918            }
 4919            editor.edit(indent_edits, cx);
 4920        });
 4921    }
 4922
 4923    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4924        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4925
 4926        let buffer = self.buffer.read(cx);
 4927        let snapshot = buffer.snapshot(cx);
 4928
 4929        let mut edits = Vec::new();
 4930        let mut rows = Vec::new();
 4931        let mut rows_inserted = 0;
 4932
 4933        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 4934            let cursor = selection.head();
 4935            let row = cursor.row;
 4936
 4937            let point = Point::new(row + 1, 0);
 4938            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4939
 4940            let newline = "\n".to_string();
 4941            edits.push((start_of_line..start_of_line, newline));
 4942
 4943            rows_inserted += 1;
 4944            rows.push(row + rows_inserted);
 4945        }
 4946
 4947        self.transact(window, cx, |editor, window, cx| {
 4948            editor.edit(edits, cx);
 4949
 4950            editor.change_selections(Default::default(), window, cx, |s| {
 4951                let mut index = 0;
 4952                s.move_cursors_with(|map, _, _| {
 4953                    let row = rows[index];
 4954                    index += 1;
 4955
 4956                    let point = Point::new(row, 0);
 4957                    let boundary = map.next_line_boundary(point).1;
 4958                    let clipped = map.clip_point(boundary, Bias::Left);
 4959
 4960                    (clipped, SelectionGoal::None)
 4961                });
 4962            });
 4963
 4964            let mut indent_edits = Vec::new();
 4965            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4966            for row in rows {
 4967                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4968                for (row, indent) in indents {
 4969                    if indent.len == 0 {
 4970                        continue;
 4971                    }
 4972
 4973                    let text = match indent.kind {
 4974                        IndentKind::Space => " ".repeat(indent.len as usize),
 4975                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4976                    };
 4977                    let point = Point::new(row.0, 0);
 4978                    indent_edits.push((point..point, text));
 4979                }
 4980            }
 4981            editor.edit(indent_edits, cx);
 4982        });
 4983    }
 4984
 4985    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4986        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4987            original_indent_columns: Vec::new(),
 4988        });
 4989        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4990    }
 4991
 4992    fn insert_with_autoindent_mode(
 4993        &mut self,
 4994        text: &str,
 4995        autoindent_mode: Option<AutoindentMode>,
 4996        window: &mut Window,
 4997        cx: &mut Context<Self>,
 4998    ) {
 4999        if self.read_only(cx) {
 5000            return;
 5001        }
 5002
 5003        let text: Arc<str> = text.into();
 5004        self.transact(window, cx, |this, window, cx| {
 5005            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5006            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5007                let anchors = {
 5008                    let snapshot = buffer.read(cx);
 5009                    old_selections
 5010                        .iter()
 5011                        .map(|s| {
 5012                            let anchor = snapshot.anchor_after(s.head());
 5013                            s.map(|_| anchor)
 5014                        })
 5015                        .collect::<Vec<_>>()
 5016                };
 5017                buffer.edit(
 5018                    old_selections
 5019                        .iter()
 5020                        .map(|s| (s.start..s.end, text.clone())),
 5021                    autoindent_mode,
 5022                    cx,
 5023                );
 5024                anchors
 5025            });
 5026
 5027            this.change_selections(Default::default(), window, cx, |s| {
 5028                s.select_anchors(selection_anchors);
 5029            });
 5030
 5031            cx.notify();
 5032        });
 5033    }
 5034
 5035    fn trigger_completion_on_input(
 5036        &mut self,
 5037        text: &str,
 5038        trigger_in_words: bool,
 5039        window: &mut Window,
 5040        cx: &mut Context<Self>,
 5041    ) {
 5042        let completions_source = self
 5043            .context_menu
 5044            .borrow()
 5045            .as_ref()
 5046            .and_then(|menu| match menu {
 5047                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5048                CodeContextMenu::CodeActions(_) => None,
 5049            });
 5050
 5051        match completions_source {
 5052            Some(CompletionsMenuSource::Words { .. }) => {
 5053                self.open_or_update_completions_menu(
 5054                    Some(CompletionsMenuSource::Words {
 5055                        ignore_threshold: false,
 5056                    }),
 5057                    None,
 5058                    window,
 5059                    cx,
 5060                );
 5061            }
 5062            Some(CompletionsMenuSource::Normal)
 5063            | Some(CompletionsMenuSource::SnippetChoices)
 5064            | None
 5065                if self.is_completion_trigger(
 5066                    text,
 5067                    trigger_in_words,
 5068                    completions_source.is_some(),
 5069                    cx,
 5070                ) =>
 5071            {
 5072                self.show_completions(
 5073                    &ShowCompletions {
 5074                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 5075                    },
 5076                    window,
 5077                    cx,
 5078                )
 5079            }
 5080            _ => {
 5081                self.hide_context_menu(window, cx);
 5082            }
 5083        }
 5084    }
 5085
 5086    fn is_completion_trigger(
 5087        &self,
 5088        text: &str,
 5089        trigger_in_words: bool,
 5090        menu_is_open: bool,
 5091        cx: &mut Context<Self>,
 5092    ) -> bool {
 5093        let position = self.selections.newest_anchor().head();
 5094        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 5095            return false;
 5096        };
 5097
 5098        if let Some(completion_provider) = &self.completion_provider {
 5099            completion_provider.is_completion_trigger(
 5100                &buffer,
 5101                position.text_anchor,
 5102                text,
 5103                trigger_in_words,
 5104                menu_is_open,
 5105                cx,
 5106            )
 5107        } else {
 5108            false
 5109        }
 5110    }
 5111
 5112    /// If any empty selections is touching the start of its innermost containing autoclose
 5113    /// region, expand it to select the brackets.
 5114    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5115        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5116        let buffer = self.buffer.read(cx).read(cx);
 5117        let new_selections = self
 5118            .selections_with_autoclose_regions(selections, &buffer)
 5119            .map(|(mut selection, region)| {
 5120                if !selection.is_empty() {
 5121                    return selection;
 5122                }
 5123
 5124                if let Some(region) = region {
 5125                    let mut range = region.range.to_offset(&buffer);
 5126                    if selection.start == range.start && range.start >= region.pair.start.len() {
 5127                        range.start -= region.pair.start.len();
 5128                        if buffer.contains_str_at(range.start, &region.pair.start)
 5129                            && buffer.contains_str_at(range.end, &region.pair.end)
 5130                        {
 5131                            range.end += region.pair.end.len();
 5132                            selection.start = range.start;
 5133                            selection.end = range.end;
 5134
 5135                            return selection;
 5136                        }
 5137                    }
 5138                }
 5139
 5140                let always_treat_brackets_as_autoclosed = buffer
 5141                    .language_settings_at(selection.start, cx)
 5142                    .always_treat_brackets_as_autoclosed;
 5143
 5144                if !always_treat_brackets_as_autoclosed {
 5145                    return selection;
 5146                }
 5147
 5148                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5149                    for (pair, enabled) in scope.brackets() {
 5150                        if !enabled || !pair.close {
 5151                            continue;
 5152                        }
 5153
 5154                        if buffer.contains_str_at(selection.start, &pair.end) {
 5155                            let pair_start_len = pair.start.len();
 5156                            if buffer.contains_str_at(
 5157                                selection.start.saturating_sub(pair_start_len),
 5158                                &pair.start,
 5159                            ) {
 5160                                selection.start -= pair_start_len;
 5161                                selection.end += pair.end.len();
 5162
 5163                                return selection;
 5164                            }
 5165                        }
 5166                    }
 5167                }
 5168
 5169                selection
 5170            })
 5171            .collect();
 5172
 5173        drop(buffer);
 5174        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5175            selections.select(new_selections)
 5176        });
 5177    }
 5178
 5179    /// Iterate the given selections, and for each one, find the smallest surrounding
 5180    /// autoclose region. This uses the ordering of the selections and the autoclose
 5181    /// regions to avoid repeated comparisons.
 5182    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5183        &'a self,
 5184        selections: impl IntoIterator<Item = Selection<D>>,
 5185        buffer: &'a MultiBufferSnapshot,
 5186    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5187        let mut i = 0;
 5188        let mut regions = self.autoclose_regions.as_slice();
 5189        selections.into_iter().map(move |selection| {
 5190            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5191
 5192            let mut enclosing = None;
 5193            while let Some(pair_state) = regions.get(i) {
 5194                if pair_state.range.end.to_offset(buffer) < range.start {
 5195                    regions = &regions[i + 1..];
 5196                    i = 0;
 5197                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5198                    break;
 5199                } else {
 5200                    if pair_state.selection_id == selection.id {
 5201                        enclosing = Some(pair_state);
 5202                    }
 5203                    i += 1;
 5204                }
 5205            }
 5206
 5207            (selection, enclosing)
 5208        })
 5209    }
 5210
 5211    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5212    fn invalidate_autoclose_regions(
 5213        &mut self,
 5214        mut selections: &[Selection<Anchor>],
 5215        buffer: &MultiBufferSnapshot,
 5216    ) {
 5217        self.autoclose_regions.retain(|state| {
 5218            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5219                return false;
 5220            }
 5221
 5222            let mut i = 0;
 5223            while let Some(selection) = selections.get(i) {
 5224                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5225                    selections = &selections[1..];
 5226                    continue;
 5227                }
 5228                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5229                    break;
 5230                }
 5231                if selection.id == state.selection_id {
 5232                    return true;
 5233                } else {
 5234                    i += 1;
 5235                }
 5236            }
 5237            false
 5238        });
 5239    }
 5240
 5241    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5242        let offset = position.to_offset(buffer);
 5243        let (word_range, kind) =
 5244            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5245        if offset > word_range.start && kind == Some(CharKind::Word) {
 5246            Some(
 5247                buffer
 5248                    .text_for_range(word_range.start..offset)
 5249                    .collect::<String>(),
 5250            )
 5251        } else {
 5252            None
 5253        }
 5254    }
 5255
 5256    pub fn visible_excerpts(
 5257        &self,
 5258        cx: &mut Context<Editor>,
 5259    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5260        let Some(project) = self.project() else {
 5261            return HashMap::default();
 5262        };
 5263        let project = project.read(cx);
 5264        let multi_buffer = self.buffer().read(cx);
 5265        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5266        let multi_buffer_visible_start = self
 5267            .scroll_manager
 5268            .anchor()
 5269            .anchor
 5270            .to_point(&multi_buffer_snapshot);
 5271        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5272            multi_buffer_visible_start
 5273                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5274            Bias::Left,
 5275        );
 5276        multi_buffer_snapshot
 5277            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5278            .into_iter()
 5279            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5280            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5281                let buffer_file = project::File::from_dyn(buffer.file())?;
 5282                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5283                let worktree_entry = buffer_worktree
 5284                    .read(cx)
 5285                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5286                if worktree_entry.is_ignored {
 5287                    None
 5288                } else {
 5289                    Some((
 5290                        excerpt_id,
 5291                        (
 5292                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5293                            buffer.version().clone(),
 5294                            excerpt_visible_range,
 5295                        ),
 5296                    ))
 5297                }
 5298            })
 5299            .collect()
 5300    }
 5301
 5302    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5303        TextLayoutDetails {
 5304            text_system: window.text_system().clone(),
 5305            editor_style: self.style.clone().unwrap(),
 5306            rem_size: window.rem_size(),
 5307            scroll_anchor: self.scroll_manager.anchor(),
 5308            visible_rows: self.visible_line_count(),
 5309            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5310        }
 5311    }
 5312
 5313    fn trigger_on_type_formatting(
 5314        &self,
 5315        input: String,
 5316        window: &mut Window,
 5317        cx: &mut Context<Self>,
 5318    ) -> Option<Task<Result<()>>> {
 5319        if input.len() != 1 {
 5320            return None;
 5321        }
 5322
 5323        let project = self.project()?;
 5324        let position = self.selections.newest_anchor().head();
 5325        let (buffer, buffer_position) = self
 5326            .buffer
 5327            .read(cx)
 5328            .text_anchor_for_position(position, cx)?;
 5329
 5330        let settings = language_settings::language_settings(
 5331            buffer
 5332                .read(cx)
 5333                .language_at(buffer_position)
 5334                .map(|l| l.name()),
 5335            buffer.read(cx).file(),
 5336            cx,
 5337        );
 5338        if !settings.use_on_type_format {
 5339            return None;
 5340        }
 5341
 5342        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5343        // hence we do LSP request & edit on host side only — add formats to host's history.
 5344        let push_to_lsp_host_history = true;
 5345        // If this is not the host, append its history with new edits.
 5346        let push_to_client_history = project.read(cx).is_via_collab();
 5347
 5348        let on_type_formatting = project.update(cx, |project, cx| {
 5349            project.on_type_format(
 5350                buffer.clone(),
 5351                buffer_position,
 5352                input,
 5353                push_to_lsp_host_history,
 5354                cx,
 5355            )
 5356        });
 5357        Some(cx.spawn_in(window, async move |editor, cx| {
 5358            if let Some(transaction) = on_type_formatting.await? {
 5359                if push_to_client_history {
 5360                    buffer
 5361                        .update(cx, |buffer, _| {
 5362                            buffer.push_transaction(transaction, Instant::now());
 5363                            buffer.finalize_last_transaction();
 5364                        })
 5365                        .ok();
 5366                }
 5367                editor.update(cx, |editor, cx| {
 5368                    editor.refresh_document_highlights(cx);
 5369                })?;
 5370            }
 5371            Ok(())
 5372        }))
 5373    }
 5374
 5375    pub fn show_word_completions(
 5376        &mut self,
 5377        _: &ShowWordCompletions,
 5378        window: &mut Window,
 5379        cx: &mut Context<Self>,
 5380    ) {
 5381        self.open_or_update_completions_menu(
 5382            Some(CompletionsMenuSource::Words {
 5383                ignore_threshold: true,
 5384            }),
 5385            None,
 5386            window,
 5387            cx,
 5388        );
 5389    }
 5390
 5391    pub fn show_completions(
 5392        &mut self,
 5393        options: &ShowCompletions,
 5394        window: &mut Window,
 5395        cx: &mut Context<Self>,
 5396    ) {
 5397        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5398    }
 5399
 5400    fn open_or_update_completions_menu(
 5401        &mut self,
 5402        requested_source: Option<CompletionsMenuSource>,
 5403        trigger: Option<&str>,
 5404        window: &mut Window,
 5405        cx: &mut Context<Self>,
 5406    ) {
 5407        if self.pending_rename.is_some() {
 5408            return;
 5409        }
 5410
 5411        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5412
 5413        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5414        // inserted and selected. To handle that case, the start of the selection is used so that
 5415        // the menu starts with all choices.
 5416        let position = self
 5417            .selections
 5418            .newest_anchor()
 5419            .start
 5420            .bias_right(&multibuffer_snapshot);
 5421        if position.diff_base_anchor.is_some() {
 5422            return;
 5423        }
 5424        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5425        let Some(buffer) = buffer_position
 5426            .buffer_id
 5427            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5428        else {
 5429            return;
 5430        };
 5431        let buffer_snapshot = buffer.read(cx).snapshot();
 5432
 5433        let query: Option<Arc<String>> =
 5434            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5435                .map(|query| query.into());
 5436
 5437        drop(multibuffer_snapshot);
 5438
 5439        // Hide the current completions menu when query is empty. Without this, cached
 5440        // completions from before the trigger char may be reused (#32774).
 5441        if query.is_none() {
 5442            let menu_is_open = matches!(
 5443                self.context_menu.borrow().as_ref(),
 5444                Some(CodeContextMenu::Completions(_))
 5445            );
 5446            if menu_is_open {
 5447                self.hide_context_menu(window, cx);
 5448            }
 5449        }
 5450
 5451        let mut ignore_word_threshold = false;
 5452        let provider = match requested_source {
 5453            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5454            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5455                ignore_word_threshold = ignore_threshold;
 5456                None
 5457            }
 5458            Some(CompletionsMenuSource::SnippetChoices) => {
 5459                log::error!("bug: SnippetChoices requested_source is not handled");
 5460                None
 5461            }
 5462        };
 5463
 5464        let sort_completions = provider
 5465            .as_ref()
 5466            .is_some_and(|provider| provider.sort_completions());
 5467
 5468        let filter_completions = provider
 5469            .as_ref()
 5470            .is_none_or(|provider| provider.filter_completions());
 5471
 5472        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5473            if filter_completions {
 5474                menu.filter(query.clone(), provider.clone(), window, cx);
 5475            }
 5476            // When `is_incomplete` is false, no need to re-query completions when the current query
 5477            // is a suffix of the initial query.
 5478            if !menu.is_incomplete {
 5479                // If the new query is a suffix of the old query (typing more characters) and
 5480                // the previous result was complete, the existing completions can be filtered.
 5481                //
 5482                // Note that this is always true for snippet completions.
 5483                let query_matches = match (&menu.initial_query, &query) {
 5484                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5485                    (None, _) => true,
 5486                    _ => false,
 5487                };
 5488                if query_matches {
 5489                    let position_matches = if menu.initial_position == position {
 5490                        true
 5491                    } else {
 5492                        let snapshot = self.buffer.read(cx).read(cx);
 5493                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5494                    };
 5495                    if position_matches {
 5496                        return;
 5497                    }
 5498                }
 5499            }
 5500        };
 5501
 5502        let trigger_kind = match trigger {
 5503            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5504                CompletionTriggerKind::TRIGGER_CHARACTER
 5505            }
 5506            _ => CompletionTriggerKind::INVOKED,
 5507        };
 5508        let completion_context = CompletionContext {
 5509            trigger_character: trigger.and_then(|trigger| {
 5510                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5511                    Some(String::from(trigger))
 5512                } else {
 5513                    None
 5514                }
 5515            }),
 5516            trigger_kind,
 5517        };
 5518
 5519        let Anchor {
 5520            excerpt_id: buffer_excerpt_id,
 5521            text_anchor: buffer_position,
 5522            ..
 5523        } = buffer_position;
 5524
 5525        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5526            buffer_snapshot.surrounding_word(buffer_position, None)
 5527        {
 5528            let word_to_exclude = buffer_snapshot
 5529                .text_for_range(word_range.clone())
 5530                .collect::<String>();
 5531            (
 5532                buffer_snapshot.anchor_before(word_range.start)
 5533                    ..buffer_snapshot.anchor_after(buffer_position),
 5534                Some(word_to_exclude),
 5535            )
 5536        } else {
 5537            (buffer_position..buffer_position, None)
 5538        };
 5539
 5540        let language = buffer_snapshot
 5541            .language_at(buffer_position)
 5542            .map(|language| language.name());
 5543
 5544        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5545            .completions
 5546            .clone();
 5547
 5548        let show_completion_documentation = buffer_snapshot
 5549            .settings_at(buffer_position, cx)
 5550            .show_completion_documentation;
 5551
 5552        // The document can be large, so stay in reasonable bounds when searching for words,
 5553        // otherwise completion pop-up might be slow to appear.
 5554        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5555        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5556        let min_word_search = buffer_snapshot.clip_point(
 5557            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5558            Bias::Left,
 5559        );
 5560        let max_word_search = buffer_snapshot.clip_point(
 5561            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5562            Bias::Right,
 5563        );
 5564        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5565            ..buffer_snapshot.point_to_offset(max_word_search);
 5566
 5567        let skip_digits = query
 5568            .as_ref()
 5569            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5570
 5571        let omit_word_completions = !self.word_completions_enabled
 5572            || (!ignore_word_threshold
 5573                && match &query {
 5574                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5575                    None => completion_settings.words_min_length != 0,
 5576                });
 5577
 5578        let (mut words, provider_responses) = match &provider {
 5579            Some(provider) => {
 5580                let provider_responses = provider.completions(
 5581                    buffer_excerpt_id,
 5582                    &buffer,
 5583                    buffer_position,
 5584                    completion_context,
 5585                    window,
 5586                    cx,
 5587                );
 5588
 5589                let words = match (omit_word_completions, completion_settings.words) {
 5590                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5591                        Task::ready(BTreeMap::default())
 5592                    }
 5593                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5594                        .background_spawn(async move {
 5595                            buffer_snapshot.words_in_range(WordsQuery {
 5596                                fuzzy_contents: None,
 5597                                range: word_search_range,
 5598                                skip_digits,
 5599                            })
 5600                        }),
 5601                };
 5602
 5603                (words, provider_responses)
 5604            }
 5605            None => {
 5606                let words = if omit_word_completions {
 5607                    Task::ready(BTreeMap::default())
 5608                } else {
 5609                    cx.background_spawn(async move {
 5610                        buffer_snapshot.words_in_range(WordsQuery {
 5611                            fuzzy_contents: None,
 5612                            range: word_search_range,
 5613                            skip_digits,
 5614                        })
 5615                    })
 5616                };
 5617                (words, Task::ready(Ok(Vec::new())))
 5618            }
 5619        };
 5620
 5621        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5622
 5623        let id = post_inc(&mut self.next_completion_id);
 5624        let task = cx.spawn_in(window, async move |editor, cx| {
 5625            let Ok(()) = editor.update(cx, |this, _| {
 5626                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5627            }) else {
 5628                return;
 5629            };
 5630
 5631            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5632            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5633            let mut completions = Vec::new();
 5634            let mut is_incomplete = false;
 5635            let mut display_options: Option<CompletionDisplayOptions> = None;
 5636            if let Some(provider_responses) = provider_responses.await.log_err()
 5637                && !provider_responses.is_empty()
 5638            {
 5639                for response in provider_responses {
 5640                    completions.extend(response.completions);
 5641                    is_incomplete = is_incomplete || response.is_incomplete;
 5642                    match display_options.as_mut() {
 5643                        None => {
 5644                            display_options = Some(response.display_options);
 5645                        }
 5646                        Some(options) => options.merge(&response.display_options),
 5647                    }
 5648                }
 5649                if completion_settings.words == WordsCompletionMode::Fallback {
 5650                    words = Task::ready(BTreeMap::default());
 5651                }
 5652            }
 5653            let display_options = display_options.unwrap_or_default();
 5654
 5655            let mut words = words.await;
 5656            if let Some(word_to_exclude) = &word_to_exclude {
 5657                words.remove(word_to_exclude);
 5658            }
 5659            for lsp_completion in &completions {
 5660                words.remove(&lsp_completion.new_text);
 5661            }
 5662            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5663                replace_range: word_replace_range.clone(),
 5664                new_text: word.clone(),
 5665                label: CodeLabel::plain(word, None),
 5666                icon_path: None,
 5667                documentation: None,
 5668                source: CompletionSource::BufferWord {
 5669                    word_range,
 5670                    resolved: false,
 5671                },
 5672                insert_text_mode: Some(InsertTextMode::AS_IS),
 5673                confirm: None,
 5674            }));
 5675
 5676            let menu = if completions.is_empty() {
 5677                None
 5678            } else {
 5679                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5680                    let languages = editor
 5681                        .workspace
 5682                        .as_ref()
 5683                        .and_then(|(workspace, _)| workspace.upgrade())
 5684                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5685                    let menu = CompletionsMenu::new(
 5686                        id,
 5687                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5688                        sort_completions,
 5689                        show_completion_documentation,
 5690                        position,
 5691                        query.clone(),
 5692                        is_incomplete,
 5693                        buffer.clone(),
 5694                        completions.into(),
 5695                        display_options,
 5696                        snippet_sort_order,
 5697                        languages,
 5698                        language,
 5699                        cx,
 5700                    );
 5701
 5702                    let query = if filter_completions { query } else { None };
 5703                    let matches_task = if let Some(query) = query {
 5704                        menu.do_async_filtering(query, cx)
 5705                    } else {
 5706                        Task::ready(menu.unfiltered_matches())
 5707                    };
 5708                    (menu, matches_task)
 5709                }) else {
 5710                    return;
 5711                };
 5712
 5713                let matches = matches_task.await;
 5714
 5715                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5716                    // Newer menu already set, so exit.
 5717                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5718                        editor.context_menu.borrow().as_ref()
 5719                        && prev_menu.id > id
 5720                    {
 5721                        return;
 5722                    };
 5723
 5724                    // Only valid to take prev_menu because it the new menu is immediately set
 5725                    // below, or the menu is hidden.
 5726                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5727                        editor.context_menu.borrow_mut().take()
 5728                    {
 5729                        let position_matches =
 5730                            if prev_menu.initial_position == menu.initial_position {
 5731                                true
 5732                            } else {
 5733                                let snapshot = editor.buffer.read(cx).read(cx);
 5734                                prev_menu.initial_position.to_offset(&snapshot)
 5735                                    == menu.initial_position.to_offset(&snapshot)
 5736                            };
 5737                        if position_matches {
 5738                            // Preserve markdown cache before `set_filter_results` because it will
 5739                            // try to populate the documentation cache.
 5740                            menu.preserve_markdown_cache(prev_menu);
 5741                        }
 5742                    };
 5743
 5744                    menu.set_filter_results(matches, provider, window, cx);
 5745                }) else {
 5746                    return;
 5747                };
 5748
 5749                menu.visible().then_some(menu)
 5750            };
 5751
 5752            editor
 5753                .update_in(cx, |editor, window, cx| {
 5754                    if editor.focus_handle.is_focused(window)
 5755                        && let Some(menu) = menu
 5756                    {
 5757                        *editor.context_menu.borrow_mut() =
 5758                            Some(CodeContextMenu::Completions(menu));
 5759
 5760                        crate::hover_popover::hide_hover(editor, cx);
 5761                        if editor.show_edit_predictions_in_menu() {
 5762                            editor.update_visible_edit_prediction(window, cx);
 5763                        } else {
 5764                            editor.discard_edit_prediction(false, cx);
 5765                        }
 5766
 5767                        cx.notify();
 5768                        return;
 5769                    }
 5770
 5771                    if editor.completion_tasks.len() <= 1 {
 5772                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5773                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5774                        // If it was already hidden and we don't show edit predictions in the menu,
 5775                        // we should also show the edit prediction when available.
 5776                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5777                            editor.update_visible_edit_prediction(window, cx);
 5778                        }
 5779                    }
 5780                })
 5781                .ok();
 5782        });
 5783
 5784        self.completion_tasks.push((id, task));
 5785    }
 5786
 5787    #[cfg(feature = "test-support")]
 5788    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5789        let menu = self.context_menu.borrow();
 5790        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5791            let completions = menu.completions.borrow();
 5792            Some(completions.to_vec())
 5793        } else {
 5794            None
 5795        }
 5796    }
 5797
 5798    pub fn with_completions_menu_matching_id<R>(
 5799        &self,
 5800        id: CompletionId,
 5801        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5802    ) -> R {
 5803        let mut context_menu = self.context_menu.borrow_mut();
 5804        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5805            return f(None);
 5806        };
 5807        if completions_menu.id != id {
 5808            return f(None);
 5809        }
 5810        f(Some(completions_menu))
 5811    }
 5812
 5813    pub fn confirm_completion(
 5814        &mut self,
 5815        action: &ConfirmCompletion,
 5816        window: &mut Window,
 5817        cx: &mut Context<Self>,
 5818    ) -> Option<Task<Result<()>>> {
 5819        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5820        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5821    }
 5822
 5823    pub fn confirm_completion_insert(
 5824        &mut self,
 5825        _: &ConfirmCompletionInsert,
 5826        window: &mut Window,
 5827        cx: &mut Context<Self>,
 5828    ) -> Option<Task<Result<()>>> {
 5829        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5830        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5831    }
 5832
 5833    pub fn confirm_completion_replace(
 5834        &mut self,
 5835        _: &ConfirmCompletionReplace,
 5836        window: &mut Window,
 5837        cx: &mut Context<Self>,
 5838    ) -> Option<Task<Result<()>>> {
 5839        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5840        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5841    }
 5842
 5843    pub fn compose_completion(
 5844        &mut self,
 5845        action: &ComposeCompletion,
 5846        window: &mut Window,
 5847        cx: &mut Context<Self>,
 5848    ) -> Option<Task<Result<()>>> {
 5849        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5850        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5851    }
 5852
 5853    fn do_completion(
 5854        &mut self,
 5855        item_ix: Option<usize>,
 5856        intent: CompletionIntent,
 5857        window: &mut Window,
 5858        cx: &mut Context<Editor>,
 5859    ) -> Option<Task<Result<()>>> {
 5860        use language::ToOffset as _;
 5861
 5862        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5863        else {
 5864            return None;
 5865        };
 5866
 5867        let candidate_id = {
 5868            let entries = completions_menu.entries.borrow();
 5869            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5870            if self.show_edit_predictions_in_menu() {
 5871                self.discard_edit_prediction(true, cx);
 5872            }
 5873            mat.candidate_id
 5874        };
 5875
 5876        let completion = completions_menu
 5877            .completions
 5878            .borrow()
 5879            .get(candidate_id)?
 5880            .clone();
 5881        cx.stop_propagation();
 5882
 5883        let buffer_handle = completions_menu.buffer.clone();
 5884
 5885        let CompletionEdit {
 5886            new_text,
 5887            snippet,
 5888            replace_range,
 5889        } = process_completion_for_edit(
 5890            &completion,
 5891            intent,
 5892            &buffer_handle,
 5893            &completions_menu.initial_position.text_anchor,
 5894            cx,
 5895        );
 5896
 5897        let buffer = buffer_handle.read(cx);
 5898        let snapshot = self.buffer.read(cx).snapshot(cx);
 5899        let newest_anchor = self.selections.newest_anchor();
 5900        let replace_range_multibuffer = {
 5901            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5902            excerpt.map_range_from_buffer(replace_range.clone())
 5903        };
 5904        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5905            return None;
 5906        }
 5907
 5908        let old_text = buffer
 5909            .text_for_range(replace_range.clone())
 5910            .collect::<String>();
 5911        let lookbehind = newest_anchor
 5912            .start
 5913            .text_anchor
 5914            .to_offset(buffer)
 5915            .saturating_sub(replace_range.start);
 5916        let lookahead = replace_range
 5917            .end
 5918            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5919        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5920        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5921
 5922        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5923        let mut ranges = Vec::new();
 5924        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5925
 5926        for selection in &selections {
 5927            let range = if selection.id == newest_anchor.id {
 5928                replace_range_multibuffer.clone()
 5929            } else {
 5930                let mut range = selection.range();
 5931
 5932                // if prefix is present, don't duplicate it
 5933                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5934                    range.start = range.start.saturating_sub(lookbehind);
 5935
 5936                    // if suffix is also present, mimic the newest cursor and replace it
 5937                    if selection.id != newest_anchor.id
 5938                        && snapshot.contains_str_at(range.end, suffix)
 5939                    {
 5940                        range.end += lookahead;
 5941                    }
 5942                }
 5943                range
 5944            };
 5945
 5946            ranges.push(range.clone());
 5947
 5948            if !self.linked_edit_ranges.is_empty() {
 5949                let start_anchor = snapshot.anchor_before(range.start);
 5950                let end_anchor = snapshot.anchor_after(range.end);
 5951                if let Some(ranges) = self
 5952                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5953                {
 5954                    for (buffer, edits) in ranges {
 5955                        linked_edits
 5956                            .entry(buffer.clone())
 5957                            .or_default()
 5958                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5959                    }
 5960                }
 5961            }
 5962        }
 5963
 5964        let common_prefix_len = old_text
 5965            .chars()
 5966            .zip(new_text.chars())
 5967            .take_while(|(a, b)| a == b)
 5968            .map(|(a, _)| a.len_utf8())
 5969            .sum::<usize>();
 5970
 5971        cx.emit(EditorEvent::InputHandled {
 5972            utf16_range_to_replace: None,
 5973            text: new_text[common_prefix_len..].into(),
 5974        });
 5975
 5976        self.transact(window, cx, |editor, window, cx| {
 5977            if let Some(mut snippet) = snippet {
 5978                snippet.text = new_text.to_string();
 5979                editor
 5980                    .insert_snippet(&ranges, snippet, window, cx)
 5981                    .log_err();
 5982            } else {
 5983                editor.buffer.update(cx, |multi_buffer, cx| {
 5984                    let auto_indent = match completion.insert_text_mode {
 5985                        Some(InsertTextMode::AS_IS) => None,
 5986                        _ => editor.autoindent_mode.clone(),
 5987                    };
 5988                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5989                    multi_buffer.edit(edits, auto_indent, cx);
 5990                });
 5991            }
 5992            for (buffer, edits) in linked_edits {
 5993                buffer.update(cx, |buffer, cx| {
 5994                    let snapshot = buffer.snapshot();
 5995                    let edits = edits
 5996                        .into_iter()
 5997                        .map(|(range, text)| {
 5998                            use text::ToPoint as TP;
 5999                            let end_point = TP::to_point(&range.end, &snapshot);
 6000                            let start_point = TP::to_point(&range.start, &snapshot);
 6001                            (start_point..end_point, text)
 6002                        })
 6003                        .sorted_by_key(|(range, _)| range.start);
 6004                    buffer.edit(edits, None, cx);
 6005                })
 6006            }
 6007
 6008            editor.refresh_edit_prediction(true, false, window, cx);
 6009        });
 6010        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6011
 6012        let show_new_completions_on_confirm = completion
 6013            .confirm
 6014            .as_ref()
 6015            .is_some_and(|confirm| confirm(intent, window, cx));
 6016        if show_new_completions_on_confirm {
 6017            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 6018        }
 6019
 6020        let provider = self.completion_provider.as_ref()?;
 6021        drop(completion);
 6022        let apply_edits = provider.apply_additional_edits_for_completion(
 6023            buffer_handle,
 6024            completions_menu.completions.clone(),
 6025            candidate_id,
 6026            true,
 6027            cx,
 6028        );
 6029
 6030        let editor_settings = EditorSettings::get_global(cx);
 6031        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6032            // After the code completion is finished, users often want to know what signatures are needed.
 6033            // so we should automatically call signature_help
 6034            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6035        }
 6036
 6037        Some(cx.foreground_executor().spawn(async move {
 6038            apply_edits.await?;
 6039            Ok(())
 6040        }))
 6041    }
 6042
 6043    pub fn toggle_code_actions(
 6044        &mut self,
 6045        action: &ToggleCodeActions,
 6046        window: &mut Window,
 6047        cx: &mut Context<Self>,
 6048    ) {
 6049        let quick_launch = action.quick_launch;
 6050        let mut context_menu = self.context_menu.borrow_mut();
 6051        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6052            if code_actions.deployed_from == action.deployed_from {
 6053                // Toggle if we're selecting the same one
 6054                *context_menu = None;
 6055                cx.notify();
 6056                return;
 6057            } else {
 6058                // Otherwise, clear it and start a new one
 6059                *context_menu = None;
 6060                cx.notify();
 6061            }
 6062        }
 6063        drop(context_menu);
 6064        let snapshot = self.snapshot(window, cx);
 6065        let deployed_from = action.deployed_from.clone();
 6066        let action = action.clone();
 6067        self.completion_tasks.clear();
 6068        self.discard_edit_prediction(false, cx);
 6069
 6070        let multibuffer_point = match &action.deployed_from {
 6071            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6072                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6073            }
 6074            _ => self
 6075                .selections
 6076                .newest::<Point>(&snapshot.display_snapshot)
 6077                .head(),
 6078        };
 6079        let Some((buffer, buffer_row)) = snapshot
 6080            .buffer_snapshot()
 6081            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6082            .and_then(|(buffer_snapshot, range)| {
 6083                self.buffer()
 6084                    .read(cx)
 6085                    .buffer(buffer_snapshot.remote_id())
 6086                    .map(|buffer| (buffer, range.start.row))
 6087            })
 6088        else {
 6089            return;
 6090        };
 6091        let buffer_id = buffer.read(cx).remote_id();
 6092        let tasks = self
 6093            .tasks
 6094            .get(&(buffer_id, buffer_row))
 6095            .map(|t| Arc::new(t.to_owned()));
 6096
 6097        if !self.focus_handle.is_focused(window) {
 6098            return;
 6099        }
 6100        let project = self.project.clone();
 6101
 6102        let code_actions_task = match deployed_from {
 6103            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6104            _ => self.code_actions(buffer_row, window, cx),
 6105        };
 6106
 6107        let runnable_task = match deployed_from {
 6108            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6109            _ => {
 6110                let mut task_context_task = Task::ready(None);
 6111                if let Some(tasks) = &tasks
 6112                    && let Some(project) = project
 6113                {
 6114                    task_context_task =
 6115                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6116                }
 6117
 6118                cx.spawn_in(window, {
 6119                    let buffer = buffer.clone();
 6120                    async move |editor, cx| {
 6121                        let task_context = task_context_task.await;
 6122
 6123                        let resolved_tasks =
 6124                            tasks
 6125                                .zip(task_context.clone())
 6126                                .map(|(tasks, task_context)| ResolvedTasks {
 6127                                    templates: tasks.resolve(&task_context).collect(),
 6128                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6129                                        multibuffer_point.row,
 6130                                        tasks.column,
 6131                                    )),
 6132                                });
 6133                        let debug_scenarios = editor
 6134                            .update(cx, |editor, cx| {
 6135                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6136                            })?
 6137                            .await;
 6138                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6139                    }
 6140                })
 6141            }
 6142        };
 6143
 6144        cx.spawn_in(window, async move |editor, cx| {
 6145            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6146            let code_actions = code_actions_task.await;
 6147            let spawn_straight_away = quick_launch
 6148                && resolved_tasks
 6149                    .as_ref()
 6150                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6151                && code_actions
 6152                    .as_ref()
 6153                    .is_none_or(|actions| actions.is_empty())
 6154                && debug_scenarios.is_empty();
 6155
 6156            editor.update_in(cx, |editor, window, cx| {
 6157                crate::hover_popover::hide_hover(editor, cx);
 6158                let actions = CodeActionContents::new(
 6159                    resolved_tasks,
 6160                    code_actions,
 6161                    debug_scenarios,
 6162                    task_context.unwrap_or_default(),
 6163                );
 6164
 6165                // Don't show the menu if there are no actions available
 6166                if actions.is_empty() {
 6167                    cx.notify();
 6168                    return Task::ready(Ok(()));
 6169                }
 6170
 6171                *editor.context_menu.borrow_mut() =
 6172                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6173                        buffer,
 6174                        actions,
 6175                        selected_item: Default::default(),
 6176                        scroll_handle: UniformListScrollHandle::default(),
 6177                        deployed_from,
 6178                    }));
 6179                cx.notify();
 6180                if spawn_straight_away
 6181                    && let Some(task) = editor.confirm_code_action(
 6182                        &ConfirmCodeAction { item_ix: Some(0) },
 6183                        window,
 6184                        cx,
 6185                    )
 6186                {
 6187                    return task;
 6188                }
 6189
 6190                Task::ready(Ok(()))
 6191            })
 6192        })
 6193        .detach_and_log_err(cx);
 6194    }
 6195
 6196    fn debug_scenarios(
 6197        &mut self,
 6198        resolved_tasks: &Option<ResolvedTasks>,
 6199        buffer: &Entity<Buffer>,
 6200        cx: &mut App,
 6201    ) -> Task<Vec<task::DebugScenario>> {
 6202        maybe!({
 6203            let project = self.project()?;
 6204            let dap_store = project.read(cx).dap_store();
 6205            let mut scenarios = vec![];
 6206            let resolved_tasks = resolved_tasks.as_ref()?;
 6207            let buffer = buffer.read(cx);
 6208            let language = buffer.language()?;
 6209            let file = buffer.file();
 6210            let debug_adapter = language_settings(language.name().into(), file, cx)
 6211                .debuggers
 6212                .first()
 6213                .map(SharedString::from)
 6214                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6215
 6216            dap_store.update(cx, |dap_store, cx| {
 6217                for (_, task) in &resolved_tasks.templates {
 6218                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6219                        task.original_task().clone(),
 6220                        debug_adapter.clone().into(),
 6221                        task.display_label().to_owned().into(),
 6222                        cx,
 6223                    );
 6224                    scenarios.push(maybe_scenario);
 6225                }
 6226            });
 6227            Some(cx.background_spawn(async move {
 6228                futures::future::join_all(scenarios)
 6229                    .await
 6230                    .into_iter()
 6231                    .flatten()
 6232                    .collect::<Vec<_>>()
 6233            }))
 6234        })
 6235        .unwrap_or_else(|| Task::ready(vec![]))
 6236    }
 6237
 6238    fn code_actions(
 6239        &mut self,
 6240        buffer_row: u32,
 6241        window: &mut Window,
 6242        cx: &mut Context<Self>,
 6243    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6244        let mut task = self.code_actions_task.take();
 6245        cx.spawn_in(window, async move |editor, cx| {
 6246            while let Some(prev_task) = task {
 6247                prev_task.await.log_err();
 6248                task = editor
 6249                    .update(cx, |this, _| this.code_actions_task.take())
 6250                    .ok()?;
 6251            }
 6252
 6253            editor
 6254                .update(cx, |editor, cx| {
 6255                    editor
 6256                        .available_code_actions
 6257                        .clone()
 6258                        .and_then(|(location, code_actions)| {
 6259                            let snapshot = location.buffer.read(cx).snapshot();
 6260                            let point_range = location.range.to_point(&snapshot);
 6261                            let point_range = point_range.start.row..=point_range.end.row;
 6262                            if point_range.contains(&buffer_row) {
 6263                                Some(code_actions)
 6264                            } else {
 6265                                None
 6266                            }
 6267                        })
 6268                })
 6269                .ok()
 6270                .flatten()
 6271        })
 6272    }
 6273
 6274    pub fn confirm_code_action(
 6275        &mut self,
 6276        action: &ConfirmCodeAction,
 6277        window: &mut Window,
 6278        cx: &mut Context<Self>,
 6279    ) -> Option<Task<Result<()>>> {
 6280        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6281
 6282        let actions_menu =
 6283            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6284                menu
 6285            } else {
 6286                return None;
 6287            };
 6288
 6289        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6290        let action = actions_menu.actions.get(action_ix)?;
 6291        let title = action.label();
 6292        let buffer = actions_menu.buffer;
 6293        let workspace = self.workspace()?;
 6294
 6295        match action {
 6296            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6297                workspace.update(cx, |workspace, cx| {
 6298                    workspace.schedule_resolved_task(
 6299                        task_source_kind,
 6300                        resolved_task,
 6301                        false,
 6302                        window,
 6303                        cx,
 6304                    );
 6305
 6306                    Some(Task::ready(Ok(())))
 6307                })
 6308            }
 6309            CodeActionsItem::CodeAction {
 6310                excerpt_id,
 6311                action,
 6312                provider,
 6313            } => {
 6314                let apply_code_action =
 6315                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6316                let workspace = workspace.downgrade();
 6317                Some(cx.spawn_in(window, async move |editor, cx| {
 6318                    let project_transaction = apply_code_action.await?;
 6319                    Self::open_project_transaction(
 6320                        &editor,
 6321                        workspace,
 6322                        project_transaction,
 6323                        title,
 6324                        cx,
 6325                    )
 6326                    .await
 6327                }))
 6328            }
 6329            CodeActionsItem::DebugScenario(scenario) => {
 6330                let context = actions_menu.actions.context;
 6331
 6332                workspace.update(cx, |workspace, cx| {
 6333                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6334                    workspace.start_debug_session(
 6335                        scenario,
 6336                        context,
 6337                        Some(buffer),
 6338                        None,
 6339                        window,
 6340                        cx,
 6341                    );
 6342                });
 6343                Some(Task::ready(Ok(())))
 6344            }
 6345        }
 6346    }
 6347
 6348    pub async fn open_project_transaction(
 6349        editor: &WeakEntity<Editor>,
 6350        workspace: WeakEntity<Workspace>,
 6351        transaction: ProjectTransaction,
 6352        title: String,
 6353        cx: &mut AsyncWindowContext,
 6354    ) -> Result<()> {
 6355        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6356        cx.update(|_, cx| {
 6357            entries.sort_unstable_by_key(|(buffer, _)| {
 6358                buffer.read(cx).file().map(|f| f.path().clone())
 6359            });
 6360        })?;
 6361        if entries.is_empty() {
 6362            return Ok(());
 6363        }
 6364
 6365        // If the project transaction's edits are all contained within this editor, then
 6366        // avoid opening a new editor to display them.
 6367
 6368        if let [(buffer, transaction)] = &*entries {
 6369            let excerpt = editor.update(cx, |editor, cx| {
 6370                editor
 6371                    .buffer()
 6372                    .read(cx)
 6373                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6374            })?;
 6375            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6376                && excerpted_buffer == *buffer
 6377            {
 6378                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6379                    let excerpt_range = excerpt_range.to_offset(buffer);
 6380                    buffer
 6381                        .edited_ranges_for_transaction::<usize>(transaction)
 6382                        .all(|range| {
 6383                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6384                        })
 6385                })?;
 6386
 6387                if all_edits_within_excerpt {
 6388                    return Ok(());
 6389                }
 6390            }
 6391        }
 6392
 6393        let mut ranges_to_highlight = Vec::new();
 6394        let excerpt_buffer = cx.new(|cx| {
 6395            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6396            for (buffer_handle, transaction) in &entries {
 6397                let edited_ranges = buffer_handle
 6398                    .read(cx)
 6399                    .edited_ranges_for_transaction::<Point>(transaction)
 6400                    .collect::<Vec<_>>();
 6401                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6402                    PathKey::for_buffer(buffer_handle, cx),
 6403                    buffer_handle.clone(),
 6404                    edited_ranges,
 6405                    multibuffer_context_lines(cx),
 6406                    cx,
 6407                );
 6408
 6409                ranges_to_highlight.extend(ranges);
 6410            }
 6411            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6412            multibuffer
 6413        })?;
 6414
 6415        workspace.update_in(cx, |workspace, window, cx| {
 6416            let project = workspace.project().clone();
 6417            let editor =
 6418                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6419            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6420            editor.update(cx, |editor, cx| {
 6421                editor.highlight_background::<Self>(
 6422                    &ranges_to_highlight,
 6423                    |theme| theme.colors().editor_highlighted_line_background,
 6424                    cx,
 6425                );
 6426            });
 6427        })?;
 6428
 6429        Ok(())
 6430    }
 6431
 6432    pub fn clear_code_action_providers(&mut self) {
 6433        self.code_action_providers.clear();
 6434        self.available_code_actions.take();
 6435    }
 6436
 6437    pub fn add_code_action_provider(
 6438        &mut self,
 6439        provider: Rc<dyn CodeActionProvider>,
 6440        window: &mut Window,
 6441        cx: &mut Context<Self>,
 6442    ) {
 6443        if self
 6444            .code_action_providers
 6445            .iter()
 6446            .any(|existing_provider| existing_provider.id() == provider.id())
 6447        {
 6448            return;
 6449        }
 6450
 6451        self.code_action_providers.push(provider);
 6452        self.refresh_code_actions(window, cx);
 6453    }
 6454
 6455    pub fn remove_code_action_provider(
 6456        &mut self,
 6457        id: Arc<str>,
 6458        window: &mut Window,
 6459        cx: &mut Context<Self>,
 6460    ) {
 6461        self.code_action_providers
 6462            .retain(|provider| provider.id() != id);
 6463        self.refresh_code_actions(window, cx);
 6464    }
 6465
 6466    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6467        !self.code_action_providers.is_empty()
 6468            && EditorSettings::get_global(cx).toolbar.code_actions
 6469    }
 6470
 6471    pub fn has_available_code_actions(&self) -> bool {
 6472        self.available_code_actions
 6473            .as_ref()
 6474            .is_some_and(|(_, actions)| !actions.is_empty())
 6475    }
 6476
 6477    fn render_inline_code_actions(
 6478        &self,
 6479        icon_size: ui::IconSize,
 6480        display_row: DisplayRow,
 6481        is_active: bool,
 6482        cx: &mut Context<Self>,
 6483    ) -> AnyElement {
 6484        let show_tooltip = !self.context_menu_visible();
 6485        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6486            .icon_size(icon_size)
 6487            .shape(ui::IconButtonShape::Square)
 6488            .icon_color(ui::Color::Hidden)
 6489            .toggle_state(is_active)
 6490            .when(show_tooltip, |this| {
 6491                this.tooltip({
 6492                    let focus_handle = self.focus_handle.clone();
 6493                    move |_window, cx| {
 6494                        Tooltip::for_action_in(
 6495                            "Toggle Code Actions",
 6496                            &ToggleCodeActions {
 6497                                deployed_from: None,
 6498                                quick_launch: false,
 6499                            },
 6500                            &focus_handle,
 6501                            cx,
 6502                        )
 6503                    }
 6504                })
 6505            })
 6506            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6507                window.focus(&editor.focus_handle(cx));
 6508                editor.toggle_code_actions(
 6509                    &crate::actions::ToggleCodeActions {
 6510                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6511                            display_row,
 6512                        )),
 6513                        quick_launch: false,
 6514                    },
 6515                    window,
 6516                    cx,
 6517                );
 6518            }))
 6519            .into_any_element()
 6520    }
 6521
 6522    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6523        &self.context_menu
 6524    }
 6525
 6526    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6527        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6528            cx.background_executor()
 6529                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6530                .await;
 6531
 6532            let (start_buffer, start, _, end, newest_selection) = this
 6533                .update(cx, |this, cx| {
 6534                    let newest_selection = this.selections.newest_anchor().clone();
 6535                    if newest_selection.head().diff_base_anchor.is_some() {
 6536                        return None;
 6537                    }
 6538                    let display_snapshot = this.display_snapshot(cx);
 6539                    let newest_selection_adjusted =
 6540                        this.selections.newest_adjusted(&display_snapshot);
 6541                    let buffer = this.buffer.read(cx);
 6542
 6543                    let (start_buffer, start) =
 6544                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6545                    let (end_buffer, end) =
 6546                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6547
 6548                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6549                })?
 6550                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6551                .context(
 6552                    "Expected selection to lie in a single buffer when refreshing code actions",
 6553                )?;
 6554            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6555                let providers = this.code_action_providers.clone();
 6556                let tasks = this
 6557                    .code_action_providers
 6558                    .iter()
 6559                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6560                    .collect::<Vec<_>>();
 6561                (providers, tasks)
 6562            })?;
 6563
 6564            let mut actions = Vec::new();
 6565            for (provider, provider_actions) in
 6566                providers.into_iter().zip(future::join_all(tasks).await)
 6567            {
 6568                if let Some(provider_actions) = provider_actions.log_err() {
 6569                    actions.extend(provider_actions.into_iter().map(|action| {
 6570                        AvailableCodeAction {
 6571                            excerpt_id: newest_selection.start.excerpt_id,
 6572                            action,
 6573                            provider: provider.clone(),
 6574                        }
 6575                    }));
 6576                }
 6577            }
 6578
 6579            this.update(cx, |this, cx| {
 6580                this.available_code_actions = if actions.is_empty() {
 6581                    None
 6582                } else {
 6583                    Some((
 6584                        Location {
 6585                            buffer: start_buffer,
 6586                            range: start..end,
 6587                        },
 6588                        actions.into(),
 6589                    ))
 6590                };
 6591                cx.notify();
 6592            })
 6593        }));
 6594    }
 6595
 6596    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6597        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6598            self.show_git_blame_inline = false;
 6599
 6600            self.show_git_blame_inline_delay_task =
 6601                Some(cx.spawn_in(window, async move |this, cx| {
 6602                    cx.background_executor().timer(delay).await;
 6603
 6604                    this.update(cx, |this, cx| {
 6605                        this.show_git_blame_inline = true;
 6606                        cx.notify();
 6607                    })
 6608                    .log_err();
 6609                }));
 6610        }
 6611    }
 6612
 6613    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6614        let snapshot = self.snapshot(window, cx);
 6615        let cursor = self
 6616            .selections
 6617            .newest::<Point>(&snapshot.display_snapshot)
 6618            .head();
 6619        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6620        else {
 6621            return;
 6622        };
 6623
 6624        let Some(blame) = self.blame.as_ref() else {
 6625            return;
 6626        };
 6627
 6628        let row_info = RowInfo {
 6629            buffer_id: Some(buffer.remote_id()),
 6630            buffer_row: Some(point.row),
 6631            ..Default::default()
 6632        };
 6633        let Some((buffer, blame_entry)) = blame
 6634            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6635            .flatten()
 6636        else {
 6637            return;
 6638        };
 6639
 6640        let anchor = self.selections.newest_anchor().head();
 6641        let position = self.to_pixel_point(anchor, &snapshot, window);
 6642        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6643            self.show_blame_popover(
 6644                buffer,
 6645                &blame_entry,
 6646                position + last_bounds.origin,
 6647                true,
 6648                cx,
 6649            );
 6650        };
 6651    }
 6652
 6653    fn show_blame_popover(
 6654        &mut self,
 6655        buffer: BufferId,
 6656        blame_entry: &BlameEntry,
 6657        position: gpui::Point<Pixels>,
 6658        ignore_timeout: bool,
 6659        cx: &mut Context<Self>,
 6660    ) {
 6661        if let Some(state) = &mut self.inline_blame_popover {
 6662            state.hide_task.take();
 6663        } else {
 6664            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6665            let blame_entry = blame_entry.clone();
 6666            let show_task = cx.spawn(async move |editor, cx| {
 6667                if !ignore_timeout {
 6668                    cx.background_executor()
 6669                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6670                        .await;
 6671                }
 6672                editor
 6673                    .update(cx, |editor, cx| {
 6674                        editor.inline_blame_popover_show_task.take();
 6675                        let Some(blame) = editor.blame.as_ref() else {
 6676                            return;
 6677                        };
 6678                        let blame = blame.read(cx);
 6679                        let details = blame.details_for_entry(buffer, &blame_entry);
 6680                        let markdown = cx.new(|cx| {
 6681                            Markdown::new(
 6682                                details
 6683                                    .as_ref()
 6684                                    .map(|message| message.message.clone())
 6685                                    .unwrap_or_default(),
 6686                                None,
 6687                                None,
 6688                                cx,
 6689                            )
 6690                        });
 6691                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6692                            position,
 6693                            hide_task: None,
 6694                            popover_bounds: None,
 6695                            popover_state: InlineBlamePopoverState {
 6696                                scroll_handle: ScrollHandle::new(),
 6697                                commit_message: details,
 6698                                markdown,
 6699                            },
 6700                            keyboard_grace: ignore_timeout,
 6701                        });
 6702                        cx.notify();
 6703                    })
 6704                    .ok();
 6705            });
 6706            self.inline_blame_popover_show_task = Some(show_task);
 6707        }
 6708    }
 6709
 6710    fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6711        self.inline_blame_popover_show_task.take();
 6712        if let Some(state) = &mut self.inline_blame_popover {
 6713            let hide_task = cx.spawn(async move |editor, cx| {
 6714                if !ignore_timeout {
 6715                    cx.background_executor()
 6716                        .timer(std::time::Duration::from_millis(100))
 6717                        .await;
 6718                }
 6719                editor
 6720                    .update(cx, |editor, cx| {
 6721                        editor.inline_blame_popover.take();
 6722                        cx.notify();
 6723                    })
 6724                    .ok();
 6725            });
 6726            state.hide_task = Some(hide_task);
 6727            true
 6728        } else {
 6729            false
 6730        }
 6731    }
 6732
 6733    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6734        if self.pending_rename.is_some() {
 6735            return None;
 6736        }
 6737
 6738        let provider = self.semantics_provider.clone()?;
 6739        let buffer = self.buffer.read(cx);
 6740        let newest_selection = self.selections.newest_anchor().clone();
 6741        let cursor_position = newest_selection.head();
 6742        let (cursor_buffer, cursor_buffer_position) =
 6743            buffer.text_anchor_for_position(cursor_position, cx)?;
 6744        let (tail_buffer, tail_buffer_position) =
 6745            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6746        if cursor_buffer != tail_buffer {
 6747            return None;
 6748        }
 6749
 6750        let snapshot = cursor_buffer.read(cx).snapshot();
 6751        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6752        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6753        if start_word_range != end_word_range {
 6754            self.document_highlights_task.take();
 6755            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6756            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6757            return None;
 6758        }
 6759
 6760        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 6761        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6762            cx.background_executor()
 6763                .timer(Duration::from_millis(debounce))
 6764                .await;
 6765
 6766            let highlights = if let Some(highlights) = cx
 6767                .update(|cx| {
 6768                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6769                })
 6770                .ok()
 6771                .flatten()
 6772            {
 6773                highlights.await.log_err()
 6774            } else {
 6775                None
 6776            };
 6777
 6778            if let Some(highlights) = highlights {
 6779                this.update(cx, |this, cx| {
 6780                    if this.pending_rename.is_some() {
 6781                        return;
 6782                    }
 6783
 6784                    let buffer = this.buffer.read(cx);
 6785                    if buffer
 6786                        .text_anchor_for_position(cursor_position, cx)
 6787                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6788                    {
 6789                        return;
 6790                    }
 6791
 6792                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6793                    let mut write_ranges = Vec::new();
 6794                    let mut read_ranges = Vec::new();
 6795                    for highlight in highlights {
 6796                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6797                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6798                        {
 6799                            let start = highlight
 6800                                .range
 6801                                .start
 6802                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6803                            let end = highlight
 6804                                .range
 6805                                .end
 6806                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6807                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6808                                continue;
 6809                            }
 6810
 6811                            let range =
 6812                                Anchor::range_in_buffer(excerpt_id, buffer_id, *start..*end);
 6813                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6814                                write_ranges.push(range);
 6815                            } else {
 6816                                read_ranges.push(range);
 6817                            }
 6818                        }
 6819                    }
 6820
 6821                    this.highlight_background::<DocumentHighlightRead>(
 6822                        &read_ranges,
 6823                        |theme| theme.colors().editor_document_highlight_read_background,
 6824                        cx,
 6825                    );
 6826                    this.highlight_background::<DocumentHighlightWrite>(
 6827                        &write_ranges,
 6828                        |theme| theme.colors().editor_document_highlight_write_background,
 6829                        cx,
 6830                    );
 6831                    cx.notify();
 6832                })
 6833                .log_err();
 6834            }
 6835        }));
 6836        None
 6837    }
 6838
 6839    fn prepare_highlight_query_from_selection(
 6840        &mut self,
 6841        window: &Window,
 6842        cx: &mut Context<Editor>,
 6843    ) -> Option<(String, Range<Anchor>)> {
 6844        if matches!(self.mode, EditorMode::SingleLine) {
 6845            return None;
 6846        }
 6847        if !EditorSettings::get_global(cx).selection_highlight {
 6848            return None;
 6849        }
 6850        if self.selections.count() != 1 || self.selections.line_mode() {
 6851            return None;
 6852        }
 6853        let snapshot = self.snapshot(window, cx);
 6854        let selection = self.selections.newest::<Point>(&snapshot);
 6855        // If the selection spans multiple rows OR it is empty
 6856        if selection.start.row != selection.end.row
 6857            || selection.start.column == selection.end.column
 6858        {
 6859            return None;
 6860        }
 6861        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 6862        let query = snapshot
 6863            .buffer_snapshot()
 6864            .text_for_range(selection_anchor_range.clone())
 6865            .collect::<String>();
 6866        if query.trim().is_empty() {
 6867            return None;
 6868        }
 6869        Some((query, selection_anchor_range))
 6870    }
 6871
 6872    fn update_selection_occurrence_highlights(
 6873        &mut self,
 6874        query_text: String,
 6875        query_range: Range<Anchor>,
 6876        multi_buffer_range_to_query: Range<Point>,
 6877        use_debounce: bool,
 6878        window: &mut Window,
 6879        cx: &mut Context<Editor>,
 6880    ) -> Task<()> {
 6881        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6882        cx.spawn_in(window, async move |editor, cx| {
 6883            if use_debounce {
 6884                cx.background_executor()
 6885                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6886                    .await;
 6887            }
 6888            let match_task = cx.background_spawn(async move {
 6889                let buffer_ranges = multi_buffer_snapshot
 6890                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6891                    .into_iter()
 6892                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6893                let mut match_ranges = Vec::new();
 6894                let Ok(regex) = project::search::SearchQuery::text(
 6895                    query_text.clone(),
 6896                    false,
 6897                    false,
 6898                    false,
 6899                    Default::default(),
 6900                    Default::default(),
 6901                    false,
 6902                    None,
 6903                ) else {
 6904                    return Vec::default();
 6905                };
 6906                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 6907                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6908                    match_ranges.extend(
 6909                        regex
 6910                            .search(buffer_snapshot, Some(search_range.clone()))
 6911                            .await
 6912                            .into_iter()
 6913                            .filter_map(|match_range| {
 6914                                let match_start = buffer_snapshot
 6915                                    .anchor_after(search_range.start + match_range.start);
 6916                                let match_end = buffer_snapshot
 6917                                    .anchor_before(search_range.start + match_range.end);
 6918                                let match_anchor_range = Anchor::range_in_buffer(
 6919                                    excerpt_id,
 6920                                    buffer_snapshot.remote_id(),
 6921                                    match_start..match_end,
 6922                                );
 6923                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6924                            }),
 6925                    );
 6926                }
 6927                match_ranges
 6928            });
 6929            let match_ranges = match_task.await;
 6930            editor
 6931                .update_in(cx, |editor, _, cx| {
 6932                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6933                    if !match_ranges.is_empty() {
 6934                        editor.highlight_background::<SelectedTextHighlight>(
 6935                            &match_ranges,
 6936                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6937                            cx,
 6938                        )
 6939                    }
 6940                })
 6941                .log_err();
 6942        })
 6943    }
 6944
 6945    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6946        struct NewlineFold;
 6947        let type_id = std::any::TypeId::of::<NewlineFold>();
 6948        if !self.mode.is_single_line() {
 6949            return;
 6950        }
 6951        let snapshot = self.snapshot(window, cx);
 6952        if snapshot.buffer_snapshot().max_point().row == 0 {
 6953            return;
 6954        }
 6955        let task = cx.background_spawn(async move {
 6956            let new_newlines = snapshot
 6957                .buffer_chars_at(0)
 6958                .filter_map(|(c, i)| {
 6959                    if c == '\n' {
 6960                        Some(
 6961                            snapshot.buffer_snapshot().anchor_after(i)
 6962                                ..snapshot.buffer_snapshot().anchor_before(i + 1),
 6963                        )
 6964                    } else {
 6965                        None
 6966                    }
 6967                })
 6968                .collect::<Vec<_>>();
 6969            let existing_newlines = snapshot
 6970                .folds_in_range(0..snapshot.buffer_snapshot().len())
 6971                .filter_map(|fold| {
 6972                    if fold.placeholder.type_tag == Some(type_id) {
 6973                        Some(fold.range.start..fold.range.end)
 6974                    } else {
 6975                        None
 6976                    }
 6977                })
 6978                .collect::<Vec<_>>();
 6979
 6980            (new_newlines, existing_newlines)
 6981        });
 6982        self.folding_newlines = cx.spawn(async move |this, cx| {
 6983            let (new_newlines, existing_newlines) = task.await;
 6984            if new_newlines == existing_newlines {
 6985                return;
 6986            }
 6987            let placeholder = FoldPlaceholder {
 6988                render: Arc::new(move |_, _, cx| {
 6989                    div()
 6990                        .bg(cx.theme().status().hint_background)
 6991                        .border_b_1()
 6992                        .size_full()
 6993                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6994                        .border_color(cx.theme().status().hint)
 6995                        .child("\\n")
 6996                        .into_any()
 6997                }),
 6998                constrain_width: false,
 6999                merge_adjacent: false,
 7000                type_tag: Some(type_id),
 7001            };
 7002            let creases = new_newlines
 7003                .into_iter()
 7004                .map(|range| Crease::simple(range, placeholder.clone()))
 7005                .collect();
 7006            this.update(cx, |this, cx| {
 7007                this.display_map.update(cx, |display_map, cx| {
 7008                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7009                    display_map.fold(creases, cx);
 7010                });
 7011            })
 7012            .ok();
 7013        });
 7014    }
 7015
 7016    fn refresh_selected_text_highlights(
 7017        &mut self,
 7018        on_buffer_edit: bool,
 7019        window: &mut Window,
 7020        cx: &mut Context<Editor>,
 7021    ) {
 7022        let Some((query_text, query_range)) =
 7023            self.prepare_highlight_query_from_selection(window, cx)
 7024        else {
 7025            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7026            self.quick_selection_highlight_task.take();
 7027            self.debounced_selection_highlight_task.take();
 7028            return;
 7029        };
 7030        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7031        if on_buffer_edit
 7032            || self
 7033                .quick_selection_highlight_task
 7034                .as_ref()
 7035                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7036        {
 7037            let multi_buffer_visible_start = self
 7038                .scroll_manager
 7039                .anchor()
 7040                .anchor
 7041                .to_point(&multi_buffer_snapshot);
 7042            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7043                multi_buffer_visible_start
 7044                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7045                Bias::Left,
 7046            );
 7047            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7048            self.quick_selection_highlight_task = Some((
 7049                query_range.clone(),
 7050                self.update_selection_occurrence_highlights(
 7051                    query_text.clone(),
 7052                    query_range.clone(),
 7053                    multi_buffer_visible_range,
 7054                    false,
 7055                    window,
 7056                    cx,
 7057                ),
 7058            ));
 7059        }
 7060        if on_buffer_edit
 7061            || self
 7062                .debounced_selection_highlight_task
 7063                .as_ref()
 7064                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7065        {
 7066            let multi_buffer_start = multi_buffer_snapshot
 7067                .anchor_before(0)
 7068                .to_point(&multi_buffer_snapshot);
 7069            let multi_buffer_end = multi_buffer_snapshot
 7070                .anchor_after(multi_buffer_snapshot.len())
 7071                .to_point(&multi_buffer_snapshot);
 7072            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7073            self.debounced_selection_highlight_task = Some((
 7074                query_range.clone(),
 7075                self.update_selection_occurrence_highlights(
 7076                    query_text,
 7077                    query_range,
 7078                    multi_buffer_full_range,
 7079                    true,
 7080                    window,
 7081                    cx,
 7082                ),
 7083            ));
 7084        }
 7085    }
 7086
 7087    pub fn refresh_edit_prediction(
 7088        &mut self,
 7089        debounce: bool,
 7090        user_requested: bool,
 7091        window: &mut Window,
 7092        cx: &mut Context<Self>,
 7093    ) -> Option<()> {
 7094        if DisableAiSettings::get_global(cx).disable_ai {
 7095            return None;
 7096        }
 7097
 7098        let provider = self.edit_prediction_provider()?;
 7099        let cursor = self.selections.newest_anchor().head();
 7100        let (buffer, cursor_buffer_position) =
 7101            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7102
 7103        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7104            self.discard_edit_prediction(false, cx);
 7105            return None;
 7106        }
 7107
 7108        self.update_visible_edit_prediction(window, cx);
 7109
 7110        if !user_requested
 7111            && (!self.should_show_edit_predictions()
 7112                || !self.is_focused(window)
 7113                || buffer.read(cx).is_empty())
 7114        {
 7115            self.discard_edit_prediction(false, cx);
 7116            return None;
 7117        }
 7118
 7119        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7120        Some(())
 7121    }
 7122
 7123    fn show_edit_predictions_in_menu(&self) -> bool {
 7124        match self.edit_prediction_settings {
 7125            EditPredictionSettings::Disabled => false,
 7126            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7127        }
 7128    }
 7129
 7130    pub fn edit_predictions_enabled(&self) -> bool {
 7131        match self.edit_prediction_settings {
 7132            EditPredictionSettings::Disabled => false,
 7133            EditPredictionSettings::Enabled { .. } => true,
 7134        }
 7135    }
 7136
 7137    fn edit_prediction_requires_modifier(&self) -> bool {
 7138        match self.edit_prediction_settings {
 7139            EditPredictionSettings::Disabled => false,
 7140            EditPredictionSettings::Enabled {
 7141                preview_requires_modifier,
 7142                ..
 7143            } => preview_requires_modifier,
 7144        }
 7145    }
 7146
 7147    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7148        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7149            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7150            self.discard_edit_prediction(false, cx);
 7151        } else {
 7152            let selection = self.selections.newest_anchor();
 7153            let cursor = selection.head();
 7154
 7155            if let Some((buffer, cursor_buffer_position)) =
 7156                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7157            {
 7158                self.edit_prediction_settings =
 7159                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7160            }
 7161        }
 7162    }
 7163
 7164    fn edit_prediction_settings_at_position(
 7165        &self,
 7166        buffer: &Entity<Buffer>,
 7167        buffer_position: language::Anchor,
 7168        cx: &App,
 7169    ) -> EditPredictionSettings {
 7170        if !self.mode.is_full()
 7171            || !self.show_edit_predictions_override.unwrap_or(true)
 7172            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7173        {
 7174            return EditPredictionSettings::Disabled;
 7175        }
 7176
 7177        let buffer = buffer.read(cx);
 7178
 7179        let file = buffer.file();
 7180
 7181        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7182            return EditPredictionSettings::Disabled;
 7183        };
 7184
 7185        let by_provider = matches!(
 7186            self.menu_edit_predictions_policy,
 7187            MenuEditPredictionsPolicy::ByProvider
 7188        );
 7189
 7190        let show_in_menu = by_provider
 7191            && self
 7192                .edit_prediction_provider
 7193                .as_ref()
 7194                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7195
 7196        let preview_requires_modifier =
 7197            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7198
 7199        EditPredictionSettings::Enabled {
 7200            show_in_menu,
 7201            preview_requires_modifier,
 7202        }
 7203    }
 7204
 7205    fn should_show_edit_predictions(&self) -> bool {
 7206        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7207    }
 7208
 7209    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7210        matches!(
 7211            self.edit_prediction_preview,
 7212            EditPredictionPreview::Active { .. }
 7213        )
 7214    }
 7215
 7216    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7217        let cursor = self.selections.newest_anchor().head();
 7218        if let Some((buffer, cursor_position)) =
 7219            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7220        {
 7221            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7222        } else {
 7223            false
 7224        }
 7225    }
 7226
 7227    pub fn supports_minimap(&self, cx: &App) -> bool {
 7228        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7229    }
 7230
 7231    fn edit_predictions_enabled_in_buffer(
 7232        &self,
 7233        buffer: &Entity<Buffer>,
 7234        buffer_position: language::Anchor,
 7235        cx: &App,
 7236    ) -> bool {
 7237        maybe!({
 7238            if self.read_only(cx) {
 7239                return Some(false);
 7240            }
 7241            let provider = self.edit_prediction_provider()?;
 7242            if !provider.is_enabled(buffer, buffer_position, cx) {
 7243                return Some(false);
 7244            }
 7245            let buffer = buffer.read(cx);
 7246            let Some(file) = buffer.file() else {
 7247                return Some(true);
 7248            };
 7249            let settings = all_language_settings(Some(file), cx);
 7250            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7251        })
 7252        .unwrap_or(false)
 7253    }
 7254
 7255    fn cycle_edit_prediction(
 7256        &mut self,
 7257        direction: Direction,
 7258        window: &mut Window,
 7259        cx: &mut Context<Self>,
 7260    ) -> Option<()> {
 7261        let provider = self.edit_prediction_provider()?;
 7262        let cursor = self.selections.newest_anchor().head();
 7263        let (buffer, cursor_buffer_position) =
 7264            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7265        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7266            return None;
 7267        }
 7268
 7269        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7270        self.update_visible_edit_prediction(window, cx);
 7271
 7272        Some(())
 7273    }
 7274
 7275    pub fn show_edit_prediction(
 7276        &mut self,
 7277        _: &ShowEditPrediction,
 7278        window: &mut Window,
 7279        cx: &mut Context<Self>,
 7280    ) {
 7281        if !self.has_active_edit_prediction() {
 7282            self.refresh_edit_prediction(false, true, window, cx);
 7283            return;
 7284        }
 7285
 7286        self.update_visible_edit_prediction(window, cx);
 7287    }
 7288
 7289    pub fn display_cursor_names(
 7290        &mut self,
 7291        _: &DisplayCursorNames,
 7292        window: &mut Window,
 7293        cx: &mut Context<Self>,
 7294    ) {
 7295        self.show_cursor_names(window, cx);
 7296    }
 7297
 7298    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7299        self.show_cursor_names = true;
 7300        cx.notify();
 7301        cx.spawn_in(window, async move |this, cx| {
 7302            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7303            this.update(cx, |this, cx| {
 7304                this.show_cursor_names = false;
 7305                cx.notify()
 7306            })
 7307            .ok()
 7308        })
 7309        .detach();
 7310    }
 7311
 7312    pub fn next_edit_prediction(
 7313        &mut self,
 7314        _: &NextEditPrediction,
 7315        window: &mut Window,
 7316        cx: &mut Context<Self>,
 7317    ) {
 7318        if self.has_active_edit_prediction() {
 7319            self.cycle_edit_prediction(Direction::Next, window, cx);
 7320        } else {
 7321            let is_copilot_disabled = self
 7322                .refresh_edit_prediction(false, true, window, cx)
 7323                .is_none();
 7324            if is_copilot_disabled {
 7325                cx.propagate();
 7326            }
 7327        }
 7328    }
 7329
 7330    pub fn previous_edit_prediction(
 7331        &mut self,
 7332        _: &PreviousEditPrediction,
 7333        window: &mut Window,
 7334        cx: &mut Context<Self>,
 7335    ) {
 7336        if self.has_active_edit_prediction() {
 7337            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7338        } else {
 7339            let is_copilot_disabled = self
 7340                .refresh_edit_prediction(false, true, window, cx)
 7341                .is_none();
 7342            if is_copilot_disabled {
 7343                cx.propagate();
 7344            }
 7345        }
 7346    }
 7347
 7348    pub fn accept_edit_prediction(
 7349        &mut self,
 7350        _: &AcceptEditPrediction,
 7351        window: &mut Window,
 7352        cx: &mut Context<Self>,
 7353    ) {
 7354        if self.show_edit_predictions_in_menu() {
 7355            self.hide_context_menu(window, cx);
 7356        }
 7357
 7358        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7359            return;
 7360        };
 7361
 7362        match &active_edit_prediction.completion {
 7363            EditPrediction::MoveWithin { target, .. } => {
 7364                let target = *target;
 7365
 7366                if let Some(position_map) = &self.last_position_map {
 7367                    if position_map
 7368                        .visible_row_range
 7369                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7370                        || !self.edit_prediction_requires_modifier()
 7371                    {
 7372                        self.unfold_ranges(&[target..target], true, false, cx);
 7373                        // Note that this is also done in vim's handler of the Tab action.
 7374                        self.change_selections(
 7375                            SelectionEffects::scroll(Autoscroll::newest()),
 7376                            window,
 7377                            cx,
 7378                            |selections| {
 7379                                selections.select_anchor_ranges([target..target]);
 7380                            },
 7381                        );
 7382                        self.clear_row_highlights::<EditPredictionPreview>();
 7383
 7384                        self.edit_prediction_preview
 7385                            .set_previous_scroll_position(None);
 7386                    } else {
 7387                        self.edit_prediction_preview
 7388                            .set_previous_scroll_position(Some(
 7389                                position_map.snapshot.scroll_anchor,
 7390                            ));
 7391
 7392                        self.highlight_rows::<EditPredictionPreview>(
 7393                            target..target,
 7394                            cx.theme().colors().editor_highlighted_line_background,
 7395                            RowHighlightOptions {
 7396                                autoscroll: true,
 7397                                ..Default::default()
 7398                            },
 7399                            cx,
 7400                        );
 7401                        self.request_autoscroll(Autoscroll::fit(), cx);
 7402                    }
 7403                }
 7404            }
 7405            EditPrediction::MoveOutside { snapshot, target } => {
 7406                if let Some(workspace) = self.workspace() {
 7407                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7408                        .detach_and_log_err(cx);
 7409                }
 7410            }
 7411            EditPrediction::Edit { edits, .. } => {
 7412                self.report_edit_prediction_event(
 7413                    active_edit_prediction.completion_id.clone(),
 7414                    true,
 7415                    cx,
 7416                );
 7417
 7418                if let Some(provider) = self.edit_prediction_provider() {
 7419                    provider.accept(cx);
 7420                }
 7421
 7422                // Store the transaction ID and selections before applying the edit
 7423                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7424
 7425                let snapshot = self.buffer.read(cx).snapshot(cx);
 7426                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7427
 7428                self.buffer.update(cx, |buffer, cx| {
 7429                    buffer.edit(edits.iter().cloned(), None, cx)
 7430                });
 7431
 7432                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7433                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7434                });
 7435
 7436                let selections = self.selections.disjoint_anchors_arc();
 7437                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7438                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7439                    if has_new_transaction {
 7440                        self.selection_history
 7441                            .insert_transaction(transaction_id_now, selections);
 7442                    }
 7443                }
 7444
 7445                self.update_visible_edit_prediction(window, cx);
 7446                if self.active_edit_prediction.is_none() {
 7447                    self.refresh_edit_prediction(true, true, window, cx);
 7448                }
 7449
 7450                cx.notify();
 7451            }
 7452        }
 7453
 7454        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7455    }
 7456
 7457    pub fn accept_partial_edit_prediction(
 7458        &mut self,
 7459        _: &AcceptPartialEditPrediction,
 7460        window: &mut Window,
 7461        cx: &mut Context<Self>,
 7462    ) {
 7463        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7464            return;
 7465        };
 7466        if self.selections.count() != 1 {
 7467            return;
 7468        }
 7469
 7470        match &active_edit_prediction.completion {
 7471            EditPrediction::MoveWithin { target, .. } => {
 7472                let target = *target;
 7473                self.change_selections(
 7474                    SelectionEffects::scroll(Autoscroll::newest()),
 7475                    window,
 7476                    cx,
 7477                    |selections| {
 7478                        selections.select_anchor_ranges([target..target]);
 7479                    },
 7480                );
 7481            }
 7482            EditPrediction::MoveOutside { snapshot, target } => {
 7483                if let Some(workspace) = self.workspace() {
 7484                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7485                        .detach_and_log_err(cx);
 7486                }
 7487            }
 7488            EditPrediction::Edit { edits, .. } => {
 7489                self.report_edit_prediction_event(
 7490                    active_edit_prediction.completion_id.clone(),
 7491                    true,
 7492                    cx,
 7493                );
 7494
 7495                // Find an insertion that starts at the cursor position.
 7496                let snapshot = self.buffer.read(cx).snapshot(cx);
 7497                let cursor_offset = self
 7498                    .selections
 7499                    .newest::<usize>(&self.display_snapshot(cx))
 7500                    .head();
 7501                let insertion = edits.iter().find_map(|(range, text)| {
 7502                    let range = range.to_offset(&snapshot);
 7503                    if range.is_empty() && range.start == cursor_offset {
 7504                        Some(text)
 7505                    } else {
 7506                        None
 7507                    }
 7508                });
 7509
 7510                if let Some(text) = insertion {
 7511                    let mut partial_completion = text
 7512                        .chars()
 7513                        .by_ref()
 7514                        .take_while(|c| c.is_alphabetic())
 7515                        .collect::<String>();
 7516                    if partial_completion.is_empty() {
 7517                        partial_completion = text
 7518                            .chars()
 7519                            .by_ref()
 7520                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7521                            .collect::<String>();
 7522                    }
 7523
 7524                    cx.emit(EditorEvent::InputHandled {
 7525                        utf16_range_to_replace: None,
 7526                        text: partial_completion.clone().into(),
 7527                    });
 7528
 7529                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7530
 7531                    self.refresh_edit_prediction(true, true, window, cx);
 7532                    cx.notify();
 7533                } else {
 7534                    self.accept_edit_prediction(&Default::default(), window, cx);
 7535                }
 7536            }
 7537        }
 7538    }
 7539
 7540    fn discard_edit_prediction(
 7541        &mut self,
 7542        should_report_edit_prediction_event: bool,
 7543        cx: &mut Context<Self>,
 7544    ) -> bool {
 7545        if should_report_edit_prediction_event {
 7546            let completion_id = self
 7547                .active_edit_prediction
 7548                .as_ref()
 7549                .and_then(|active_completion| active_completion.completion_id.clone());
 7550
 7551            self.report_edit_prediction_event(completion_id, false, cx);
 7552        }
 7553
 7554        if let Some(provider) = self.edit_prediction_provider() {
 7555            provider.discard(cx);
 7556        }
 7557
 7558        self.take_active_edit_prediction(cx)
 7559    }
 7560
 7561    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7562        let Some(provider) = self.edit_prediction_provider() else {
 7563            return;
 7564        };
 7565
 7566        let Some((_, buffer, _)) = self
 7567            .buffer
 7568            .read(cx)
 7569            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7570        else {
 7571            return;
 7572        };
 7573
 7574        let extension = buffer
 7575            .read(cx)
 7576            .file()
 7577            .and_then(|file| Some(file.path().extension()?.to_string()));
 7578
 7579        let event_type = match accepted {
 7580            true => "Edit Prediction Accepted",
 7581            false => "Edit Prediction Discarded",
 7582        };
 7583        telemetry::event!(
 7584            event_type,
 7585            provider = provider.name(),
 7586            prediction_id = id,
 7587            suggestion_accepted = accepted,
 7588            file_extension = extension,
 7589        );
 7590    }
 7591
 7592    fn open_editor_at_anchor(
 7593        snapshot: &language::BufferSnapshot,
 7594        target: language::Anchor,
 7595        workspace: &Entity<Workspace>,
 7596        window: &mut Window,
 7597        cx: &mut App,
 7598    ) -> Task<Result<()>> {
 7599        workspace.update(cx, |workspace, cx| {
 7600            let path = snapshot.file().map(|file| file.full_path(cx));
 7601            let Some(path) =
 7602                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7603            else {
 7604                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7605            };
 7606            let target = text::ToPoint::to_point(&target, snapshot);
 7607            let item = workspace.open_path(path, None, true, window, cx);
 7608            window.spawn(cx, async move |cx| {
 7609                let Some(editor) = item.await?.downcast::<Editor>() else {
 7610                    return Ok(());
 7611                };
 7612                editor
 7613                    .update_in(cx, |editor, window, cx| {
 7614                        editor.go_to_singleton_buffer_point(target, window, cx);
 7615                    })
 7616                    .ok();
 7617                anyhow::Ok(())
 7618            })
 7619        })
 7620    }
 7621
 7622    pub fn has_active_edit_prediction(&self) -> bool {
 7623        self.active_edit_prediction.is_some()
 7624    }
 7625
 7626    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7627        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7628            return false;
 7629        };
 7630
 7631        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7632        self.clear_highlights::<EditPredictionHighlight>(cx);
 7633        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7634        true
 7635    }
 7636
 7637    /// Returns true when we're displaying the edit prediction popover below the cursor
 7638    /// like we are not previewing and the LSP autocomplete menu is visible
 7639    /// or we are in `when_holding_modifier` mode.
 7640    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7641        if self.edit_prediction_preview_is_active()
 7642            || !self.show_edit_predictions_in_menu()
 7643            || !self.edit_predictions_enabled()
 7644        {
 7645            return false;
 7646        }
 7647
 7648        if self.has_visible_completions_menu() {
 7649            return true;
 7650        }
 7651
 7652        has_completion && self.edit_prediction_requires_modifier()
 7653    }
 7654
 7655    fn handle_modifiers_changed(
 7656        &mut self,
 7657        modifiers: Modifiers,
 7658        position_map: &PositionMap,
 7659        window: &mut Window,
 7660        cx: &mut Context<Self>,
 7661    ) {
 7662        // Ensure that the edit prediction preview is updated, even when not
 7663        // enabled, if there's an active edit prediction preview.
 7664        if self.show_edit_predictions_in_menu()
 7665            || matches!(
 7666                self.edit_prediction_preview,
 7667                EditPredictionPreview::Active { .. }
 7668            )
 7669        {
 7670            self.update_edit_prediction_preview(&modifiers, window, cx);
 7671        }
 7672
 7673        self.update_selection_mode(&modifiers, position_map, window, cx);
 7674
 7675        let mouse_position = window.mouse_position();
 7676        if !position_map.text_hitbox.is_hovered(window) {
 7677            return;
 7678        }
 7679
 7680        self.update_hovered_link(
 7681            position_map.point_for_position(mouse_position),
 7682            &position_map.snapshot,
 7683            modifiers,
 7684            window,
 7685            cx,
 7686        )
 7687    }
 7688
 7689    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7690        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7691            MultiCursorModifier::Alt => modifiers.secondary(),
 7692            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7693        }
 7694    }
 7695
 7696    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7697        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7698            MultiCursorModifier::Alt => modifiers.alt,
 7699            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7700        }
 7701    }
 7702
 7703    fn columnar_selection_mode(
 7704        modifiers: &Modifiers,
 7705        cx: &mut Context<Self>,
 7706    ) -> Option<ColumnarMode> {
 7707        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7708            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 7709                Some(ColumnarMode::FromMouse)
 7710            } else if Self::is_alt_pressed(modifiers, cx) {
 7711                Some(ColumnarMode::FromSelection)
 7712            } else {
 7713                None
 7714            }
 7715        } else {
 7716            None
 7717        }
 7718    }
 7719
 7720    fn update_selection_mode(
 7721        &mut self,
 7722        modifiers: &Modifiers,
 7723        position_map: &PositionMap,
 7724        window: &mut Window,
 7725        cx: &mut Context<Self>,
 7726    ) {
 7727        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7728            return;
 7729        };
 7730        if self.selections.pending_anchor().is_none() {
 7731            return;
 7732        }
 7733
 7734        let mouse_position = window.mouse_position();
 7735        let point_for_position = position_map.point_for_position(mouse_position);
 7736        let position = point_for_position.previous_valid;
 7737
 7738        self.select(
 7739            SelectPhase::BeginColumnar {
 7740                position,
 7741                reset: false,
 7742                mode,
 7743                goal_column: point_for_position.exact_unclipped.column(),
 7744            },
 7745            window,
 7746            cx,
 7747        );
 7748    }
 7749
 7750    fn update_edit_prediction_preview(
 7751        &mut self,
 7752        modifiers: &Modifiers,
 7753        window: &mut Window,
 7754        cx: &mut Context<Self>,
 7755    ) {
 7756        let mut modifiers_held = false;
 7757        if let Some(accept_keystroke) = self
 7758            .accept_edit_prediction_keybind(false, window, cx)
 7759            .keystroke()
 7760        {
 7761            modifiers_held = modifiers_held
 7762                || (accept_keystroke.modifiers() == modifiers
 7763                    && accept_keystroke.modifiers().modified());
 7764        };
 7765        if let Some(accept_partial_keystroke) = self
 7766            .accept_edit_prediction_keybind(true, window, cx)
 7767            .keystroke()
 7768        {
 7769            modifiers_held = modifiers_held
 7770                || (accept_partial_keystroke.modifiers() == modifiers
 7771                    && accept_partial_keystroke.modifiers().modified());
 7772        }
 7773
 7774        if modifiers_held {
 7775            if matches!(
 7776                self.edit_prediction_preview,
 7777                EditPredictionPreview::Inactive { .. }
 7778            ) {
 7779                self.edit_prediction_preview = EditPredictionPreview::Active {
 7780                    previous_scroll_position: None,
 7781                    since: Instant::now(),
 7782                };
 7783
 7784                self.update_visible_edit_prediction(window, cx);
 7785                cx.notify();
 7786            }
 7787        } else if let EditPredictionPreview::Active {
 7788            previous_scroll_position,
 7789            since,
 7790        } = self.edit_prediction_preview
 7791        {
 7792            if let (Some(previous_scroll_position), Some(position_map)) =
 7793                (previous_scroll_position, self.last_position_map.as_ref())
 7794            {
 7795                self.set_scroll_position(
 7796                    previous_scroll_position
 7797                        .scroll_position(&position_map.snapshot.display_snapshot),
 7798                    window,
 7799                    cx,
 7800                );
 7801            }
 7802
 7803            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7804                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7805            };
 7806            self.clear_row_highlights::<EditPredictionPreview>();
 7807            self.update_visible_edit_prediction(window, cx);
 7808            cx.notify();
 7809        }
 7810    }
 7811
 7812    fn update_visible_edit_prediction(
 7813        &mut self,
 7814        _window: &mut Window,
 7815        cx: &mut Context<Self>,
 7816    ) -> Option<()> {
 7817        if DisableAiSettings::get_global(cx).disable_ai {
 7818            return None;
 7819        }
 7820
 7821        if self.ime_transaction.is_some() {
 7822            self.discard_edit_prediction(false, cx);
 7823            return None;
 7824        }
 7825
 7826        let selection = self.selections.newest_anchor();
 7827        let cursor = selection.head();
 7828        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7829        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7830        let excerpt_id = cursor.excerpt_id;
 7831
 7832        let show_in_menu = self.show_edit_predictions_in_menu();
 7833        let completions_menu_has_precedence = !show_in_menu
 7834            && (self.context_menu.borrow().is_some()
 7835                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7836
 7837        if completions_menu_has_precedence
 7838            || !offset_selection.is_empty()
 7839            || self
 7840                .active_edit_prediction
 7841                .as_ref()
 7842                .is_some_and(|completion| {
 7843                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7844                        return false;
 7845                    };
 7846                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7847                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7848                    !invalidation_range.contains(&offset_selection.head())
 7849                })
 7850        {
 7851            self.discard_edit_prediction(false, cx);
 7852            return None;
 7853        }
 7854
 7855        self.take_active_edit_prediction(cx);
 7856        let Some(provider) = self.edit_prediction_provider() else {
 7857            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7858            return None;
 7859        };
 7860
 7861        let (buffer, cursor_buffer_position) =
 7862            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7863
 7864        self.edit_prediction_settings =
 7865            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7866
 7867        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7868
 7869        if self.edit_prediction_indent_conflict {
 7870            let cursor_point = cursor.to_point(&multibuffer);
 7871
 7872            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7873
 7874            if let Some((_, indent)) = indents.iter().next()
 7875                && indent.len == cursor_point.column
 7876            {
 7877                self.edit_prediction_indent_conflict = false;
 7878            }
 7879        }
 7880
 7881        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7882
 7883        let (completion_id, edits, edit_preview) = match edit_prediction {
 7884            edit_prediction::EditPrediction::Local {
 7885                id,
 7886                edits,
 7887                edit_preview,
 7888            } => (id, edits, edit_preview),
 7889            edit_prediction::EditPrediction::Jump {
 7890                id,
 7891                snapshot,
 7892                target,
 7893            } => {
 7894                self.stale_edit_prediction_in_menu = None;
 7895                self.active_edit_prediction = Some(EditPredictionState {
 7896                    inlay_ids: vec![],
 7897                    completion: EditPrediction::MoveOutside { snapshot, target },
 7898                    completion_id: id,
 7899                    invalidation_range: None,
 7900                });
 7901                cx.notify();
 7902                return Some(());
 7903            }
 7904        };
 7905
 7906        let edits = edits
 7907            .into_iter()
 7908            .flat_map(|(range, new_text)| {
 7909                Some((
 7910                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 7911                    new_text,
 7912                ))
 7913            })
 7914            .collect::<Vec<_>>();
 7915        if edits.is_empty() {
 7916            return None;
 7917        }
 7918
 7919        let first_edit_start = edits.first().unwrap().0.start;
 7920        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7921        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7922
 7923        let last_edit_end = edits.last().unwrap().0.end;
 7924        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7925        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7926
 7927        let cursor_row = cursor.to_point(&multibuffer).row;
 7928
 7929        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7930
 7931        let mut inlay_ids = Vec::new();
 7932        let invalidation_row_range;
 7933        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7934            Some(cursor_row..edit_end_row)
 7935        } else if cursor_row > edit_end_row {
 7936            Some(edit_start_row..cursor_row)
 7937        } else {
 7938            None
 7939        };
 7940        let supports_jump = self
 7941            .edit_prediction_provider
 7942            .as_ref()
 7943            .map(|provider| provider.provider.supports_jump_to_edit())
 7944            .unwrap_or(true);
 7945
 7946        let is_move = supports_jump
 7947            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7948        let completion = if is_move {
 7949            invalidation_row_range =
 7950                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7951            let target = first_edit_start;
 7952            EditPrediction::MoveWithin { target, snapshot }
 7953        } else {
 7954            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7955                && !self.edit_predictions_hidden_for_vim_mode;
 7956
 7957            if show_completions_in_buffer {
 7958                if edits
 7959                    .iter()
 7960                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7961                {
 7962                    let mut inlays = Vec::new();
 7963                    for (range, new_text) in &edits {
 7964                        let inlay = Inlay::edit_prediction(
 7965                            post_inc(&mut self.next_inlay_id),
 7966                            range.start,
 7967                            new_text.as_str(),
 7968                        );
 7969                        inlay_ids.push(inlay.id);
 7970                        inlays.push(inlay);
 7971                    }
 7972
 7973                    self.splice_inlays(&[], inlays, cx);
 7974                } else {
 7975                    let background_color = cx.theme().status().deleted_background;
 7976                    self.highlight_text::<EditPredictionHighlight>(
 7977                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7978                        HighlightStyle {
 7979                            background_color: Some(background_color),
 7980                            ..Default::default()
 7981                        },
 7982                        cx,
 7983                    );
 7984                }
 7985            }
 7986
 7987            invalidation_row_range = edit_start_row..edit_end_row;
 7988
 7989            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7990                if provider.show_tab_accept_marker() {
 7991                    EditDisplayMode::TabAccept
 7992                } else {
 7993                    EditDisplayMode::Inline
 7994                }
 7995            } else {
 7996                EditDisplayMode::DiffPopover
 7997            };
 7998
 7999            EditPrediction::Edit {
 8000                edits,
 8001                edit_preview,
 8002                display_mode,
 8003                snapshot,
 8004            }
 8005        };
 8006
 8007        let invalidation_range = multibuffer
 8008            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8009            ..multibuffer.anchor_after(Point::new(
 8010                invalidation_row_range.end,
 8011                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8012            ));
 8013
 8014        self.stale_edit_prediction_in_menu = None;
 8015        self.active_edit_prediction = Some(EditPredictionState {
 8016            inlay_ids,
 8017            completion,
 8018            completion_id,
 8019            invalidation_range: Some(invalidation_range),
 8020        });
 8021
 8022        cx.notify();
 8023
 8024        Some(())
 8025    }
 8026
 8027    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 8028        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8029    }
 8030
 8031    fn clear_tasks(&mut self) {
 8032        self.tasks.clear()
 8033    }
 8034
 8035    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8036        if self.tasks.insert(key, value).is_some() {
 8037            // This case should hopefully be rare, but just in case...
 8038            log::error!(
 8039                "multiple different run targets found on a single line, only the last target will be rendered"
 8040            )
 8041        }
 8042    }
 8043
 8044    /// Get all display points of breakpoints that will be rendered within editor
 8045    ///
 8046    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8047    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8048    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8049    fn active_breakpoints(
 8050        &self,
 8051        range: Range<DisplayRow>,
 8052        window: &mut Window,
 8053        cx: &mut Context<Self>,
 8054    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8055        let mut breakpoint_display_points = HashMap::default();
 8056
 8057        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8058            return breakpoint_display_points;
 8059        };
 8060
 8061        let snapshot = self.snapshot(window, cx);
 8062
 8063        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8064        let Some(project) = self.project() else {
 8065            return breakpoint_display_points;
 8066        };
 8067
 8068        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8069            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8070
 8071        for (buffer_snapshot, range, excerpt_id) in
 8072            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8073        {
 8074            let Some(buffer) = project
 8075                .read(cx)
 8076                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8077            else {
 8078                continue;
 8079            };
 8080            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8081                &buffer,
 8082                Some(
 8083                    buffer_snapshot.anchor_before(range.start)
 8084                        ..buffer_snapshot.anchor_after(range.end),
 8085                ),
 8086                buffer_snapshot,
 8087                cx,
 8088            );
 8089            for (breakpoint, state) in breakpoints {
 8090                let multi_buffer_anchor =
 8091                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8092                let position = multi_buffer_anchor
 8093                    .to_point(&multi_buffer_snapshot)
 8094                    .to_display_point(&snapshot);
 8095
 8096                breakpoint_display_points.insert(
 8097                    position.row(),
 8098                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8099                );
 8100            }
 8101        }
 8102
 8103        breakpoint_display_points
 8104    }
 8105
 8106    fn breakpoint_context_menu(
 8107        &self,
 8108        anchor: Anchor,
 8109        window: &mut Window,
 8110        cx: &mut Context<Self>,
 8111    ) -> Entity<ui::ContextMenu> {
 8112        let weak_editor = cx.weak_entity();
 8113        let focus_handle = self.focus_handle(cx);
 8114
 8115        let row = self
 8116            .buffer
 8117            .read(cx)
 8118            .snapshot(cx)
 8119            .summary_for_anchor::<Point>(&anchor)
 8120            .row;
 8121
 8122        let breakpoint = self
 8123            .breakpoint_at_row(row, window, cx)
 8124            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8125
 8126        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8127            "Edit Log Breakpoint"
 8128        } else {
 8129            "Set Log Breakpoint"
 8130        };
 8131
 8132        let condition_breakpoint_msg = if breakpoint
 8133            .as_ref()
 8134            .is_some_and(|bp| bp.1.condition.is_some())
 8135        {
 8136            "Edit Condition Breakpoint"
 8137        } else {
 8138            "Set Condition Breakpoint"
 8139        };
 8140
 8141        let hit_condition_breakpoint_msg = if breakpoint
 8142            .as_ref()
 8143            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8144        {
 8145            "Edit Hit Condition Breakpoint"
 8146        } else {
 8147            "Set Hit Condition Breakpoint"
 8148        };
 8149
 8150        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8151            "Unset Breakpoint"
 8152        } else {
 8153            "Set Breakpoint"
 8154        };
 8155
 8156        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8157
 8158        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8159            BreakpointState::Enabled => Some("Disable"),
 8160            BreakpointState::Disabled => Some("Enable"),
 8161        });
 8162
 8163        let (anchor, breakpoint) =
 8164            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8165
 8166        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8167            menu.on_blur_subscription(Subscription::new(|| {}))
 8168                .context(focus_handle)
 8169                .when(run_to_cursor, |this| {
 8170                    let weak_editor = weak_editor.clone();
 8171                    this.entry("Run to cursor", None, move |window, cx| {
 8172                        weak_editor
 8173                            .update(cx, |editor, cx| {
 8174                                editor.change_selections(
 8175                                    SelectionEffects::no_scroll(),
 8176                                    window,
 8177                                    cx,
 8178                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8179                                );
 8180                            })
 8181                            .ok();
 8182
 8183                        window.dispatch_action(Box::new(RunToCursor), cx);
 8184                    })
 8185                    .separator()
 8186                })
 8187                .when_some(toggle_state_msg, |this, msg| {
 8188                    this.entry(msg, None, {
 8189                        let weak_editor = weak_editor.clone();
 8190                        let breakpoint = breakpoint.clone();
 8191                        move |_window, cx| {
 8192                            weak_editor
 8193                                .update(cx, |this, cx| {
 8194                                    this.edit_breakpoint_at_anchor(
 8195                                        anchor,
 8196                                        breakpoint.as_ref().clone(),
 8197                                        BreakpointEditAction::InvertState,
 8198                                        cx,
 8199                                    );
 8200                                })
 8201                                .log_err();
 8202                        }
 8203                    })
 8204                })
 8205                .entry(set_breakpoint_msg, None, {
 8206                    let weak_editor = weak_editor.clone();
 8207                    let breakpoint = breakpoint.clone();
 8208                    move |_window, cx| {
 8209                        weak_editor
 8210                            .update(cx, |this, cx| {
 8211                                this.edit_breakpoint_at_anchor(
 8212                                    anchor,
 8213                                    breakpoint.as_ref().clone(),
 8214                                    BreakpointEditAction::Toggle,
 8215                                    cx,
 8216                                );
 8217                            })
 8218                            .log_err();
 8219                    }
 8220                })
 8221                .entry(log_breakpoint_msg, None, {
 8222                    let breakpoint = breakpoint.clone();
 8223                    let weak_editor = weak_editor.clone();
 8224                    move |window, cx| {
 8225                        weak_editor
 8226                            .update(cx, |this, cx| {
 8227                                this.add_edit_breakpoint_block(
 8228                                    anchor,
 8229                                    breakpoint.as_ref(),
 8230                                    BreakpointPromptEditAction::Log,
 8231                                    window,
 8232                                    cx,
 8233                                );
 8234                            })
 8235                            .log_err();
 8236                    }
 8237                })
 8238                .entry(condition_breakpoint_msg, None, {
 8239                    let breakpoint = breakpoint.clone();
 8240                    let weak_editor = weak_editor.clone();
 8241                    move |window, cx| {
 8242                        weak_editor
 8243                            .update(cx, |this, cx| {
 8244                                this.add_edit_breakpoint_block(
 8245                                    anchor,
 8246                                    breakpoint.as_ref(),
 8247                                    BreakpointPromptEditAction::Condition,
 8248                                    window,
 8249                                    cx,
 8250                                );
 8251                            })
 8252                            .log_err();
 8253                    }
 8254                })
 8255                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8256                    weak_editor
 8257                        .update(cx, |this, cx| {
 8258                            this.add_edit_breakpoint_block(
 8259                                anchor,
 8260                                breakpoint.as_ref(),
 8261                                BreakpointPromptEditAction::HitCondition,
 8262                                window,
 8263                                cx,
 8264                            );
 8265                        })
 8266                        .log_err();
 8267                })
 8268        })
 8269    }
 8270
 8271    fn render_breakpoint(
 8272        &self,
 8273        position: Anchor,
 8274        row: DisplayRow,
 8275        breakpoint: &Breakpoint,
 8276        state: Option<BreakpointSessionState>,
 8277        cx: &mut Context<Self>,
 8278    ) -> IconButton {
 8279        let is_rejected = state.is_some_and(|s| !s.verified);
 8280        // Is it a breakpoint that shows up when hovering over gutter?
 8281        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8282            (false, false),
 8283            |PhantomBreakpointIndicator {
 8284                 is_active,
 8285                 display_row,
 8286                 collides_with_existing_breakpoint,
 8287             }| {
 8288                (
 8289                    is_active && display_row == row,
 8290                    collides_with_existing_breakpoint,
 8291                )
 8292            },
 8293        );
 8294
 8295        let (color, icon) = {
 8296            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8297                (false, false) => ui::IconName::DebugBreakpoint,
 8298                (true, false) => ui::IconName::DebugLogBreakpoint,
 8299                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8300                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8301            };
 8302
 8303            let color = if is_phantom {
 8304                Color::Hint
 8305            } else if is_rejected {
 8306                Color::Disabled
 8307            } else {
 8308                Color::Debugger
 8309            };
 8310
 8311            (color, icon)
 8312        };
 8313
 8314        let breakpoint = Arc::from(breakpoint.clone());
 8315
 8316        let alt_as_text = gpui::Keystroke {
 8317            modifiers: Modifiers::secondary_key(),
 8318            ..Default::default()
 8319        };
 8320        let primary_action_text = if breakpoint.is_disabled() {
 8321            "Enable breakpoint"
 8322        } else if is_phantom && !collides_with_existing {
 8323            "Set breakpoint"
 8324        } else {
 8325            "Unset breakpoint"
 8326        };
 8327        let focus_handle = self.focus_handle.clone();
 8328
 8329        let meta = if is_rejected {
 8330            SharedString::from("No executable code is associated with this line.")
 8331        } else if collides_with_existing && !breakpoint.is_disabled() {
 8332            SharedString::from(format!(
 8333                "{alt_as_text}-click to disable,\nright-click for more options."
 8334            ))
 8335        } else {
 8336            SharedString::from("Right-click for more options.")
 8337        };
 8338        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8339            .icon_size(IconSize::XSmall)
 8340            .size(ui::ButtonSize::None)
 8341            .when(is_rejected, |this| {
 8342                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8343            })
 8344            .icon_color(color)
 8345            .style(ButtonStyle::Transparent)
 8346            .on_click(cx.listener({
 8347                move |editor, event: &ClickEvent, window, cx| {
 8348                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8349                        BreakpointEditAction::InvertState
 8350                    } else {
 8351                        BreakpointEditAction::Toggle
 8352                    };
 8353
 8354                    window.focus(&editor.focus_handle(cx));
 8355                    editor.edit_breakpoint_at_anchor(
 8356                        position,
 8357                        breakpoint.as_ref().clone(),
 8358                        edit_action,
 8359                        cx,
 8360                    );
 8361                }
 8362            }))
 8363            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8364                editor.set_breakpoint_context_menu(
 8365                    row,
 8366                    Some(position),
 8367                    event.position(),
 8368                    window,
 8369                    cx,
 8370                );
 8371            }))
 8372            .tooltip(move |_window, cx| {
 8373                Tooltip::with_meta_in(
 8374                    primary_action_text,
 8375                    Some(&ToggleBreakpoint),
 8376                    meta.clone(),
 8377                    &focus_handle,
 8378                    cx,
 8379                )
 8380            })
 8381    }
 8382
 8383    fn build_tasks_context(
 8384        project: &Entity<Project>,
 8385        buffer: &Entity<Buffer>,
 8386        buffer_row: u32,
 8387        tasks: &Arc<RunnableTasks>,
 8388        cx: &mut Context<Self>,
 8389    ) -> Task<Option<task::TaskContext>> {
 8390        let position = Point::new(buffer_row, tasks.column);
 8391        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8392        let location = Location {
 8393            buffer: buffer.clone(),
 8394            range: range_start..range_start,
 8395        };
 8396        // Fill in the environmental variables from the tree-sitter captures
 8397        let mut captured_task_variables = TaskVariables::default();
 8398        for (capture_name, value) in tasks.extra_variables.clone() {
 8399            captured_task_variables.insert(
 8400                task::VariableName::Custom(capture_name.into()),
 8401                value.clone(),
 8402            );
 8403        }
 8404        project.update(cx, |project, cx| {
 8405            project.task_store().update(cx, |task_store, cx| {
 8406                task_store.task_context_for_location(captured_task_variables, location, cx)
 8407            })
 8408        })
 8409    }
 8410
 8411    pub fn spawn_nearest_task(
 8412        &mut self,
 8413        action: &SpawnNearestTask,
 8414        window: &mut Window,
 8415        cx: &mut Context<Self>,
 8416    ) {
 8417        let Some((workspace, _)) = self.workspace.clone() else {
 8418            return;
 8419        };
 8420        let Some(project) = self.project.clone() else {
 8421            return;
 8422        };
 8423
 8424        // Try to find a closest, enclosing node using tree-sitter that has a task
 8425        let Some((buffer, buffer_row, tasks)) = self
 8426            .find_enclosing_node_task(cx)
 8427            // Or find the task that's closest in row-distance.
 8428            .or_else(|| self.find_closest_task(cx))
 8429        else {
 8430            return;
 8431        };
 8432
 8433        let reveal_strategy = action.reveal;
 8434        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8435        cx.spawn_in(window, async move |_, cx| {
 8436            let context = task_context.await?;
 8437            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8438
 8439            let resolved = &mut resolved_task.resolved;
 8440            resolved.reveal = reveal_strategy;
 8441
 8442            workspace
 8443                .update_in(cx, |workspace, window, cx| {
 8444                    workspace.schedule_resolved_task(
 8445                        task_source_kind,
 8446                        resolved_task,
 8447                        false,
 8448                        window,
 8449                        cx,
 8450                    );
 8451                })
 8452                .ok()
 8453        })
 8454        .detach();
 8455    }
 8456
 8457    fn find_closest_task(
 8458        &mut self,
 8459        cx: &mut Context<Self>,
 8460    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8461        let cursor_row = self
 8462            .selections
 8463            .newest_adjusted(&self.display_snapshot(cx))
 8464            .head()
 8465            .row;
 8466
 8467        let ((buffer_id, row), tasks) = self
 8468            .tasks
 8469            .iter()
 8470            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8471
 8472        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8473        let tasks = Arc::new(tasks.to_owned());
 8474        Some((buffer, *row, tasks))
 8475    }
 8476
 8477    fn find_enclosing_node_task(
 8478        &mut self,
 8479        cx: &mut Context<Self>,
 8480    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8481        let snapshot = self.buffer.read(cx).snapshot(cx);
 8482        let offset = self
 8483            .selections
 8484            .newest::<usize>(&self.display_snapshot(cx))
 8485            .head();
 8486        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8487        let buffer_id = excerpt.buffer().remote_id();
 8488
 8489        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8490        let mut cursor = layer.node().walk();
 8491
 8492        while cursor.goto_first_child_for_byte(offset).is_some() {
 8493            if cursor.node().end_byte() == offset {
 8494                cursor.goto_next_sibling();
 8495            }
 8496        }
 8497
 8498        // Ascend to the smallest ancestor that contains the range and has a task.
 8499        loop {
 8500            let node = cursor.node();
 8501            let node_range = node.byte_range();
 8502            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8503
 8504            // Check if this node contains our offset
 8505            if node_range.start <= offset && node_range.end >= offset {
 8506                // If it contains offset, check for task
 8507                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8508                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8509                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8510                }
 8511            }
 8512
 8513            if !cursor.goto_parent() {
 8514                break;
 8515            }
 8516        }
 8517        None
 8518    }
 8519
 8520    fn render_run_indicator(
 8521        &self,
 8522        _style: &EditorStyle,
 8523        is_active: bool,
 8524        row: DisplayRow,
 8525        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8526        cx: &mut Context<Self>,
 8527    ) -> IconButton {
 8528        let color = Color::Muted;
 8529        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8530
 8531        IconButton::new(
 8532            ("run_indicator", row.0 as usize),
 8533            ui::IconName::PlayOutlined,
 8534        )
 8535        .shape(ui::IconButtonShape::Square)
 8536        .icon_size(IconSize::XSmall)
 8537        .icon_color(color)
 8538        .toggle_state(is_active)
 8539        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8540            let quick_launch = match e {
 8541                ClickEvent::Keyboard(_) => true,
 8542                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8543            };
 8544
 8545            window.focus(&editor.focus_handle(cx));
 8546            editor.toggle_code_actions(
 8547                &ToggleCodeActions {
 8548                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8549                    quick_launch,
 8550                },
 8551                window,
 8552                cx,
 8553            );
 8554        }))
 8555        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8556            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8557        }))
 8558    }
 8559
 8560    pub fn context_menu_visible(&self) -> bool {
 8561        !self.edit_prediction_preview_is_active()
 8562            && self
 8563                .context_menu
 8564                .borrow()
 8565                .as_ref()
 8566                .is_some_and(|menu| menu.visible())
 8567    }
 8568
 8569    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8570        self.context_menu
 8571            .borrow()
 8572            .as_ref()
 8573            .map(|menu| menu.origin())
 8574    }
 8575
 8576    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8577        self.context_menu_options = Some(options);
 8578    }
 8579
 8580    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8581    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8582
 8583    fn render_edit_prediction_popover(
 8584        &mut self,
 8585        text_bounds: &Bounds<Pixels>,
 8586        content_origin: gpui::Point<Pixels>,
 8587        right_margin: Pixels,
 8588        editor_snapshot: &EditorSnapshot,
 8589        visible_row_range: Range<DisplayRow>,
 8590        scroll_top: ScrollOffset,
 8591        scroll_bottom: ScrollOffset,
 8592        line_layouts: &[LineWithInvisibles],
 8593        line_height: Pixels,
 8594        scroll_position: gpui::Point<ScrollOffset>,
 8595        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8596        newest_selection_head: Option<DisplayPoint>,
 8597        editor_width: Pixels,
 8598        style: &EditorStyle,
 8599        window: &mut Window,
 8600        cx: &mut App,
 8601    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8602        if self.mode().is_minimap() {
 8603            return None;
 8604        }
 8605        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8606
 8607        if self.edit_prediction_visible_in_cursor_popover(true) {
 8608            return None;
 8609        }
 8610
 8611        match &active_edit_prediction.completion {
 8612            EditPrediction::MoveWithin { target, .. } => {
 8613                let target_display_point = target.to_display_point(editor_snapshot);
 8614
 8615                if self.edit_prediction_requires_modifier() {
 8616                    if !self.edit_prediction_preview_is_active() {
 8617                        return None;
 8618                    }
 8619
 8620                    self.render_edit_prediction_modifier_jump_popover(
 8621                        text_bounds,
 8622                        content_origin,
 8623                        visible_row_range,
 8624                        line_layouts,
 8625                        line_height,
 8626                        scroll_pixel_position,
 8627                        newest_selection_head,
 8628                        target_display_point,
 8629                        window,
 8630                        cx,
 8631                    )
 8632                } else {
 8633                    self.render_edit_prediction_eager_jump_popover(
 8634                        text_bounds,
 8635                        content_origin,
 8636                        editor_snapshot,
 8637                        visible_row_range,
 8638                        scroll_top,
 8639                        scroll_bottom,
 8640                        line_height,
 8641                        scroll_pixel_position,
 8642                        target_display_point,
 8643                        editor_width,
 8644                        window,
 8645                        cx,
 8646                    )
 8647                }
 8648            }
 8649            EditPrediction::Edit {
 8650                display_mode: EditDisplayMode::Inline,
 8651                ..
 8652            } => None,
 8653            EditPrediction::Edit {
 8654                display_mode: EditDisplayMode::TabAccept,
 8655                edits,
 8656                ..
 8657            } => {
 8658                let range = &edits.first()?.0;
 8659                let target_display_point = range.end.to_display_point(editor_snapshot);
 8660
 8661                self.render_edit_prediction_end_of_line_popover(
 8662                    "Accept",
 8663                    editor_snapshot,
 8664                    visible_row_range,
 8665                    target_display_point,
 8666                    line_height,
 8667                    scroll_pixel_position,
 8668                    content_origin,
 8669                    editor_width,
 8670                    window,
 8671                    cx,
 8672                )
 8673            }
 8674            EditPrediction::Edit {
 8675                edits,
 8676                edit_preview,
 8677                display_mode: EditDisplayMode::DiffPopover,
 8678                snapshot,
 8679            } => self.render_edit_prediction_diff_popover(
 8680                text_bounds,
 8681                content_origin,
 8682                right_margin,
 8683                editor_snapshot,
 8684                visible_row_range,
 8685                line_layouts,
 8686                line_height,
 8687                scroll_position,
 8688                scroll_pixel_position,
 8689                newest_selection_head,
 8690                editor_width,
 8691                style,
 8692                edits,
 8693                edit_preview,
 8694                snapshot,
 8695                window,
 8696                cx,
 8697            ),
 8698            EditPrediction::MoveOutside { snapshot, .. } => {
 8699                let file_name = snapshot
 8700                    .file()
 8701                    .map(|file| file.file_name(cx))
 8702                    .unwrap_or("untitled");
 8703                let mut element = self
 8704                    .render_edit_prediction_line_popover(
 8705                        format!("Jump to {file_name}"),
 8706                        Some(IconName::ZedPredict),
 8707                        window,
 8708                        cx,
 8709                    )
 8710                    .into_any();
 8711
 8712                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8713                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8714                let origin_y = text_bounds.size.height - size.height - px(30.);
 8715                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8716                element.prepaint_at(origin, window, cx);
 8717
 8718                Some((element, origin))
 8719            }
 8720        }
 8721    }
 8722
 8723    fn render_edit_prediction_modifier_jump_popover(
 8724        &mut self,
 8725        text_bounds: &Bounds<Pixels>,
 8726        content_origin: gpui::Point<Pixels>,
 8727        visible_row_range: Range<DisplayRow>,
 8728        line_layouts: &[LineWithInvisibles],
 8729        line_height: Pixels,
 8730        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8731        newest_selection_head: Option<DisplayPoint>,
 8732        target_display_point: DisplayPoint,
 8733        window: &mut Window,
 8734        cx: &mut App,
 8735    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8736        let scrolled_content_origin =
 8737            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8738
 8739        const SCROLL_PADDING_Y: Pixels = px(12.);
 8740
 8741        if target_display_point.row() < visible_row_range.start {
 8742            return self.render_edit_prediction_scroll_popover(
 8743                |_| SCROLL_PADDING_Y,
 8744                IconName::ArrowUp,
 8745                visible_row_range,
 8746                line_layouts,
 8747                newest_selection_head,
 8748                scrolled_content_origin,
 8749                window,
 8750                cx,
 8751            );
 8752        } else if target_display_point.row() >= visible_row_range.end {
 8753            return self.render_edit_prediction_scroll_popover(
 8754                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8755                IconName::ArrowDown,
 8756                visible_row_range,
 8757                line_layouts,
 8758                newest_selection_head,
 8759                scrolled_content_origin,
 8760                window,
 8761                cx,
 8762            );
 8763        }
 8764
 8765        const POLE_WIDTH: Pixels = px(2.);
 8766
 8767        let line_layout =
 8768            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8769        let target_column = target_display_point.column() as usize;
 8770
 8771        let target_x = line_layout.x_for_index(target_column);
 8772        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8773            - scroll_pixel_position.y;
 8774
 8775        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8776
 8777        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8778        border_color.l += 0.001;
 8779
 8780        let mut element = v_flex()
 8781            .items_end()
 8782            .when(flag_on_right, |el| el.items_start())
 8783            .child(if flag_on_right {
 8784                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8785                    .rounded_bl(px(0.))
 8786                    .rounded_tl(px(0.))
 8787                    .border_l_2()
 8788                    .border_color(border_color)
 8789            } else {
 8790                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8791                    .rounded_br(px(0.))
 8792                    .rounded_tr(px(0.))
 8793                    .border_r_2()
 8794                    .border_color(border_color)
 8795            })
 8796            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8797            .into_any();
 8798
 8799        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8800
 8801        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8802            - point(
 8803                if flag_on_right {
 8804                    POLE_WIDTH
 8805                } else {
 8806                    size.width - POLE_WIDTH
 8807                },
 8808                size.height - line_height,
 8809            );
 8810
 8811        origin.x = origin.x.max(content_origin.x);
 8812
 8813        element.prepaint_at(origin, window, cx);
 8814
 8815        Some((element, origin))
 8816    }
 8817
 8818    fn render_edit_prediction_scroll_popover(
 8819        &mut self,
 8820        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8821        scroll_icon: IconName,
 8822        visible_row_range: Range<DisplayRow>,
 8823        line_layouts: &[LineWithInvisibles],
 8824        newest_selection_head: Option<DisplayPoint>,
 8825        scrolled_content_origin: gpui::Point<Pixels>,
 8826        window: &mut Window,
 8827        cx: &mut App,
 8828    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8829        let mut element = self
 8830            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8831            .into_any();
 8832
 8833        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8834
 8835        let cursor = newest_selection_head?;
 8836        let cursor_row_layout =
 8837            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8838        let cursor_column = cursor.column() as usize;
 8839
 8840        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8841
 8842        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8843
 8844        element.prepaint_at(origin, window, cx);
 8845        Some((element, origin))
 8846    }
 8847
 8848    fn render_edit_prediction_eager_jump_popover(
 8849        &mut self,
 8850        text_bounds: &Bounds<Pixels>,
 8851        content_origin: gpui::Point<Pixels>,
 8852        editor_snapshot: &EditorSnapshot,
 8853        visible_row_range: Range<DisplayRow>,
 8854        scroll_top: ScrollOffset,
 8855        scroll_bottom: ScrollOffset,
 8856        line_height: Pixels,
 8857        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8858        target_display_point: DisplayPoint,
 8859        editor_width: Pixels,
 8860        window: &mut Window,
 8861        cx: &mut App,
 8862    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8863        if target_display_point.row().as_f64() < scroll_top {
 8864            let mut element = self
 8865                .render_edit_prediction_line_popover(
 8866                    "Jump to Edit",
 8867                    Some(IconName::ArrowUp),
 8868                    window,
 8869                    cx,
 8870                )
 8871                .into_any();
 8872
 8873            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8874            let offset = point(
 8875                (text_bounds.size.width - size.width) / 2.,
 8876                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8877            );
 8878
 8879            let origin = text_bounds.origin + offset;
 8880            element.prepaint_at(origin, window, cx);
 8881            Some((element, origin))
 8882        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 8883            let mut element = self
 8884                .render_edit_prediction_line_popover(
 8885                    "Jump to Edit",
 8886                    Some(IconName::ArrowDown),
 8887                    window,
 8888                    cx,
 8889                )
 8890                .into_any();
 8891
 8892            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8893            let offset = point(
 8894                (text_bounds.size.width - size.width) / 2.,
 8895                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8896            );
 8897
 8898            let origin = text_bounds.origin + offset;
 8899            element.prepaint_at(origin, window, cx);
 8900            Some((element, origin))
 8901        } else {
 8902            self.render_edit_prediction_end_of_line_popover(
 8903                "Jump to Edit",
 8904                editor_snapshot,
 8905                visible_row_range,
 8906                target_display_point,
 8907                line_height,
 8908                scroll_pixel_position,
 8909                content_origin,
 8910                editor_width,
 8911                window,
 8912                cx,
 8913            )
 8914        }
 8915    }
 8916
 8917    fn render_edit_prediction_end_of_line_popover(
 8918        self: &mut Editor,
 8919        label: &'static str,
 8920        editor_snapshot: &EditorSnapshot,
 8921        visible_row_range: Range<DisplayRow>,
 8922        target_display_point: DisplayPoint,
 8923        line_height: Pixels,
 8924        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8925        content_origin: gpui::Point<Pixels>,
 8926        editor_width: Pixels,
 8927        window: &mut Window,
 8928        cx: &mut App,
 8929    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8930        let target_line_end = DisplayPoint::new(
 8931            target_display_point.row(),
 8932            editor_snapshot.line_len(target_display_point.row()),
 8933        );
 8934
 8935        let mut element = self
 8936            .render_edit_prediction_line_popover(label, None, window, cx)
 8937            .into_any();
 8938
 8939        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8940
 8941        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8942
 8943        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 8944        let mut origin = start_point
 8945            + line_origin
 8946            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8947        origin.x = origin.x.max(content_origin.x);
 8948
 8949        let max_x = content_origin.x + editor_width - size.width;
 8950
 8951        if origin.x > max_x {
 8952            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8953
 8954            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8955                origin.y += offset;
 8956                IconName::ArrowUp
 8957            } else {
 8958                origin.y -= offset;
 8959                IconName::ArrowDown
 8960            };
 8961
 8962            element = self
 8963                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 8964                .into_any();
 8965
 8966            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8967
 8968            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8969        }
 8970
 8971        element.prepaint_at(origin, window, cx);
 8972        Some((element, origin))
 8973    }
 8974
 8975    fn render_edit_prediction_diff_popover(
 8976        self: &Editor,
 8977        text_bounds: &Bounds<Pixels>,
 8978        content_origin: gpui::Point<Pixels>,
 8979        right_margin: Pixels,
 8980        editor_snapshot: &EditorSnapshot,
 8981        visible_row_range: Range<DisplayRow>,
 8982        line_layouts: &[LineWithInvisibles],
 8983        line_height: Pixels,
 8984        scroll_position: gpui::Point<ScrollOffset>,
 8985        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8986        newest_selection_head: Option<DisplayPoint>,
 8987        editor_width: Pixels,
 8988        style: &EditorStyle,
 8989        edits: &Vec<(Range<Anchor>, String)>,
 8990        edit_preview: &Option<language::EditPreview>,
 8991        snapshot: &language::BufferSnapshot,
 8992        window: &mut Window,
 8993        cx: &mut App,
 8994    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8995        let edit_start = edits
 8996            .first()
 8997            .unwrap()
 8998            .0
 8999            .start
 9000            .to_display_point(editor_snapshot);
 9001        let edit_end = edits
 9002            .last()
 9003            .unwrap()
 9004            .0
 9005            .end
 9006            .to_display_point(editor_snapshot);
 9007
 9008        let is_visible = visible_row_range.contains(&edit_start.row())
 9009            || visible_row_range.contains(&edit_end.row());
 9010        if !is_visible {
 9011            return None;
 9012        }
 9013
 9014        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9015            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9016        } else {
 9017            // Fallback for providers without edit_preview
 9018            crate::edit_prediction_fallback_text(edits, cx)
 9019        };
 9020
 9021        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9022        let line_count = highlighted_edits.text.lines().count();
 9023
 9024        const BORDER_WIDTH: Pixels = px(1.);
 9025
 9026        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9027        let has_keybind = keybind.is_some();
 9028
 9029        let mut element = h_flex()
 9030            .items_start()
 9031            .child(
 9032                h_flex()
 9033                    .bg(cx.theme().colors().editor_background)
 9034                    .border(BORDER_WIDTH)
 9035                    .shadow_xs()
 9036                    .border_color(cx.theme().colors().border)
 9037                    .rounded_l_lg()
 9038                    .when(line_count > 1, |el| el.rounded_br_lg())
 9039                    .pr_1()
 9040                    .child(styled_text),
 9041            )
 9042            .child(
 9043                h_flex()
 9044                    .h(line_height + BORDER_WIDTH * 2.)
 9045                    .px_1p5()
 9046                    .gap_1()
 9047                    // Workaround: For some reason, there's a gap if we don't do this
 9048                    .ml(-BORDER_WIDTH)
 9049                    .shadow(vec![gpui::BoxShadow {
 9050                        color: gpui::black().opacity(0.05),
 9051                        offset: point(px(1.), px(1.)),
 9052                        blur_radius: px(2.),
 9053                        spread_radius: px(0.),
 9054                    }])
 9055                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9056                    .border(BORDER_WIDTH)
 9057                    .border_color(cx.theme().colors().border)
 9058                    .rounded_r_lg()
 9059                    .id("edit_prediction_diff_popover_keybind")
 9060                    .when(!has_keybind, |el| {
 9061                        let status_colors = cx.theme().status();
 9062
 9063                        el.bg(status_colors.error_background)
 9064                            .border_color(status_colors.error.opacity(0.6))
 9065                            .child(Icon::new(IconName::Info).color(Color::Error))
 9066                            .cursor_default()
 9067                            .hoverable_tooltip(move |_window, cx| {
 9068                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9069                            })
 9070                    })
 9071                    .children(keybind),
 9072            )
 9073            .into_any();
 9074
 9075        let longest_row =
 9076            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9077        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9078            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9079        } else {
 9080            layout_line(
 9081                longest_row,
 9082                editor_snapshot,
 9083                style,
 9084                editor_width,
 9085                |_| false,
 9086                window,
 9087                cx,
 9088            )
 9089            .width
 9090        };
 9091
 9092        let viewport_bounds =
 9093            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9094                right: -right_margin,
 9095                ..Default::default()
 9096            });
 9097
 9098        let x_after_longest = Pixels::from(
 9099            ScrollPixelOffset::from(
 9100                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9101            ) - scroll_pixel_position.x,
 9102        );
 9103
 9104        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9105
 9106        // Fully visible if it can be displayed within the window (allow overlapping other
 9107        // panes). However, this is only allowed if the popover starts within text_bounds.
 9108        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9109            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9110
 9111        let mut origin = if can_position_to_the_right {
 9112            point(
 9113                x_after_longest,
 9114                text_bounds.origin.y
 9115                    + Pixels::from(
 9116                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9117                            - scroll_pixel_position.y,
 9118                    ),
 9119            )
 9120        } else {
 9121            let cursor_row = newest_selection_head.map(|head| head.row());
 9122            let above_edit = edit_start
 9123                .row()
 9124                .0
 9125                .checked_sub(line_count as u32)
 9126                .map(DisplayRow);
 9127            let below_edit = Some(edit_end.row() + 1);
 9128            let above_cursor =
 9129                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9130            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9131
 9132            // Place the edit popover adjacent to the edit if there is a location
 9133            // available that is onscreen and does not obscure the cursor. Otherwise,
 9134            // place it adjacent to the cursor.
 9135            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9136                .into_iter()
 9137                .flatten()
 9138                .find(|&start_row| {
 9139                    let end_row = start_row + line_count as u32;
 9140                    visible_row_range.contains(&start_row)
 9141                        && visible_row_range.contains(&end_row)
 9142                        && cursor_row
 9143                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9144                })?;
 9145
 9146            content_origin
 9147                + point(
 9148                    Pixels::from(-scroll_pixel_position.x),
 9149                    Pixels::from(
 9150                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9151                    ),
 9152                )
 9153        };
 9154
 9155        origin.x -= BORDER_WIDTH;
 9156
 9157        window.defer_draw(element, origin, 1);
 9158
 9159        // Do not return an element, since it will already be drawn due to defer_draw.
 9160        None
 9161    }
 9162
 9163    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9164        px(30.)
 9165    }
 9166
 9167    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9168        if self.read_only(cx) {
 9169            cx.theme().players().read_only()
 9170        } else {
 9171            self.style.as_ref().unwrap().local_player
 9172        }
 9173    }
 9174
 9175    fn render_edit_prediction_accept_keybind(
 9176        &self,
 9177        window: &mut Window,
 9178        cx: &mut App,
 9179    ) -> Option<AnyElement> {
 9180        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9181        let accept_keystroke = accept_binding.keystroke()?;
 9182
 9183        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9184
 9185        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9186            Color::Accent
 9187        } else {
 9188            Color::Muted
 9189        };
 9190
 9191        h_flex()
 9192            .px_0p5()
 9193            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9194            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9195            .text_size(TextSize::XSmall.rems(cx))
 9196            .child(h_flex().children(ui::render_modifiers(
 9197                accept_keystroke.modifiers(),
 9198                PlatformStyle::platform(),
 9199                Some(modifiers_color),
 9200                Some(IconSize::XSmall.rems().into()),
 9201                true,
 9202            )))
 9203            .when(is_platform_style_mac, |parent| {
 9204                parent.child(accept_keystroke.key().to_string())
 9205            })
 9206            .when(!is_platform_style_mac, |parent| {
 9207                parent.child(
 9208                    Key::new(
 9209                        util::capitalize(accept_keystroke.key()),
 9210                        Some(Color::Default),
 9211                    )
 9212                    .size(Some(IconSize::XSmall.rems().into())),
 9213                )
 9214            })
 9215            .into_any()
 9216            .into()
 9217    }
 9218
 9219    fn render_edit_prediction_line_popover(
 9220        &self,
 9221        label: impl Into<SharedString>,
 9222        icon: Option<IconName>,
 9223        window: &mut Window,
 9224        cx: &mut App,
 9225    ) -> Stateful<Div> {
 9226        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9227
 9228        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9229        let has_keybind = keybind.is_some();
 9230
 9231        h_flex()
 9232            .id("ep-line-popover")
 9233            .py_0p5()
 9234            .pl_1()
 9235            .pr(padding_right)
 9236            .gap_1()
 9237            .rounded_md()
 9238            .border_1()
 9239            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9240            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9241            .shadow_xs()
 9242            .when(!has_keybind, |el| {
 9243                let status_colors = cx.theme().status();
 9244
 9245                el.bg(status_colors.error_background)
 9246                    .border_color(status_colors.error.opacity(0.6))
 9247                    .pl_2()
 9248                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9249                    .cursor_default()
 9250                    .hoverable_tooltip(move |_window, cx| {
 9251                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9252                    })
 9253            })
 9254            .children(keybind)
 9255            .child(
 9256                Label::new(label)
 9257                    .size(LabelSize::Small)
 9258                    .when(!has_keybind, |el| {
 9259                        el.color(cx.theme().status().error.into()).strikethrough()
 9260                    }),
 9261            )
 9262            .when(!has_keybind, |el| {
 9263                el.child(
 9264                    h_flex().ml_1().child(
 9265                        Icon::new(IconName::Info)
 9266                            .size(IconSize::Small)
 9267                            .color(cx.theme().status().error.into()),
 9268                    ),
 9269                )
 9270            })
 9271            .when_some(icon, |element, icon| {
 9272                element.child(
 9273                    div()
 9274                        .mt(px(1.5))
 9275                        .child(Icon::new(icon).size(IconSize::Small)),
 9276                )
 9277            })
 9278    }
 9279
 9280    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9281        let accent_color = cx.theme().colors().text_accent;
 9282        let editor_bg_color = cx.theme().colors().editor_background;
 9283        editor_bg_color.blend(accent_color.opacity(0.1))
 9284    }
 9285
 9286    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9287        let accent_color = cx.theme().colors().text_accent;
 9288        let editor_bg_color = cx.theme().colors().editor_background;
 9289        editor_bg_color.blend(accent_color.opacity(0.6))
 9290    }
 9291    fn get_prediction_provider_icon_name(
 9292        provider: &Option<RegisteredEditPredictionProvider>,
 9293    ) -> IconName {
 9294        match provider {
 9295            Some(provider) => match provider.provider.name() {
 9296                "copilot" => IconName::Copilot,
 9297                "supermaven" => IconName::Supermaven,
 9298                _ => IconName::ZedPredict,
 9299            },
 9300            None => IconName::ZedPredict,
 9301        }
 9302    }
 9303
 9304    fn render_edit_prediction_cursor_popover(
 9305        &self,
 9306        min_width: Pixels,
 9307        max_width: Pixels,
 9308        cursor_point: Point,
 9309        style: &EditorStyle,
 9310        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9311        _window: &Window,
 9312        cx: &mut Context<Editor>,
 9313    ) -> Option<AnyElement> {
 9314        let provider = self.edit_prediction_provider.as_ref()?;
 9315        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9316
 9317        let is_refreshing = provider.provider.is_refreshing(cx);
 9318
 9319        fn pending_completion_container(icon: IconName) -> Div {
 9320            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9321        }
 9322
 9323        let completion = match &self.active_edit_prediction {
 9324            Some(prediction) => {
 9325                if !self.has_visible_completions_menu() {
 9326                    const RADIUS: Pixels = px(6.);
 9327                    const BORDER_WIDTH: Pixels = px(1.);
 9328
 9329                    return Some(
 9330                        h_flex()
 9331                            .elevation_2(cx)
 9332                            .border(BORDER_WIDTH)
 9333                            .border_color(cx.theme().colors().border)
 9334                            .when(accept_keystroke.is_none(), |el| {
 9335                                el.border_color(cx.theme().status().error)
 9336                            })
 9337                            .rounded(RADIUS)
 9338                            .rounded_tl(px(0.))
 9339                            .overflow_hidden()
 9340                            .child(div().px_1p5().child(match &prediction.completion {
 9341                                EditPrediction::MoveWithin { target, snapshot } => {
 9342                                    use text::ToPoint as _;
 9343                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9344                                    {
 9345                                        Icon::new(IconName::ZedPredictDown)
 9346                                    } else {
 9347                                        Icon::new(IconName::ZedPredictUp)
 9348                                    }
 9349                                }
 9350                                EditPrediction::MoveOutside { .. } => {
 9351                                    // TODO [zeta2] custom icon for external jump?
 9352                                    Icon::new(provider_icon)
 9353                                }
 9354                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9355                            }))
 9356                            .child(
 9357                                h_flex()
 9358                                    .gap_1()
 9359                                    .py_1()
 9360                                    .px_2()
 9361                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9362                                    .border_l_1()
 9363                                    .border_color(cx.theme().colors().border)
 9364                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9365                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9366                                        el.child(
 9367                                            Label::new("Hold")
 9368                                                .size(LabelSize::Small)
 9369                                                .when(accept_keystroke.is_none(), |el| {
 9370                                                    el.strikethrough()
 9371                                                })
 9372                                                .line_height_style(LineHeightStyle::UiLabel),
 9373                                        )
 9374                                    })
 9375                                    .id("edit_prediction_cursor_popover_keybind")
 9376                                    .when(accept_keystroke.is_none(), |el| {
 9377                                        let status_colors = cx.theme().status();
 9378
 9379                                        el.bg(status_colors.error_background)
 9380                                            .border_color(status_colors.error.opacity(0.6))
 9381                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9382                                            .cursor_default()
 9383                                            .hoverable_tooltip(move |_window, cx| {
 9384                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9385                                                    .into()
 9386                                            })
 9387                                    })
 9388                                    .when_some(
 9389                                        accept_keystroke.as_ref(),
 9390                                        |el, accept_keystroke| {
 9391                                            el.child(h_flex().children(ui::render_modifiers(
 9392                                                accept_keystroke.modifiers(),
 9393                                                PlatformStyle::platform(),
 9394                                                Some(Color::Default),
 9395                                                Some(IconSize::XSmall.rems().into()),
 9396                                                false,
 9397                                            )))
 9398                                        },
 9399                                    ),
 9400                            )
 9401                            .into_any(),
 9402                    );
 9403                }
 9404
 9405                self.render_edit_prediction_cursor_popover_preview(
 9406                    prediction,
 9407                    cursor_point,
 9408                    style,
 9409                    cx,
 9410                )?
 9411            }
 9412
 9413            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9414                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9415                    stale_completion,
 9416                    cursor_point,
 9417                    style,
 9418                    cx,
 9419                )?,
 9420
 9421                None => pending_completion_container(provider_icon)
 9422                    .child(Label::new("...").size(LabelSize::Small)),
 9423            },
 9424
 9425            None => pending_completion_container(provider_icon)
 9426                .child(Label::new("...").size(LabelSize::Small)),
 9427        };
 9428
 9429        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9430            completion
 9431                .with_animation(
 9432                    "loading-completion",
 9433                    Animation::new(Duration::from_secs(2))
 9434                        .repeat()
 9435                        .with_easing(pulsating_between(0.4, 0.8)),
 9436                    |label, delta| label.opacity(delta),
 9437                )
 9438                .into_any_element()
 9439        } else {
 9440            completion.into_any_element()
 9441        };
 9442
 9443        let has_completion = self.active_edit_prediction.is_some();
 9444
 9445        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9446        Some(
 9447            h_flex()
 9448                .min_w(min_width)
 9449                .max_w(max_width)
 9450                .flex_1()
 9451                .elevation_2(cx)
 9452                .border_color(cx.theme().colors().border)
 9453                .child(
 9454                    div()
 9455                        .flex_1()
 9456                        .py_1()
 9457                        .px_2()
 9458                        .overflow_hidden()
 9459                        .child(completion),
 9460                )
 9461                .when_some(accept_keystroke, |el, accept_keystroke| {
 9462                    if !accept_keystroke.modifiers().modified() {
 9463                        return el;
 9464                    }
 9465
 9466                    el.child(
 9467                        h_flex()
 9468                            .h_full()
 9469                            .border_l_1()
 9470                            .rounded_r_lg()
 9471                            .border_color(cx.theme().colors().border)
 9472                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9473                            .gap_1()
 9474                            .py_1()
 9475                            .px_2()
 9476                            .child(
 9477                                h_flex()
 9478                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9479                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9480                                    .child(h_flex().children(ui::render_modifiers(
 9481                                        accept_keystroke.modifiers(),
 9482                                        PlatformStyle::platform(),
 9483                                        Some(if !has_completion {
 9484                                            Color::Muted
 9485                                        } else {
 9486                                            Color::Default
 9487                                        }),
 9488                                        None,
 9489                                        false,
 9490                                    ))),
 9491                            )
 9492                            .child(Label::new("Preview").into_any_element())
 9493                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9494                    )
 9495                })
 9496                .into_any(),
 9497        )
 9498    }
 9499
 9500    fn render_edit_prediction_cursor_popover_preview(
 9501        &self,
 9502        completion: &EditPredictionState,
 9503        cursor_point: Point,
 9504        style: &EditorStyle,
 9505        cx: &mut Context<Editor>,
 9506    ) -> Option<Div> {
 9507        use text::ToPoint as _;
 9508
 9509        fn render_relative_row_jump(
 9510            prefix: impl Into<String>,
 9511            current_row: u32,
 9512            target_row: u32,
 9513        ) -> Div {
 9514            let (row_diff, arrow) = if target_row < current_row {
 9515                (current_row - target_row, IconName::ArrowUp)
 9516            } else {
 9517                (target_row - current_row, IconName::ArrowDown)
 9518            };
 9519
 9520            h_flex()
 9521                .child(
 9522                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9523                        .color(Color::Muted)
 9524                        .size(LabelSize::Small),
 9525                )
 9526                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9527        }
 9528
 9529        let supports_jump = self
 9530            .edit_prediction_provider
 9531            .as_ref()
 9532            .map(|provider| provider.provider.supports_jump_to_edit())
 9533            .unwrap_or(true);
 9534
 9535        match &completion.completion {
 9536            EditPrediction::MoveWithin {
 9537                target, snapshot, ..
 9538            } => {
 9539                if !supports_jump {
 9540                    return None;
 9541                }
 9542
 9543                Some(
 9544                    h_flex()
 9545                        .px_2()
 9546                        .gap_2()
 9547                        .flex_1()
 9548                        .child(
 9549                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9550                                Icon::new(IconName::ZedPredictDown)
 9551                            } else {
 9552                                Icon::new(IconName::ZedPredictUp)
 9553                            },
 9554                        )
 9555                        .child(Label::new("Jump to Edit")),
 9556                )
 9557            }
 9558            EditPrediction::MoveOutside { snapshot, .. } => {
 9559                let file_name = snapshot
 9560                    .file()
 9561                    .map(|file| file.file_name(cx))
 9562                    .unwrap_or("untitled");
 9563                Some(
 9564                    h_flex()
 9565                        .px_2()
 9566                        .gap_2()
 9567                        .flex_1()
 9568                        .child(Icon::new(IconName::ZedPredict))
 9569                        .child(Label::new(format!("Jump to {file_name}"))),
 9570                )
 9571            }
 9572            EditPrediction::Edit {
 9573                edits,
 9574                edit_preview,
 9575                snapshot,
 9576                display_mode: _,
 9577            } => {
 9578                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9579
 9580                let (highlighted_edits, has_more_lines) =
 9581                    if let Some(edit_preview) = edit_preview.as_ref() {
 9582                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9583                            .first_line_preview()
 9584                    } else {
 9585                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9586                    };
 9587
 9588                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9589                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9590
 9591                let preview = h_flex()
 9592                    .gap_1()
 9593                    .min_w_16()
 9594                    .child(styled_text)
 9595                    .when(has_more_lines, |parent| parent.child(""));
 9596
 9597                let left = if supports_jump && first_edit_row != cursor_point.row {
 9598                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9599                        .into_any_element()
 9600                } else {
 9601                    let icon_name =
 9602                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9603                    Icon::new(icon_name).into_any_element()
 9604                };
 9605
 9606                Some(
 9607                    h_flex()
 9608                        .h_full()
 9609                        .flex_1()
 9610                        .gap_2()
 9611                        .pr_1()
 9612                        .overflow_x_hidden()
 9613                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9614                        .child(left)
 9615                        .child(preview),
 9616                )
 9617            }
 9618        }
 9619    }
 9620
 9621    pub fn render_context_menu(
 9622        &self,
 9623        style: &EditorStyle,
 9624        max_height_in_lines: u32,
 9625        window: &mut Window,
 9626        cx: &mut Context<Editor>,
 9627    ) -> Option<AnyElement> {
 9628        let menu = self.context_menu.borrow();
 9629        let menu = menu.as_ref()?;
 9630        if !menu.visible() {
 9631            return None;
 9632        };
 9633        Some(menu.render(style, max_height_in_lines, window, cx))
 9634    }
 9635
 9636    fn render_context_menu_aside(
 9637        &mut self,
 9638        max_size: Size<Pixels>,
 9639        window: &mut Window,
 9640        cx: &mut Context<Editor>,
 9641    ) -> Option<AnyElement> {
 9642        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9643            if menu.visible() {
 9644                menu.render_aside(max_size, window, cx)
 9645            } else {
 9646                None
 9647            }
 9648        })
 9649    }
 9650
 9651    fn hide_context_menu(
 9652        &mut self,
 9653        window: &mut Window,
 9654        cx: &mut Context<Self>,
 9655    ) -> Option<CodeContextMenu> {
 9656        cx.notify();
 9657        self.completion_tasks.clear();
 9658        let context_menu = self.context_menu.borrow_mut().take();
 9659        self.stale_edit_prediction_in_menu.take();
 9660        self.update_visible_edit_prediction(window, cx);
 9661        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9662            && let Some(completion_provider) = &self.completion_provider
 9663        {
 9664            completion_provider.selection_changed(None, window, cx);
 9665        }
 9666        context_menu
 9667    }
 9668
 9669    fn show_snippet_choices(
 9670        &mut self,
 9671        choices: &Vec<String>,
 9672        selection: Range<Anchor>,
 9673        cx: &mut Context<Self>,
 9674    ) {
 9675        let Some((_, buffer, _)) = self
 9676            .buffer()
 9677            .read(cx)
 9678            .excerpt_containing(selection.start, cx)
 9679        else {
 9680            return;
 9681        };
 9682        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9683        else {
 9684            return;
 9685        };
 9686        if buffer != end_buffer {
 9687            log::error!("expected anchor range to have matching buffer IDs");
 9688            return;
 9689        }
 9690
 9691        let id = post_inc(&mut self.next_completion_id);
 9692        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9693        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9694            CompletionsMenu::new_snippet_choices(
 9695                id,
 9696                true,
 9697                choices,
 9698                selection,
 9699                buffer,
 9700                snippet_sort_order,
 9701            ),
 9702        ));
 9703    }
 9704
 9705    pub fn insert_snippet(
 9706        &mut self,
 9707        insertion_ranges: &[Range<usize>],
 9708        snippet: Snippet,
 9709        window: &mut Window,
 9710        cx: &mut Context<Self>,
 9711    ) -> Result<()> {
 9712        struct Tabstop<T> {
 9713            is_end_tabstop: bool,
 9714            ranges: Vec<Range<T>>,
 9715            choices: Option<Vec<String>>,
 9716        }
 9717
 9718        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9719            let snippet_text: Arc<str> = snippet.text.clone().into();
 9720            let edits = insertion_ranges
 9721                .iter()
 9722                .cloned()
 9723                .map(|range| (range, snippet_text.clone()));
 9724            let autoindent_mode = AutoindentMode::Block {
 9725                original_indent_columns: Vec::new(),
 9726            };
 9727            buffer.edit(edits, Some(autoindent_mode), cx);
 9728
 9729            let snapshot = &*buffer.read(cx);
 9730            let snippet = &snippet;
 9731            snippet
 9732                .tabstops
 9733                .iter()
 9734                .map(|tabstop| {
 9735                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9736                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9737                    });
 9738                    let mut tabstop_ranges = tabstop
 9739                        .ranges
 9740                        .iter()
 9741                        .flat_map(|tabstop_range| {
 9742                            let mut delta = 0_isize;
 9743                            insertion_ranges.iter().map(move |insertion_range| {
 9744                                let insertion_start = insertion_range.start as isize + delta;
 9745                                delta +=
 9746                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9747
 9748                                let start = ((insertion_start + tabstop_range.start) as usize)
 9749                                    .min(snapshot.len());
 9750                                let end = ((insertion_start + tabstop_range.end) as usize)
 9751                                    .min(snapshot.len());
 9752                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9753                            })
 9754                        })
 9755                        .collect::<Vec<_>>();
 9756                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9757
 9758                    Tabstop {
 9759                        is_end_tabstop,
 9760                        ranges: tabstop_ranges,
 9761                        choices: tabstop.choices.clone(),
 9762                    }
 9763                })
 9764                .collect::<Vec<_>>()
 9765        });
 9766        if let Some(tabstop) = tabstops.first() {
 9767            self.change_selections(Default::default(), window, cx, |s| {
 9768                // Reverse order so that the first range is the newest created selection.
 9769                // Completions will use it and autoscroll will prioritize it.
 9770                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9771            });
 9772
 9773            if let Some(choices) = &tabstop.choices
 9774                && let Some(selection) = tabstop.ranges.first()
 9775            {
 9776                self.show_snippet_choices(choices, selection.clone(), cx)
 9777            }
 9778
 9779            // If we're already at the last tabstop and it's at the end of the snippet,
 9780            // we're done, we don't need to keep the state around.
 9781            if !tabstop.is_end_tabstop {
 9782                let choices = tabstops
 9783                    .iter()
 9784                    .map(|tabstop| tabstop.choices.clone())
 9785                    .collect();
 9786
 9787                let ranges = tabstops
 9788                    .into_iter()
 9789                    .map(|tabstop| tabstop.ranges)
 9790                    .collect::<Vec<_>>();
 9791
 9792                self.snippet_stack.push(SnippetState {
 9793                    active_index: 0,
 9794                    ranges,
 9795                    choices,
 9796                });
 9797            }
 9798
 9799            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9800            if self.autoclose_regions.is_empty() {
 9801                let snapshot = self.buffer.read(cx).snapshot(cx);
 9802                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
 9803                    let selection_head = selection.head();
 9804                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9805                        continue;
 9806                    };
 9807
 9808                    let mut bracket_pair = None;
 9809                    let max_lookup_length = scope
 9810                        .brackets()
 9811                        .map(|(pair, _)| {
 9812                            pair.start
 9813                                .as_str()
 9814                                .chars()
 9815                                .count()
 9816                                .max(pair.end.as_str().chars().count())
 9817                        })
 9818                        .max();
 9819                    if let Some(max_lookup_length) = max_lookup_length {
 9820                        let next_text = snapshot
 9821                            .chars_at(selection_head)
 9822                            .take(max_lookup_length)
 9823                            .collect::<String>();
 9824                        let prev_text = snapshot
 9825                            .reversed_chars_at(selection_head)
 9826                            .take(max_lookup_length)
 9827                            .collect::<String>();
 9828
 9829                        for (pair, enabled) in scope.brackets() {
 9830                            if enabled
 9831                                && pair.close
 9832                                && prev_text.starts_with(pair.start.as_str())
 9833                                && next_text.starts_with(pair.end.as_str())
 9834                            {
 9835                                bracket_pair = Some(pair.clone());
 9836                                break;
 9837                            }
 9838                        }
 9839                    }
 9840
 9841                    if let Some(pair) = bracket_pair {
 9842                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9843                        let autoclose_enabled =
 9844                            self.use_autoclose && snapshot_settings.use_autoclose;
 9845                        if autoclose_enabled {
 9846                            let start = snapshot.anchor_after(selection_head);
 9847                            let end = snapshot.anchor_after(selection_head);
 9848                            self.autoclose_regions.push(AutocloseRegion {
 9849                                selection_id: selection.id,
 9850                                range: start..end,
 9851                                pair,
 9852                            });
 9853                        }
 9854                    }
 9855                }
 9856            }
 9857        }
 9858        Ok(())
 9859    }
 9860
 9861    pub fn move_to_next_snippet_tabstop(
 9862        &mut self,
 9863        window: &mut Window,
 9864        cx: &mut Context<Self>,
 9865    ) -> bool {
 9866        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9867    }
 9868
 9869    pub fn move_to_prev_snippet_tabstop(
 9870        &mut self,
 9871        window: &mut Window,
 9872        cx: &mut Context<Self>,
 9873    ) -> bool {
 9874        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9875    }
 9876
 9877    pub fn move_to_snippet_tabstop(
 9878        &mut self,
 9879        bias: Bias,
 9880        window: &mut Window,
 9881        cx: &mut Context<Self>,
 9882    ) -> bool {
 9883        if let Some(mut snippet) = self.snippet_stack.pop() {
 9884            match bias {
 9885                Bias::Left => {
 9886                    if snippet.active_index > 0 {
 9887                        snippet.active_index -= 1;
 9888                    } else {
 9889                        self.snippet_stack.push(snippet);
 9890                        return false;
 9891                    }
 9892                }
 9893                Bias::Right => {
 9894                    if snippet.active_index + 1 < snippet.ranges.len() {
 9895                        snippet.active_index += 1;
 9896                    } else {
 9897                        self.snippet_stack.push(snippet);
 9898                        return false;
 9899                    }
 9900                }
 9901            }
 9902            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9903                self.change_selections(Default::default(), window, cx, |s| {
 9904                    // Reverse order so that the first range is the newest created selection.
 9905                    // Completions will use it and autoscroll will prioritize it.
 9906                    s.select_ranges(current_ranges.iter().rev().cloned())
 9907                });
 9908
 9909                if let Some(choices) = &snippet.choices[snippet.active_index]
 9910                    && let Some(selection) = current_ranges.first()
 9911                {
 9912                    self.show_snippet_choices(choices, selection.clone(), cx);
 9913                }
 9914
 9915                // If snippet state is not at the last tabstop, push it back on the stack
 9916                if snippet.active_index + 1 < snippet.ranges.len() {
 9917                    self.snippet_stack.push(snippet);
 9918                }
 9919                return true;
 9920            }
 9921        }
 9922
 9923        false
 9924    }
 9925
 9926    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9927        self.transact(window, cx, |this, window, cx| {
 9928            this.select_all(&SelectAll, window, cx);
 9929            this.insert("", window, cx);
 9930        });
 9931    }
 9932
 9933    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9934        if self.read_only(cx) {
 9935            return;
 9936        }
 9937        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9938        self.transact(window, cx, |this, window, cx| {
 9939            this.select_autoclose_pair(window, cx);
 9940
 9941            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9942
 9943            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9944            if !this.linked_edit_ranges.is_empty() {
 9945                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
 9946                let snapshot = this.buffer.read(cx).snapshot(cx);
 9947
 9948                for selection in selections.iter() {
 9949                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9950                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9951                    if selection_start.buffer_id != selection_end.buffer_id {
 9952                        continue;
 9953                    }
 9954                    if let Some(ranges) =
 9955                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9956                    {
 9957                        for (buffer, entries) in ranges {
 9958                            linked_ranges.entry(buffer).or_default().extend(entries);
 9959                        }
 9960                    }
 9961                }
 9962            }
 9963
 9964            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
 9965            for selection in &mut selections {
 9966                if selection.is_empty() {
 9967                    let old_head = selection.head();
 9968                    let mut new_head =
 9969                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9970                            .to_point(&display_map);
 9971                    if let Some((buffer, line_buffer_range)) = display_map
 9972                        .buffer_snapshot()
 9973                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9974                    {
 9975                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9976                        let indent_len = match indent_size.kind {
 9977                            IndentKind::Space => {
 9978                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9979                            }
 9980                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9981                        };
 9982                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9983                            let indent_len = indent_len.get();
 9984                            new_head = cmp::min(
 9985                                new_head,
 9986                                MultiBufferPoint::new(
 9987                                    old_head.row,
 9988                                    ((old_head.column - 1) / indent_len) * indent_len,
 9989                                ),
 9990                            );
 9991                        }
 9992                    }
 9993
 9994                    selection.set_head(new_head, SelectionGoal::None);
 9995                }
 9996            }
 9997
 9998            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9999            this.insert("", window, cx);
10000            let empty_str: Arc<str> = Arc::from("");
10001            for (buffer, edits) in linked_ranges {
10002                let snapshot = buffer.read(cx).snapshot();
10003                use text::ToPoint as TP;
10004
10005                let edits = edits
10006                    .into_iter()
10007                    .map(|range| {
10008                        let end_point = TP::to_point(&range.end, &snapshot);
10009                        let mut start_point = TP::to_point(&range.start, &snapshot);
10010
10011                        if end_point == start_point {
10012                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10013                                .saturating_sub(1);
10014                            start_point =
10015                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10016                        };
10017
10018                        (start_point..end_point, empty_str.clone())
10019                    })
10020                    .sorted_by_key(|(range, _)| range.start)
10021                    .collect::<Vec<_>>();
10022                buffer.update(cx, |this, cx| {
10023                    this.edit(edits, None, cx);
10024                })
10025            }
10026            this.refresh_edit_prediction(true, false, window, cx);
10027            refresh_linked_ranges(this, window, cx);
10028        });
10029    }
10030
10031    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10032        if self.read_only(cx) {
10033            return;
10034        }
10035        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10036        self.transact(window, cx, |this, window, cx| {
10037            this.change_selections(Default::default(), window, cx, |s| {
10038                s.move_with(|map, selection| {
10039                    if selection.is_empty() {
10040                        let cursor = movement::right(map, selection.head());
10041                        selection.end = cursor;
10042                        selection.reversed = true;
10043                        selection.goal = SelectionGoal::None;
10044                    }
10045                })
10046            });
10047            this.insert("", window, cx);
10048            this.refresh_edit_prediction(true, false, window, cx);
10049        });
10050    }
10051
10052    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10053        if self.mode.is_single_line() {
10054            cx.propagate();
10055            return;
10056        }
10057
10058        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10059        if self.move_to_prev_snippet_tabstop(window, cx) {
10060            return;
10061        }
10062        self.outdent(&Outdent, window, cx);
10063    }
10064
10065    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10066        if self.mode.is_single_line() {
10067            cx.propagate();
10068            return;
10069        }
10070
10071        if self.move_to_next_snippet_tabstop(window, cx) {
10072            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10073            return;
10074        }
10075        if self.read_only(cx) {
10076            return;
10077        }
10078        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10079        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10080        let buffer = self.buffer.read(cx);
10081        let snapshot = buffer.snapshot(cx);
10082        let rows_iter = selections.iter().map(|s| s.head().row);
10083        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10084
10085        let has_some_cursor_in_whitespace = selections
10086            .iter()
10087            .filter(|selection| selection.is_empty())
10088            .any(|selection| {
10089                let cursor = selection.head();
10090                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10091                cursor.column < current_indent.len
10092            });
10093
10094        let mut edits = Vec::new();
10095        let mut prev_edited_row = 0;
10096        let mut row_delta = 0;
10097        for selection in &mut selections {
10098            if selection.start.row != prev_edited_row {
10099                row_delta = 0;
10100            }
10101            prev_edited_row = selection.end.row;
10102
10103            // If the selection is non-empty, then increase the indentation of the selected lines.
10104            if !selection.is_empty() {
10105                row_delta =
10106                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10107                continue;
10108            }
10109
10110            let cursor = selection.head();
10111            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10112            if let Some(suggested_indent) =
10113                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10114            {
10115                // Don't do anything if already at suggested indent
10116                // and there is any other cursor which is not
10117                if has_some_cursor_in_whitespace
10118                    && cursor.column == current_indent.len
10119                    && current_indent.len == suggested_indent.len
10120                {
10121                    continue;
10122                }
10123
10124                // Adjust line and move cursor to suggested indent
10125                // if cursor is not at suggested indent
10126                if cursor.column < suggested_indent.len
10127                    && cursor.column <= current_indent.len
10128                    && current_indent.len <= suggested_indent.len
10129                {
10130                    selection.start = Point::new(cursor.row, suggested_indent.len);
10131                    selection.end = selection.start;
10132                    if row_delta == 0 {
10133                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10134                            cursor.row,
10135                            current_indent,
10136                            suggested_indent,
10137                        ));
10138                        row_delta = suggested_indent.len - current_indent.len;
10139                    }
10140                    continue;
10141                }
10142
10143                // If current indent is more than suggested indent
10144                // only move cursor to current indent and skip indent
10145                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10146                    selection.start = Point::new(cursor.row, current_indent.len);
10147                    selection.end = selection.start;
10148                    continue;
10149                }
10150            }
10151
10152            // Otherwise, insert a hard or soft tab.
10153            let settings = buffer.language_settings_at(cursor, cx);
10154            let tab_size = if settings.hard_tabs {
10155                IndentSize::tab()
10156            } else {
10157                let tab_size = settings.tab_size.get();
10158                let indent_remainder = snapshot
10159                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10160                    .flat_map(str::chars)
10161                    .fold(row_delta % tab_size, |counter: u32, c| {
10162                        if c == '\t' {
10163                            0
10164                        } else {
10165                            (counter + 1) % tab_size
10166                        }
10167                    });
10168
10169                let chars_to_next_tab_stop = tab_size - indent_remainder;
10170                IndentSize::spaces(chars_to_next_tab_stop)
10171            };
10172            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10173            selection.end = selection.start;
10174            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10175            row_delta += tab_size.len;
10176        }
10177
10178        self.transact(window, cx, |this, window, cx| {
10179            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10180            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10181            this.refresh_edit_prediction(true, false, window, cx);
10182        });
10183    }
10184
10185    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10186        if self.read_only(cx) {
10187            return;
10188        }
10189        if self.mode.is_single_line() {
10190            cx.propagate();
10191            return;
10192        }
10193
10194        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10195        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10196        let mut prev_edited_row = 0;
10197        let mut row_delta = 0;
10198        let mut edits = Vec::new();
10199        let buffer = self.buffer.read(cx);
10200        let snapshot = buffer.snapshot(cx);
10201        for selection in &mut selections {
10202            if selection.start.row != prev_edited_row {
10203                row_delta = 0;
10204            }
10205            prev_edited_row = selection.end.row;
10206
10207            row_delta =
10208                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10209        }
10210
10211        self.transact(window, cx, |this, window, cx| {
10212            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10213            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10214        });
10215    }
10216
10217    fn indent_selection(
10218        buffer: &MultiBuffer,
10219        snapshot: &MultiBufferSnapshot,
10220        selection: &mut Selection<Point>,
10221        edits: &mut Vec<(Range<Point>, String)>,
10222        delta_for_start_row: u32,
10223        cx: &App,
10224    ) -> u32 {
10225        let settings = buffer.language_settings_at(selection.start, cx);
10226        let tab_size = settings.tab_size.get();
10227        let indent_kind = if settings.hard_tabs {
10228            IndentKind::Tab
10229        } else {
10230            IndentKind::Space
10231        };
10232        let mut start_row = selection.start.row;
10233        let mut end_row = selection.end.row + 1;
10234
10235        // If a selection ends at the beginning of a line, don't indent
10236        // that last line.
10237        if selection.end.column == 0 && selection.end.row > selection.start.row {
10238            end_row -= 1;
10239        }
10240
10241        // Avoid re-indenting a row that has already been indented by a
10242        // previous selection, but still update this selection's column
10243        // to reflect that indentation.
10244        if delta_for_start_row > 0 {
10245            start_row += 1;
10246            selection.start.column += delta_for_start_row;
10247            if selection.end.row == selection.start.row {
10248                selection.end.column += delta_for_start_row;
10249            }
10250        }
10251
10252        let mut delta_for_end_row = 0;
10253        let has_multiple_rows = start_row + 1 != end_row;
10254        for row in start_row..end_row {
10255            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10256            let indent_delta = match (current_indent.kind, indent_kind) {
10257                (IndentKind::Space, IndentKind::Space) => {
10258                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10259                    IndentSize::spaces(columns_to_next_tab_stop)
10260                }
10261                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10262                (_, IndentKind::Tab) => IndentSize::tab(),
10263            };
10264
10265            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10266                0
10267            } else {
10268                selection.start.column
10269            };
10270            let row_start = Point::new(row, start);
10271            edits.push((
10272                row_start..row_start,
10273                indent_delta.chars().collect::<String>(),
10274            ));
10275
10276            // Update this selection's endpoints to reflect the indentation.
10277            if row == selection.start.row {
10278                selection.start.column += indent_delta.len;
10279            }
10280            if row == selection.end.row {
10281                selection.end.column += indent_delta.len;
10282                delta_for_end_row = indent_delta.len;
10283            }
10284        }
10285
10286        if selection.start.row == selection.end.row {
10287            delta_for_start_row + delta_for_end_row
10288        } else {
10289            delta_for_end_row
10290        }
10291    }
10292
10293    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10294        if self.read_only(cx) {
10295            return;
10296        }
10297        if self.mode.is_single_line() {
10298            cx.propagate();
10299            return;
10300        }
10301
10302        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10303        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10304        let selections = self.selections.all::<Point>(&display_map);
10305        let mut deletion_ranges = Vec::new();
10306        let mut last_outdent = None;
10307        {
10308            let buffer = self.buffer.read(cx);
10309            let snapshot = buffer.snapshot(cx);
10310            for selection in &selections {
10311                let settings = buffer.language_settings_at(selection.start, cx);
10312                let tab_size = settings.tab_size.get();
10313                let mut rows = selection.spanned_rows(false, &display_map);
10314
10315                // Avoid re-outdenting a row that has already been outdented by a
10316                // previous selection.
10317                if let Some(last_row) = last_outdent
10318                    && last_row == rows.start
10319                {
10320                    rows.start = rows.start.next_row();
10321                }
10322                let has_multiple_rows = rows.len() > 1;
10323                for row in rows.iter_rows() {
10324                    let indent_size = snapshot.indent_size_for_line(row);
10325                    if indent_size.len > 0 {
10326                        let deletion_len = match indent_size.kind {
10327                            IndentKind::Space => {
10328                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10329                                if columns_to_prev_tab_stop == 0 {
10330                                    tab_size
10331                                } else {
10332                                    columns_to_prev_tab_stop
10333                                }
10334                            }
10335                            IndentKind::Tab => 1,
10336                        };
10337                        let start = if has_multiple_rows
10338                            || deletion_len > selection.start.column
10339                            || indent_size.len < selection.start.column
10340                        {
10341                            0
10342                        } else {
10343                            selection.start.column - deletion_len
10344                        };
10345                        deletion_ranges.push(
10346                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10347                        );
10348                        last_outdent = Some(row);
10349                    }
10350                }
10351            }
10352        }
10353
10354        self.transact(window, cx, |this, window, cx| {
10355            this.buffer.update(cx, |buffer, cx| {
10356                let empty_str: Arc<str> = Arc::default();
10357                buffer.edit(
10358                    deletion_ranges
10359                        .into_iter()
10360                        .map(|range| (range, empty_str.clone())),
10361                    None,
10362                    cx,
10363                );
10364            });
10365            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10366            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10367        });
10368    }
10369
10370    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10371        if self.read_only(cx) {
10372            return;
10373        }
10374        if self.mode.is_single_line() {
10375            cx.propagate();
10376            return;
10377        }
10378
10379        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10380        let selections = self
10381            .selections
10382            .all::<usize>(&self.display_snapshot(cx))
10383            .into_iter()
10384            .map(|s| s.range());
10385
10386        self.transact(window, cx, |this, window, cx| {
10387            this.buffer.update(cx, |buffer, cx| {
10388                buffer.autoindent_ranges(selections, cx);
10389            });
10390            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10391            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10392        });
10393    }
10394
10395    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10396        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10397        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10398        let selections = self.selections.all::<Point>(&display_map);
10399
10400        let mut new_cursors = Vec::new();
10401        let mut edit_ranges = Vec::new();
10402        let mut selections = selections.iter().peekable();
10403        while let Some(selection) = selections.next() {
10404            let mut rows = selection.spanned_rows(false, &display_map);
10405
10406            // Accumulate contiguous regions of rows that we want to delete.
10407            while let Some(next_selection) = selections.peek() {
10408                let next_rows = next_selection.spanned_rows(false, &display_map);
10409                if next_rows.start <= rows.end {
10410                    rows.end = next_rows.end;
10411                    selections.next().unwrap();
10412                } else {
10413                    break;
10414                }
10415            }
10416
10417            let buffer = display_map.buffer_snapshot();
10418            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10419            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10420                // If there's a line after the range, delete the \n from the end of the row range
10421                (
10422                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10423                    rows.end,
10424                )
10425            } else {
10426                // If there isn't a line after the range, delete the \n from the line before the
10427                // start of the row range
10428                edit_start = edit_start.saturating_sub(1);
10429                (buffer.len(), rows.start.previous_row())
10430            };
10431
10432            let text_layout_details = self.text_layout_details(window);
10433            let x = display_map.x_for_display_point(
10434                selection.head().to_display_point(&display_map),
10435                &text_layout_details,
10436            );
10437            let row = Point::new(target_row.0, 0)
10438                .to_display_point(&display_map)
10439                .row();
10440            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10441
10442            new_cursors.push((
10443                selection.id,
10444                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10445                SelectionGoal::None,
10446            ));
10447            edit_ranges.push(edit_start..edit_end);
10448        }
10449
10450        self.transact(window, cx, |this, window, cx| {
10451            let buffer = this.buffer.update(cx, |buffer, cx| {
10452                let empty_str: Arc<str> = Arc::default();
10453                buffer.edit(
10454                    edit_ranges
10455                        .into_iter()
10456                        .map(|range| (range, empty_str.clone())),
10457                    None,
10458                    cx,
10459                );
10460                buffer.snapshot(cx)
10461            });
10462            let new_selections = new_cursors
10463                .into_iter()
10464                .map(|(id, cursor, goal)| {
10465                    let cursor = cursor.to_point(&buffer);
10466                    Selection {
10467                        id,
10468                        start: cursor,
10469                        end: cursor,
10470                        reversed: false,
10471                        goal,
10472                    }
10473                })
10474                .collect();
10475
10476            this.change_selections(Default::default(), window, cx, |s| {
10477                s.select(new_selections);
10478            });
10479        });
10480    }
10481
10482    pub fn join_lines_impl(
10483        &mut self,
10484        insert_whitespace: bool,
10485        window: &mut Window,
10486        cx: &mut Context<Self>,
10487    ) {
10488        if self.read_only(cx) {
10489            return;
10490        }
10491        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10492        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10493            let start = MultiBufferRow(selection.start.row);
10494            // Treat single line selections as if they include the next line. Otherwise this action
10495            // would do nothing for single line selections individual cursors.
10496            let end = if selection.start.row == selection.end.row {
10497                MultiBufferRow(selection.start.row + 1)
10498            } else {
10499                MultiBufferRow(selection.end.row)
10500            };
10501
10502            if let Some(last_row_range) = row_ranges.last_mut()
10503                && start <= last_row_range.end
10504            {
10505                last_row_range.end = end;
10506                continue;
10507            }
10508            row_ranges.push(start..end);
10509        }
10510
10511        let snapshot = self.buffer.read(cx).snapshot(cx);
10512        let mut cursor_positions = Vec::new();
10513        for row_range in &row_ranges {
10514            let anchor = snapshot.anchor_before(Point::new(
10515                row_range.end.previous_row().0,
10516                snapshot.line_len(row_range.end.previous_row()),
10517            ));
10518            cursor_positions.push(anchor..anchor);
10519        }
10520
10521        self.transact(window, cx, |this, window, cx| {
10522            for row_range in row_ranges.into_iter().rev() {
10523                for row in row_range.iter_rows().rev() {
10524                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10525                    let next_line_row = row.next_row();
10526                    let indent = snapshot.indent_size_for_line(next_line_row);
10527                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10528
10529                    let replace =
10530                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10531                            " "
10532                        } else {
10533                            ""
10534                        };
10535
10536                    this.buffer.update(cx, |buffer, cx| {
10537                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10538                    });
10539                }
10540            }
10541
10542            this.change_selections(Default::default(), window, cx, |s| {
10543                s.select_anchor_ranges(cursor_positions)
10544            });
10545        });
10546    }
10547
10548    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10549        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10550        self.join_lines_impl(true, window, cx);
10551    }
10552
10553    pub fn sort_lines_case_sensitive(
10554        &mut self,
10555        _: &SortLinesCaseSensitive,
10556        window: &mut Window,
10557        cx: &mut Context<Self>,
10558    ) {
10559        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10560    }
10561
10562    pub fn sort_lines_by_length(
10563        &mut self,
10564        _: &SortLinesByLength,
10565        window: &mut Window,
10566        cx: &mut Context<Self>,
10567    ) {
10568        self.manipulate_immutable_lines(window, cx, |lines| {
10569            lines.sort_by_key(|&line| line.chars().count())
10570        })
10571    }
10572
10573    pub fn sort_lines_case_insensitive(
10574        &mut self,
10575        _: &SortLinesCaseInsensitive,
10576        window: &mut Window,
10577        cx: &mut Context<Self>,
10578    ) {
10579        self.manipulate_immutable_lines(window, cx, |lines| {
10580            lines.sort_by_key(|line| line.to_lowercase())
10581        })
10582    }
10583
10584    pub fn unique_lines_case_insensitive(
10585        &mut self,
10586        _: &UniqueLinesCaseInsensitive,
10587        window: &mut Window,
10588        cx: &mut Context<Self>,
10589    ) {
10590        self.manipulate_immutable_lines(window, cx, |lines| {
10591            let mut seen = HashSet::default();
10592            lines.retain(|line| seen.insert(line.to_lowercase()));
10593        })
10594    }
10595
10596    pub fn unique_lines_case_sensitive(
10597        &mut self,
10598        _: &UniqueLinesCaseSensitive,
10599        window: &mut Window,
10600        cx: &mut Context<Self>,
10601    ) {
10602        self.manipulate_immutable_lines(window, cx, |lines| {
10603            let mut seen = HashSet::default();
10604            lines.retain(|line| seen.insert(*line));
10605        })
10606    }
10607
10608    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10609        let snapshot = self.buffer.read(cx).snapshot(cx);
10610        for selection in self.selections.disjoint_anchors_arc().iter() {
10611            if snapshot
10612                .language_at(selection.start)
10613                .and_then(|lang| lang.config().wrap_characters.as_ref())
10614                .is_some()
10615            {
10616                return true;
10617            }
10618        }
10619        false
10620    }
10621
10622    fn wrap_selections_in_tag(
10623        &mut self,
10624        _: &WrapSelectionsInTag,
10625        window: &mut Window,
10626        cx: &mut Context<Self>,
10627    ) {
10628        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10629
10630        let snapshot = self.buffer.read(cx).snapshot(cx);
10631
10632        let mut edits = Vec::new();
10633        let mut boundaries = Vec::new();
10634
10635        for selection in self
10636            .selections
10637            .all_adjusted(&self.display_snapshot(cx))
10638            .iter()
10639        {
10640            let Some(wrap_config) = snapshot
10641                .language_at(selection.start)
10642                .and_then(|lang| lang.config().wrap_characters.clone())
10643            else {
10644                continue;
10645            };
10646
10647            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10648            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10649
10650            let start_before = snapshot.anchor_before(selection.start);
10651            let end_after = snapshot.anchor_after(selection.end);
10652
10653            edits.push((start_before..start_before, open_tag));
10654            edits.push((end_after..end_after, close_tag));
10655
10656            boundaries.push((
10657                start_before,
10658                end_after,
10659                wrap_config.start_prefix.len(),
10660                wrap_config.end_suffix.len(),
10661            ));
10662        }
10663
10664        if edits.is_empty() {
10665            return;
10666        }
10667
10668        self.transact(window, cx, |this, window, cx| {
10669            let buffer = this.buffer.update(cx, |buffer, cx| {
10670                buffer.edit(edits, None, cx);
10671                buffer.snapshot(cx)
10672            });
10673
10674            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10675            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10676                boundaries.into_iter()
10677            {
10678                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10679                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10680                new_selections.push(open_offset..open_offset);
10681                new_selections.push(close_offset..close_offset);
10682            }
10683
10684            this.change_selections(Default::default(), window, cx, |s| {
10685                s.select_ranges(new_selections);
10686            });
10687
10688            this.request_autoscroll(Autoscroll::fit(), cx);
10689        });
10690    }
10691
10692    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10693        let Some(project) = self.project.clone() else {
10694            return;
10695        };
10696        self.reload(project, window, cx)
10697            .detach_and_notify_err(window, cx);
10698    }
10699
10700    pub fn restore_file(
10701        &mut self,
10702        _: &::git::RestoreFile,
10703        window: &mut Window,
10704        cx: &mut Context<Self>,
10705    ) {
10706        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10707        let mut buffer_ids = HashSet::default();
10708        let snapshot = self.buffer().read(cx).snapshot(cx);
10709        for selection in self.selections.all::<usize>(&self.display_snapshot(cx)) {
10710            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10711        }
10712
10713        let buffer = self.buffer().read(cx);
10714        let ranges = buffer_ids
10715            .into_iter()
10716            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10717            .collect::<Vec<_>>();
10718
10719        self.restore_hunks_in_ranges(ranges, window, cx);
10720    }
10721
10722    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10723        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10724        let selections = self
10725            .selections
10726            .all(&self.display_snapshot(cx))
10727            .into_iter()
10728            .map(|s| s.range())
10729            .collect();
10730        self.restore_hunks_in_ranges(selections, window, cx);
10731    }
10732
10733    pub fn restore_hunks_in_ranges(
10734        &mut self,
10735        ranges: Vec<Range<Point>>,
10736        window: &mut Window,
10737        cx: &mut Context<Editor>,
10738    ) {
10739        let mut revert_changes = HashMap::default();
10740        let chunk_by = self
10741            .snapshot(window, cx)
10742            .hunks_for_ranges(ranges)
10743            .into_iter()
10744            .chunk_by(|hunk| hunk.buffer_id);
10745        for (buffer_id, hunks) in &chunk_by {
10746            let hunks = hunks.collect::<Vec<_>>();
10747            for hunk in &hunks {
10748                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10749            }
10750            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10751        }
10752        drop(chunk_by);
10753        if !revert_changes.is_empty() {
10754            self.transact(window, cx, |editor, window, cx| {
10755                editor.restore(revert_changes, window, cx);
10756            });
10757        }
10758    }
10759
10760    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
10761        if let Some(status) = self
10762            .addons
10763            .iter()
10764            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
10765        {
10766            return Some(status);
10767        }
10768        self.project
10769            .as_ref()?
10770            .read(cx)
10771            .status_for_buffer_id(buffer_id, cx)
10772    }
10773
10774    pub fn open_active_item_in_terminal(
10775        &mut self,
10776        _: &OpenInTerminal,
10777        window: &mut Window,
10778        cx: &mut Context<Self>,
10779    ) {
10780        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10781            let project_path = buffer.read(cx).project_path(cx)?;
10782            let project = self.project()?.read(cx);
10783            let entry = project.entry_for_path(&project_path, cx)?;
10784            let parent = match &entry.canonical_path {
10785                Some(canonical_path) => canonical_path.to_path_buf(),
10786                None => project.absolute_path(&project_path, cx)?,
10787            }
10788            .parent()?
10789            .to_path_buf();
10790            Some(parent)
10791        }) {
10792            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10793        }
10794    }
10795
10796    fn set_breakpoint_context_menu(
10797        &mut self,
10798        display_row: DisplayRow,
10799        position: Option<Anchor>,
10800        clicked_point: gpui::Point<Pixels>,
10801        window: &mut Window,
10802        cx: &mut Context<Self>,
10803    ) {
10804        let source = self
10805            .buffer
10806            .read(cx)
10807            .snapshot(cx)
10808            .anchor_before(Point::new(display_row.0, 0u32));
10809
10810        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10811
10812        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10813            self,
10814            source,
10815            clicked_point,
10816            context_menu,
10817            window,
10818            cx,
10819        );
10820    }
10821
10822    fn add_edit_breakpoint_block(
10823        &mut self,
10824        anchor: Anchor,
10825        breakpoint: &Breakpoint,
10826        edit_action: BreakpointPromptEditAction,
10827        window: &mut Window,
10828        cx: &mut Context<Self>,
10829    ) {
10830        let weak_editor = cx.weak_entity();
10831        let bp_prompt = cx.new(|cx| {
10832            BreakpointPromptEditor::new(
10833                weak_editor,
10834                anchor,
10835                breakpoint.clone(),
10836                edit_action,
10837                window,
10838                cx,
10839            )
10840        });
10841
10842        let height = bp_prompt.update(cx, |this, cx| {
10843            this.prompt
10844                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10845        });
10846        let cloned_prompt = bp_prompt.clone();
10847        let blocks = vec![BlockProperties {
10848            style: BlockStyle::Sticky,
10849            placement: BlockPlacement::Above(anchor),
10850            height: Some(height),
10851            render: Arc::new(move |cx| {
10852                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10853                cloned_prompt.clone().into_any_element()
10854            }),
10855            priority: 0,
10856        }];
10857
10858        let focus_handle = bp_prompt.focus_handle(cx);
10859        window.focus(&focus_handle);
10860
10861        let block_ids = self.insert_blocks(blocks, None, cx);
10862        bp_prompt.update(cx, |prompt, _| {
10863            prompt.add_block_ids(block_ids);
10864        });
10865    }
10866
10867    pub(crate) fn breakpoint_at_row(
10868        &self,
10869        row: u32,
10870        window: &mut Window,
10871        cx: &mut Context<Self>,
10872    ) -> Option<(Anchor, Breakpoint)> {
10873        let snapshot = self.snapshot(window, cx);
10874        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
10875
10876        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10877    }
10878
10879    pub(crate) fn breakpoint_at_anchor(
10880        &self,
10881        breakpoint_position: Anchor,
10882        snapshot: &EditorSnapshot,
10883        cx: &mut Context<Self>,
10884    ) -> Option<(Anchor, Breakpoint)> {
10885        let buffer = self
10886            .buffer
10887            .read(cx)
10888            .buffer_for_anchor(breakpoint_position, cx)?;
10889
10890        let enclosing_excerpt = breakpoint_position.excerpt_id;
10891        let buffer_snapshot = buffer.read(cx).snapshot();
10892
10893        let row = buffer_snapshot
10894            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10895            .row;
10896
10897        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
10898        let anchor_end = snapshot
10899            .buffer_snapshot()
10900            .anchor_after(Point::new(row, line_len));
10901
10902        self.breakpoint_store
10903            .as_ref()?
10904            .read_with(cx, |breakpoint_store, cx| {
10905                breakpoint_store
10906                    .breakpoints(
10907                        &buffer,
10908                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10909                        &buffer_snapshot,
10910                        cx,
10911                    )
10912                    .next()
10913                    .and_then(|(bp, _)| {
10914                        let breakpoint_row = buffer_snapshot
10915                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10916                            .row;
10917
10918                        if breakpoint_row == row {
10919                            snapshot
10920                                .buffer_snapshot()
10921                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10922                                .map(|position| (position, bp.bp.clone()))
10923                        } else {
10924                            None
10925                        }
10926                    })
10927            })
10928    }
10929
10930    pub fn edit_log_breakpoint(
10931        &mut self,
10932        _: &EditLogBreakpoint,
10933        window: &mut Window,
10934        cx: &mut Context<Self>,
10935    ) {
10936        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10937            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10938                message: None,
10939                state: BreakpointState::Enabled,
10940                condition: None,
10941                hit_condition: None,
10942            });
10943
10944            self.add_edit_breakpoint_block(
10945                anchor,
10946                &breakpoint,
10947                BreakpointPromptEditAction::Log,
10948                window,
10949                cx,
10950            );
10951        }
10952    }
10953
10954    fn breakpoints_at_cursors(
10955        &self,
10956        window: &mut Window,
10957        cx: &mut Context<Self>,
10958    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10959        let snapshot = self.snapshot(window, cx);
10960        let cursors = self
10961            .selections
10962            .disjoint_anchors_arc()
10963            .iter()
10964            .map(|selection| {
10965                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
10966
10967                let breakpoint_position = self
10968                    .breakpoint_at_row(cursor_position.row, window, cx)
10969                    .map(|bp| bp.0)
10970                    .unwrap_or_else(|| {
10971                        snapshot
10972                            .display_snapshot
10973                            .buffer_snapshot()
10974                            .anchor_after(Point::new(cursor_position.row, 0))
10975                    });
10976
10977                let breakpoint = self
10978                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10979                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10980
10981                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10982            })
10983            // 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.
10984            .collect::<HashMap<Anchor, _>>();
10985
10986        cursors.into_iter().collect()
10987    }
10988
10989    pub fn enable_breakpoint(
10990        &mut self,
10991        _: &crate::actions::EnableBreakpoint,
10992        window: &mut Window,
10993        cx: &mut Context<Self>,
10994    ) {
10995        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10996            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10997                continue;
10998            };
10999            self.edit_breakpoint_at_anchor(
11000                anchor,
11001                breakpoint,
11002                BreakpointEditAction::InvertState,
11003                cx,
11004            );
11005        }
11006    }
11007
11008    pub fn disable_breakpoint(
11009        &mut self,
11010        _: &crate::actions::DisableBreakpoint,
11011        window: &mut Window,
11012        cx: &mut Context<Self>,
11013    ) {
11014        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11015            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11016                continue;
11017            };
11018            self.edit_breakpoint_at_anchor(
11019                anchor,
11020                breakpoint,
11021                BreakpointEditAction::InvertState,
11022                cx,
11023            );
11024        }
11025    }
11026
11027    pub fn toggle_breakpoint(
11028        &mut self,
11029        _: &crate::actions::ToggleBreakpoint,
11030        window: &mut Window,
11031        cx: &mut Context<Self>,
11032    ) {
11033        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11034            if let Some(breakpoint) = breakpoint {
11035                self.edit_breakpoint_at_anchor(
11036                    anchor,
11037                    breakpoint,
11038                    BreakpointEditAction::Toggle,
11039                    cx,
11040                );
11041            } else {
11042                self.edit_breakpoint_at_anchor(
11043                    anchor,
11044                    Breakpoint::new_standard(),
11045                    BreakpointEditAction::Toggle,
11046                    cx,
11047                );
11048            }
11049        }
11050    }
11051
11052    pub fn edit_breakpoint_at_anchor(
11053        &mut self,
11054        breakpoint_position: Anchor,
11055        breakpoint: Breakpoint,
11056        edit_action: BreakpointEditAction,
11057        cx: &mut Context<Self>,
11058    ) {
11059        let Some(breakpoint_store) = &self.breakpoint_store else {
11060            return;
11061        };
11062
11063        let Some(buffer) = self
11064            .buffer
11065            .read(cx)
11066            .buffer_for_anchor(breakpoint_position, cx)
11067        else {
11068            return;
11069        };
11070
11071        breakpoint_store.update(cx, |breakpoint_store, cx| {
11072            breakpoint_store.toggle_breakpoint(
11073                buffer,
11074                BreakpointWithPosition {
11075                    position: breakpoint_position.text_anchor,
11076                    bp: breakpoint,
11077                },
11078                edit_action,
11079                cx,
11080            );
11081        });
11082
11083        cx.notify();
11084    }
11085
11086    #[cfg(any(test, feature = "test-support"))]
11087    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11088        self.breakpoint_store.clone()
11089    }
11090
11091    pub fn prepare_restore_change(
11092        &self,
11093        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11094        hunk: &MultiBufferDiffHunk,
11095        cx: &mut App,
11096    ) -> Option<()> {
11097        if hunk.is_created_file() {
11098            return None;
11099        }
11100        let buffer = self.buffer.read(cx);
11101        let diff = buffer.diff_for(hunk.buffer_id)?;
11102        let buffer = buffer.buffer(hunk.buffer_id)?;
11103        let buffer = buffer.read(cx);
11104        let original_text = diff
11105            .read(cx)
11106            .base_text()
11107            .as_rope()
11108            .slice(hunk.diff_base_byte_range.clone());
11109        let buffer_snapshot = buffer.snapshot();
11110        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11111        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11112            probe
11113                .0
11114                .start
11115                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11116                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11117        }) {
11118            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11119            Some(())
11120        } else {
11121            None
11122        }
11123    }
11124
11125    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11126        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11127    }
11128
11129    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11130        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11131    }
11132
11133    fn manipulate_lines<M>(
11134        &mut self,
11135        window: &mut Window,
11136        cx: &mut Context<Self>,
11137        mut manipulate: M,
11138    ) where
11139        M: FnMut(&str) -> LineManipulationResult,
11140    {
11141        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11142
11143        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11144        let buffer = self.buffer.read(cx).snapshot(cx);
11145
11146        let mut edits = Vec::new();
11147
11148        let selections = self.selections.all::<Point>(&display_map);
11149        let mut selections = selections.iter().peekable();
11150        let mut contiguous_row_selections = Vec::new();
11151        let mut new_selections = Vec::new();
11152        let mut added_lines = 0;
11153        let mut removed_lines = 0;
11154
11155        while let Some(selection) = selections.next() {
11156            let (start_row, end_row) = consume_contiguous_rows(
11157                &mut contiguous_row_selections,
11158                selection,
11159                &display_map,
11160                &mut selections,
11161            );
11162
11163            let start_point = Point::new(start_row.0, 0);
11164            let end_point = Point::new(
11165                end_row.previous_row().0,
11166                buffer.line_len(end_row.previous_row()),
11167            );
11168            let text = buffer
11169                .text_for_range(start_point..end_point)
11170                .collect::<String>();
11171
11172            let LineManipulationResult {
11173                new_text,
11174                line_count_before,
11175                line_count_after,
11176            } = manipulate(&text);
11177
11178            edits.push((start_point..end_point, new_text));
11179
11180            // Selections must change based on added and removed line count
11181            let start_row =
11182                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11183            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11184            new_selections.push(Selection {
11185                id: selection.id,
11186                start: start_row,
11187                end: end_row,
11188                goal: SelectionGoal::None,
11189                reversed: selection.reversed,
11190            });
11191
11192            if line_count_after > line_count_before {
11193                added_lines += line_count_after - line_count_before;
11194            } else if line_count_before > line_count_after {
11195                removed_lines += line_count_before - line_count_after;
11196            }
11197        }
11198
11199        self.transact(window, cx, |this, window, cx| {
11200            let buffer = this.buffer.update(cx, |buffer, cx| {
11201                buffer.edit(edits, None, cx);
11202                buffer.snapshot(cx)
11203            });
11204
11205            // Recalculate offsets on newly edited buffer
11206            let new_selections = new_selections
11207                .iter()
11208                .map(|s| {
11209                    let start_point = Point::new(s.start.0, 0);
11210                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11211                    Selection {
11212                        id: s.id,
11213                        start: buffer.point_to_offset(start_point),
11214                        end: buffer.point_to_offset(end_point),
11215                        goal: s.goal,
11216                        reversed: s.reversed,
11217                    }
11218                })
11219                .collect();
11220
11221            this.change_selections(Default::default(), window, cx, |s| {
11222                s.select(new_selections);
11223            });
11224
11225            this.request_autoscroll(Autoscroll::fit(), cx);
11226        });
11227    }
11228
11229    fn manipulate_immutable_lines<Fn>(
11230        &mut self,
11231        window: &mut Window,
11232        cx: &mut Context<Self>,
11233        mut callback: Fn,
11234    ) where
11235        Fn: FnMut(&mut Vec<&str>),
11236    {
11237        self.manipulate_lines(window, cx, |text| {
11238            let mut lines: Vec<&str> = text.split('\n').collect();
11239            let line_count_before = lines.len();
11240
11241            callback(&mut lines);
11242
11243            LineManipulationResult {
11244                new_text: lines.join("\n"),
11245                line_count_before,
11246                line_count_after: lines.len(),
11247            }
11248        });
11249    }
11250
11251    fn manipulate_mutable_lines<Fn>(
11252        &mut self,
11253        window: &mut Window,
11254        cx: &mut Context<Self>,
11255        mut callback: Fn,
11256    ) where
11257        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11258    {
11259        self.manipulate_lines(window, cx, |text| {
11260            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11261            let line_count_before = lines.len();
11262
11263            callback(&mut lines);
11264
11265            LineManipulationResult {
11266                new_text: lines.join("\n"),
11267                line_count_before,
11268                line_count_after: lines.len(),
11269            }
11270        });
11271    }
11272
11273    pub fn convert_indentation_to_spaces(
11274        &mut self,
11275        _: &ConvertIndentationToSpaces,
11276        window: &mut Window,
11277        cx: &mut Context<Self>,
11278    ) {
11279        let settings = self.buffer.read(cx).language_settings(cx);
11280        let tab_size = settings.tab_size.get() as usize;
11281
11282        self.manipulate_mutable_lines(window, cx, |lines| {
11283            // Allocates a reasonably sized scratch buffer once for the whole loop
11284            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11285            // Avoids recomputing spaces that could be inserted many times
11286            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11287                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11288                .collect();
11289
11290            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11291                let mut chars = line.as_ref().chars();
11292                let mut col = 0;
11293                let mut changed = false;
11294
11295                for ch in chars.by_ref() {
11296                    match ch {
11297                        ' ' => {
11298                            reindented_line.push(' ');
11299                            col += 1;
11300                        }
11301                        '\t' => {
11302                            // \t are converted to spaces depending on the current column
11303                            let spaces_len = tab_size - (col % tab_size);
11304                            reindented_line.extend(&space_cache[spaces_len - 1]);
11305                            col += spaces_len;
11306                            changed = true;
11307                        }
11308                        _ => {
11309                            // If we dont append before break, the character is consumed
11310                            reindented_line.push(ch);
11311                            break;
11312                        }
11313                    }
11314                }
11315
11316                if !changed {
11317                    reindented_line.clear();
11318                    continue;
11319                }
11320                // Append the rest of the line and replace old reference with new one
11321                reindented_line.extend(chars);
11322                *line = Cow::Owned(reindented_line.clone());
11323                reindented_line.clear();
11324            }
11325        });
11326    }
11327
11328    pub fn convert_indentation_to_tabs(
11329        &mut self,
11330        _: &ConvertIndentationToTabs,
11331        window: &mut Window,
11332        cx: &mut Context<Self>,
11333    ) {
11334        let settings = self.buffer.read(cx).language_settings(cx);
11335        let tab_size = settings.tab_size.get() as usize;
11336
11337        self.manipulate_mutable_lines(window, cx, |lines| {
11338            // Allocates a reasonably sized buffer once for the whole loop
11339            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11340            // Avoids recomputing spaces that could be inserted many times
11341            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11342                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11343                .collect();
11344
11345            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11346                let mut chars = line.chars();
11347                let mut spaces_count = 0;
11348                let mut first_non_indent_char = None;
11349                let mut changed = false;
11350
11351                for ch in chars.by_ref() {
11352                    match ch {
11353                        ' ' => {
11354                            // Keep track of spaces. Append \t when we reach tab_size
11355                            spaces_count += 1;
11356                            changed = true;
11357                            if spaces_count == tab_size {
11358                                reindented_line.push('\t');
11359                                spaces_count = 0;
11360                            }
11361                        }
11362                        '\t' => {
11363                            reindented_line.push('\t');
11364                            spaces_count = 0;
11365                        }
11366                        _ => {
11367                            // Dont append it yet, we might have remaining spaces
11368                            first_non_indent_char = Some(ch);
11369                            break;
11370                        }
11371                    }
11372                }
11373
11374                if !changed {
11375                    reindented_line.clear();
11376                    continue;
11377                }
11378                // Remaining spaces that didn't make a full tab stop
11379                if spaces_count > 0 {
11380                    reindented_line.extend(&space_cache[spaces_count - 1]);
11381                }
11382                // If we consume an extra character that was not indentation, add it back
11383                if let Some(extra_char) = first_non_indent_char {
11384                    reindented_line.push(extra_char);
11385                }
11386                // Append the rest of the line and replace old reference with new one
11387                reindented_line.extend(chars);
11388                *line = Cow::Owned(reindented_line.clone());
11389                reindented_line.clear();
11390            }
11391        });
11392    }
11393
11394    pub fn convert_to_upper_case(
11395        &mut self,
11396        _: &ConvertToUpperCase,
11397        window: &mut Window,
11398        cx: &mut Context<Self>,
11399    ) {
11400        self.manipulate_text(window, cx, |text| text.to_uppercase())
11401    }
11402
11403    pub fn convert_to_lower_case(
11404        &mut self,
11405        _: &ConvertToLowerCase,
11406        window: &mut Window,
11407        cx: &mut Context<Self>,
11408    ) {
11409        self.manipulate_text(window, cx, |text| text.to_lowercase())
11410    }
11411
11412    pub fn convert_to_title_case(
11413        &mut self,
11414        _: &ConvertToTitleCase,
11415        window: &mut Window,
11416        cx: &mut Context<Self>,
11417    ) {
11418        self.manipulate_text(window, cx, |text| {
11419            text.split('\n')
11420                .map(|line| line.to_case(Case::Title))
11421                .join("\n")
11422        })
11423    }
11424
11425    pub fn convert_to_snake_case(
11426        &mut self,
11427        _: &ConvertToSnakeCase,
11428        window: &mut Window,
11429        cx: &mut Context<Self>,
11430    ) {
11431        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11432    }
11433
11434    pub fn convert_to_kebab_case(
11435        &mut self,
11436        _: &ConvertToKebabCase,
11437        window: &mut Window,
11438        cx: &mut Context<Self>,
11439    ) {
11440        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11441    }
11442
11443    pub fn convert_to_upper_camel_case(
11444        &mut self,
11445        _: &ConvertToUpperCamelCase,
11446        window: &mut Window,
11447        cx: &mut Context<Self>,
11448    ) {
11449        self.manipulate_text(window, cx, |text| {
11450            text.split('\n')
11451                .map(|line| line.to_case(Case::UpperCamel))
11452                .join("\n")
11453        })
11454    }
11455
11456    pub fn convert_to_lower_camel_case(
11457        &mut self,
11458        _: &ConvertToLowerCamelCase,
11459        window: &mut Window,
11460        cx: &mut Context<Self>,
11461    ) {
11462        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11463    }
11464
11465    pub fn convert_to_opposite_case(
11466        &mut self,
11467        _: &ConvertToOppositeCase,
11468        window: &mut Window,
11469        cx: &mut Context<Self>,
11470    ) {
11471        self.manipulate_text(window, cx, |text| {
11472            text.chars()
11473                .fold(String::with_capacity(text.len()), |mut t, c| {
11474                    if c.is_uppercase() {
11475                        t.extend(c.to_lowercase());
11476                    } else {
11477                        t.extend(c.to_uppercase());
11478                    }
11479                    t
11480                })
11481        })
11482    }
11483
11484    pub fn convert_to_sentence_case(
11485        &mut self,
11486        _: &ConvertToSentenceCase,
11487        window: &mut Window,
11488        cx: &mut Context<Self>,
11489    ) {
11490        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11491    }
11492
11493    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11494        self.manipulate_text(window, cx, |text| {
11495            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11496            if has_upper_case_characters {
11497                text.to_lowercase()
11498            } else {
11499                text.to_uppercase()
11500            }
11501        })
11502    }
11503
11504    pub fn convert_to_rot13(
11505        &mut self,
11506        _: &ConvertToRot13,
11507        window: &mut Window,
11508        cx: &mut Context<Self>,
11509    ) {
11510        self.manipulate_text(window, cx, |text| {
11511            text.chars()
11512                .map(|c| match c {
11513                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11514                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11515                    _ => c,
11516                })
11517                .collect()
11518        })
11519    }
11520
11521    pub fn convert_to_rot47(
11522        &mut self,
11523        _: &ConvertToRot47,
11524        window: &mut Window,
11525        cx: &mut Context<Self>,
11526    ) {
11527        self.manipulate_text(window, cx, |text| {
11528            text.chars()
11529                .map(|c| {
11530                    let code_point = c as u32;
11531                    if code_point >= 33 && code_point <= 126 {
11532                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11533                    }
11534                    c
11535                })
11536                .collect()
11537        })
11538    }
11539
11540    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11541    where
11542        Fn: FnMut(&str) -> String,
11543    {
11544        let buffer = self.buffer.read(cx).snapshot(cx);
11545
11546        let mut new_selections = Vec::new();
11547        let mut edits = Vec::new();
11548        let mut selection_adjustment = 0i32;
11549
11550        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
11551            let selection_is_empty = selection.is_empty();
11552
11553            let (start, end) = if selection_is_empty {
11554                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11555                (word_range.start, word_range.end)
11556            } else {
11557                (
11558                    buffer.point_to_offset(selection.start),
11559                    buffer.point_to_offset(selection.end),
11560                )
11561            };
11562
11563            let text = buffer.text_for_range(start..end).collect::<String>();
11564            let old_length = text.len() as i32;
11565            let text = callback(&text);
11566
11567            new_selections.push(Selection {
11568                start: (start as i32 - selection_adjustment) as usize,
11569                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11570                goal: SelectionGoal::None,
11571                id: selection.id,
11572                reversed: selection.reversed,
11573            });
11574
11575            selection_adjustment += old_length - text.len() as i32;
11576
11577            edits.push((start..end, text));
11578        }
11579
11580        self.transact(window, cx, |this, window, cx| {
11581            this.buffer.update(cx, |buffer, cx| {
11582                buffer.edit(edits, None, cx);
11583            });
11584
11585            this.change_selections(Default::default(), window, cx, |s| {
11586                s.select(new_selections);
11587            });
11588
11589            this.request_autoscroll(Autoscroll::fit(), cx);
11590        });
11591    }
11592
11593    pub fn move_selection_on_drop(
11594        &mut self,
11595        selection: &Selection<Anchor>,
11596        target: DisplayPoint,
11597        is_cut: bool,
11598        window: &mut Window,
11599        cx: &mut Context<Self>,
11600    ) {
11601        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11602        let buffer = display_map.buffer_snapshot();
11603        let mut edits = Vec::new();
11604        let insert_point = display_map
11605            .clip_point(target, Bias::Left)
11606            .to_point(&display_map);
11607        let text = buffer
11608            .text_for_range(selection.start..selection.end)
11609            .collect::<String>();
11610        if is_cut {
11611            edits.push(((selection.start..selection.end), String::new()));
11612        }
11613        let insert_anchor = buffer.anchor_before(insert_point);
11614        edits.push(((insert_anchor..insert_anchor), text));
11615        let last_edit_start = insert_anchor.bias_left(buffer);
11616        let last_edit_end = insert_anchor.bias_right(buffer);
11617        self.transact(window, cx, |this, window, cx| {
11618            this.buffer.update(cx, |buffer, cx| {
11619                buffer.edit(edits, None, cx);
11620            });
11621            this.change_selections(Default::default(), window, cx, |s| {
11622                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11623            });
11624        });
11625    }
11626
11627    pub fn clear_selection_drag_state(&mut self) {
11628        self.selection_drag_state = SelectionDragState::None;
11629    }
11630
11631    pub fn duplicate(
11632        &mut self,
11633        upwards: bool,
11634        whole_lines: bool,
11635        window: &mut Window,
11636        cx: &mut Context<Self>,
11637    ) {
11638        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11639
11640        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11641        let buffer = display_map.buffer_snapshot();
11642        let selections = self.selections.all::<Point>(&display_map);
11643
11644        let mut edits = Vec::new();
11645        let mut selections_iter = selections.iter().peekable();
11646        while let Some(selection) = selections_iter.next() {
11647            let mut rows = selection.spanned_rows(false, &display_map);
11648            // duplicate line-wise
11649            if whole_lines || selection.start == selection.end {
11650                // Avoid duplicating the same lines twice.
11651                while let Some(next_selection) = selections_iter.peek() {
11652                    let next_rows = next_selection.spanned_rows(false, &display_map);
11653                    if next_rows.start < rows.end {
11654                        rows.end = next_rows.end;
11655                        selections_iter.next().unwrap();
11656                    } else {
11657                        break;
11658                    }
11659                }
11660
11661                // Copy the text from the selected row region and splice it either at the start
11662                // or end of the region.
11663                let start = Point::new(rows.start.0, 0);
11664                let end = Point::new(
11665                    rows.end.previous_row().0,
11666                    buffer.line_len(rows.end.previous_row()),
11667                );
11668
11669                let mut text = buffer.text_for_range(start..end).collect::<String>();
11670
11671                let insert_location = if upwards {
11672                    // When duplicating upward, we need to insert before the current line.
11673                    // If we're on the last line and it doesn't end with a newline,
11674                    // we need to add a newline before the duplicated content.
11675                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11676                        && buffer.max_point().column > 0
11677                        && !text.ends_with('\n');
11678
11679                    if needs_leading_newline {
11680                        text.insert(0, '\n');
11681                        end
11682                    } else {
11683                        text.push('\n');
11684                        Point::new(rows.start.0, 0)
11685                    }
11686                } else {
11687                    text.push('\n');
11688                    start
11689                };
11690                edits.push((insert_location..insert_location, text));
11691            } else {
11692                // duplicate character-wise
11693                let start = selection.start;
11694                let end = selection.end;
11695                let text = buffer.text_for_range(start..end).collect::<String>();
11696                edits.push((selection.end..selection.end, text));
11697            }
11698        }
11699
11700        self.transact(window, cx, |this, window, cx| {
11701            this.buffer.update(cx, |buffer, cx| {
11702                buffer.edit(edits, None, cx);
11703            });
11704
11705            // When duplicating upward with whole lines, move the cursor to the duplicated line
11706            if upwards && whole_lines {
11707                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
11708
11709                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11710                    let mut new_ranges = Vec::new();
11711                    let selections = s.all::<Point>(&display_map);
11712                    let mut selections_iter = selections.iter().peekable();
11713
11714                    while let Some(first_selection) = selections_iter.next() {
11715                        // Group contiguous selections together to find the total row span
11716                        let mut group_selections = vec![first_selection];
11717                        let mut rows = first_selection.spanned_rows(false, &display_map);
11718
11719                        while let Some(next_selection) = selections_iter.peek() {
11720                            let next_rows = next_selection.spanned_rows(false, &display_map);
11721                            if next_rows.start < rows.end {
11722                                rows.end = next_rows.end;
11723                                group_selections.push(selections_iter.next().unwrap());
11724                            } else {
11725                                break;
11726                            }
11727                        }
11728
11729                        let row_count = rows.end.0 - rows.start.0;
11730
11731                        // Move all selections in this group up by the total number of duplicated rows
11732                        for selection in group_selections {
11733                            let new_start = Point::new(
11734                                selection.start.row.saturating_sub(row_count),
11735                                selection.start.column,
11736                            );
11737
11738                            let new_end = Point::new(
11739                                selection.end.row.saturating_sub(row_count),
11740                                selection.end.column,
11741                            );
11742
11743                            new_ranges.push(new_start..new_end);
11744                        }
11745                    }
11746
11747                    s.select_ranges(new_ranges);
11748                });
11749            }
11750
11751            this.request_autoscroll(Autoscroll::fit(), cx);
11752        });
11753    }
11754
11755    pub fn duplicate_line_up(
11756        &mut self,
11757        _: &DuplicateLineUp,
11758        window: &mut Window,
11759        cx: &mut Context<Self>,
11760    ) {
11761        self.duplicate(true, true, window, cx);
11762    }
11763
11764    pub fn duplicate_line_down(
11765        &mut self,
11766        _: &DuplicateLineDown,
11767        window: &mut Window,
11768        cx: &mut Context<Self>,
11769    ) {
11770        self.duplicate(false, true, window, cx);
11771    }
11772
11773    pub fn duplicate_selection(
11774        &mut self,
11775        _: &DuplicateSelection,
11776        window: &mut Window,
11777        cx: &mut Context<Self>,
11778    ) {
11779        self.duplicate(false, false, window, cx);
11780    }
11781
11782    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11783        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11784        if self.mode.is_single_line() {
11785            cx.propagate();
11786            return;
11787        }
11788
11789        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11790        let buffer = self.buffer.read(cx).snapshot(cx);
11791
11792        let mut edits = Vec::new();
11793        let mut unfold_ranges = Vec::new();
11794        let mut refold_creases = Vec::new();
11795
11796        let selections = self.selections.all::<Point>(&display_map);
11797        let mut selections = selections.iter().peekable();
11798        let mut contiguous_row_selections = Vec::new();
11799        let mut new_selections = Vec::new();
11800
11801        while let Some(selection) = selections.next() {
11802            // Find all the selections that span a contiguous row range
11803            let (start_row, end_row) = consume_contiguous_rows(
11804                &mut contiguous_row_selections,
11805                selection,
11806                &display_map,
11807                &mut selections,
11808            );
11809
11810            // Move the text spanned by the row range to be before the line preceding the row range
11811            if start_row.0 > 0 {
11812                let range_to_move = Point::new(
11813                    start_row.previous_row().0,
11814                    buffer.line_len(start_row.previous_row()),
11815                )
11816                    ..Point::new(
11817                        end_row.previous_row().0,
11818                        buffer.line_len(end_row.previous_row()),
11819                    );
11820                let insertion_point = display_map
11821                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11822                    .0;
11823
11824                // Don't move lines across excerpts
11825                if buffer
11826                    .excerpt_containing(insertion_point..range_to_move.end)
11827                    .is_some()
11828                {
11829                    let text = buffer
11830                        .text_for_range(range_to_move.clone())
11831                        .flat_map(|s| s.chars())
11832                        .skip(1)
11833                        .chain(['\n'])
11834                        .collect::<String>();
11835
11836                    edits.push((
11837                        buffer.anchor_after(range_to_move.start)
11838                            ..buffer.anchor_before(range_to_move.end),
11839                        String::new(),
11840                    ));
11841                    let insertion_anchor = buffer.anchor_after(insertion_point);
11842                    edits.push((insertion_anchor..insertion_anchor, text));
11843
11844                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11845
11846                    // Move selections up
11847                    new_selections.extend(contiguous_row_selections.drain(..).map(
11848                        |mut selection| {
11849                            selection.start.row -= row_delta;
11850                            selection.end.row -= row_delta;
11851                            selection
11852                        },
11853                    ));
11854
11855                    // Move folds up
11856                    unfold_ranges.push(range_to_move.clone());
11857                    for fold in display_map.folds_in_range(
11858                        buffer.anchor_before(range_to_move.start)
11859                            ..buffer.anchor_after(range_to_move.end),
11860                    ) {
11861                        let mut start = fold.range.start.to_point(&buffer);
11862                        let mut end = fold.range.end.to_point(&buffer);
11863                        start.row -= row_delta;
11864                        end.row -= row_delta;
11865                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11866                    }
11867                }
11868            }
11869
11870            // If we didn't move line(s), preserve the existing selections
11871            new_selections.append(&mut contiguous_row_selections);
11872        }
11873
11874        self.transact(window, cx, |this, window, cx| {
11875            this.unfold_ranges(&unfold_ranges, true, true, cx);
11876            this.buffer.update(cx, |buffer, cx| {
11877                for (range, text) in edits {
11878                    buffer.edit([(range, text)], None, cx);
11879                }
11880            });
11881            this.fold_creases(refold_creases, true, window, cx);
11882            this.change_selections(Default::default(), window, cx, |s| {
11883                s.select(new_selections);
11884            })
11885        });
11886    }
11887
11888    pub fn move_line_down(
11889        &mut self,
11890        _: &MoveLineDown,
11891        window: &mut Window,
11892        cx: &mut Context<Self>,
11893    ) {
11894        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11895        if self.mode.is_single_line() {
11896            cx.propagate();
11897            return;
11898        }
11899
11900        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11901        let buffer = self.buffer.read(cx).snapshot(cx);
11902
11903        let mut edits = Vec::new();
11904        let mut unfold_ranges = Vec::new();
11905        let mut refold_creases = Vec::new();
11906
11907        let selections = self.selections.all::<Point>(&display_map);
11908        let mut selections = selections.iter().peekable();
11909        let mut contiguous_row_selections = Vec::new();
11910        let mut new_selections = Vec::new();
11911
11912        while let Some(selection) = selections.next() {
11913            // Find all the selections that span a contiguous row range
11914            let (start_row, end_row) = consume_contiguous_rows(
11915                &mut contiguous_row_selections,
11916                selection,
11917                &display_map,
11918                &mut selections,
11919            );
11920
11921            // Move the text spanned by the row range to be after the last line of the row range
11922            if end_row.0 <= buffer.max_point().row {
11923                let range_to_move =
11924                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11925                let insertion_point = display_map
11926                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11927                    .0;
11928
11929                // Don't move lines across excerpt boundaries
11930                if buffer
11931                    .excerpt_containing(range_to_move.start..insertion_point)
11932                    .is_some()
11933                {
11934                    let mut text = String::from("\n");
11935                    text.extend(buffer.text_for_range(range_to_move.clone()));
11936                    text.pop(); // Drop trailing newline
11937                    edits.push((
11938                        buffer.anchor_after(range_to_move.start)
11939                            ..buffer.anchor_before(range_to_move.end),
11940                        String::new(),
11941                    ));
11942                    let insertion_anchor = buffer.anchor_after(insertion_point);
11943                    edits.push((insertion_anchor..insertion_anchor, text));
11944
11945                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11946
11947                    // Move selections down
11948                    new_selections.extend(contiguous_row_selections.drain(..).map(
11949                        |mut selection| {
11950                            selection.start.row += row_delta;
11951                            selection.end.row += row_delta;
11952                            selection
11953                        },
11954                    ));
11955
11956                    // Move folds down
11957                    unfold_ranges.push(range_to_move.clone());
11958                    for fold in display_map.folds_in_range(
11959                        buffer.anchor_before(range_to_move.start)
11960                            ..buffer.anchor_after(range_to_move.end),
11961                    ) {
11962                        let mut start = fold.range.start.to_point(&buffer);
11963                        let mut end = fold.range.end.to_point(&buffer);
11964                        start.row += row_delta;
11965                        end.row += row_delta;
11966                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11967                    }
11968                }
11969            }
11970
11971            // If we didn't move line(s), preserve the existing selections
11972            new_selections.append(&mut contiguous_row_selections);
11973        }
11974
11975        self.transact(window, cx, |this, window, cx| {
11976            this.unfold_ranges(&unfold_ranges, true, true, cx);
11977            this.buffer.update(cx, |buffer, cx| {
11978                for (range, text) in edits {
11979                    buffer.edit([(range, text)], None, cx);
11980                }
11981            });
11982            this.fold_creases(refold_creases, true, window, cx);
11983            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11984        });
11985    }
11986
11987    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11988        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11989        let text_layout_details = &self.text_layout_details(window);
11990        self.transact(window, cx, |this, window, cx| {
11991            let edits = this.change_selections(Default::default(), window, cx, |s| {
11992                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11993                s.move_with(|display_map, selection| {
11994                    if !selection.is_empty() {
11995                        return;
11996                    }
11997
11998                    let mut head = selection.head();
11999                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12000                    if head.column() == display_map.line_len(head.row()) {
12001                        transpose_offset = display_map
12002                            .buffer_snapshot()
12003                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12004                    }
12005
12006                    if transpose_offset == 0 {
12007                        return;
12008                    }
12009
12010                    *head.column_mut() += 1;
12011                    head = display_map.clip_point(head, Bias::Right);
12012                    let goal = SelectionGoal::HorizontalPosition(
12013                        display_map
12014                            .x_for_display_point(head, text_layout_details)
12015                            .into(),
12016                    );
12017                    selection.collapse_to(head, goal);
12018
12019                    let transpose_start = display_map
12020                        .buffer_snapshot()
12021                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
12022                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12023                        let transpose_end = display_map
12024                            .buffer_snapshot()
12025                            .clip_offset(transpose_offset + 1, Bias::Right);
12026                        if let Some(ch) = display_map
12027                            .buffer_snapshot()
12028                            .chars_at(transpose_start)
12029                            .next()
12030                        {
12031                            edits.push((transpose_start..transpose_offset, String::new()));
12032                            edits.push((transpose_end..transpose_end, ch.to_string()));
12033                        }
12034                    }
12035                });
12036                edits
12037            });
12038            this.buffer
12039                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12040            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12041            this.change_selections(Default::default(), window, cx, |s| {
12042                s.select(selections);
12043            });
12044        });
12045    }
12046
12047    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12048        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12049        if self.mode.is_single_line() {
12050            cx.propagate();
12051            return;
12052        }
12053
12054        self.rewrap_impl(RewrapOptions::default(), cx)
12055    }
12056
12057    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12058        let buffer = self.buffer.read(cx).snapshot(cx);
12059        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12060
12061        #[derive(Clone, Debug, PartialEq)]
12062        enum CommentFormat {
12063            /// single line comment, with prefix for line
12064            Line(String),
12065            /// single line within a block comment, with prefix for line
12066            BlockLine(String),
12067            /// a single line of a block comment that includes the initial delimiter
12068            BlockCommentWithStart(BlockCommentConfig),
12069            /// a single line of a block comment that includes the ending delimiter
12070            BlockCommentWithEnd(BlockCommentConfig),
12071        }
12072
12073        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12074        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12075            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12076                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12077                .peekable();
12078
12079            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12080                row
12081            } else {
12082                return Vec::new();
12083            };
12084
12085            let language_settings = buffer.language_settings_at(selection.head(), cx);
12086            let language_scope = buffer.language_scope_at(selection.head());
12087
12088            let indent_and_prefix_for_row =
12089                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12090                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12091                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12092                        &language_scope
12093                    {
12094                        let indent_end = Point::new(row, indent.len);
12095                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12096                        let line_text_after_indent = buffer
12097                            .text_for_range(indent_end..line_end)
12098                            .collect::<String>();
12099
12100                        let is_within_comment_override = buffer
12101                            .language_scope_at(indent_end)
12102                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12103                        let comment_delimiters = if is_within_comment_override {
12104                            // we are within a comment syntax node, but we don't
12105                            // yet know what kind of comment: block, doc or line
12106                            match (
12107                                language_scope.documentation_comment(),
12108                                language_scope.block_comment(),
12109                            ) {
12110                                (Some(config), _) | (_, Some(config))
12111                                    if buffer.contains_str_at(indent_end, &config.start) =>
12112                                {
12113                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12114                                }
12115                                (Some(config), _) | (_, Some(config))
12116                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12117                                {
12118                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12119                                }
12120                                (Some(config), _) | (_, Some(config))
12121                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12122                                {
12123                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12124                                }
12125                                (_, _) => language_scope
12126                                    .line_comment_prefixes()
12127                                    .iter()
12128                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12129                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12130                            }
12131                        } else {
12132                            // we not in an overridden comment node, but we may
12133                            // be within a non-overridden line comment node
12134                            language_scope
12135                                .line_comment_prefixes()
12136                                .iter()
12137                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12138                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12139                        };
12140
12141                        let rewrap_prefix = language_scope
12142                            .rewrap_prefixes()
12143                            .iter()
12144                            .find_map(|prefix_regex| {
12145                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12146                                    if mat.start() == 0 {
12147                                        Some(mat.as_str().to_string())
12148                                    } else {
12149                                        None
12150                                    }
12151                                })
12152                            })
12153                            .flatten();
12154                        (comment_delimiters, rewrap_prefix)
12155                    } else {
12156                        (None, None)
12157                    };
12158                    (indent, comment_prefix, rewrap_prefix)
12159                };
12160
12161            let mut ranges = Vec::new();
12162            let from_empty_selection = selection.is_empty();
12163
12164            let mut current_range_start = first_row;
12165            let mut prev_row = first_row;
12166            let (
12167                mut current_range_indent,
12168                mut current_range_comment_delimiters,
12169                mut current_range_rewrap_prefix,
12170            ) = indent_and_prefix_for_row(first_row);
12171
12172            for row in non_blank_rows_iter.skip(1) {
12173                let has_paragraph_break = row > prev_row + 1;
12174
12175                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12176                    indent_and_prefix_for_row(row);
12177
12178                let has_indent_change = row_indent != current_range_indent;
12179                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12180
12181                let has_boundary_change = has_comment_change
12182                    || row_rewrap_prefix.is_some()
12183                    || (has_indent_change && current_range_comment_delimiters.is_some());
12184
12185                if has_paragraph_break || has_boundary_change {
12186                    ranges.push((
12187                        language_settings.clone(),
12188                        Point::new(current_range_start, 0)
12189                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12190                        current_range_indent,
12191                        current_range_comment_delimiters.clone(),
12192                        current_range_rewrap_prefix.clone(),
12193                        from_empty_selection,
12194                    ));
12195                    current_range_start = row;
12196                    current_range_indent = row_indent;
12197                    current_range_comment_delimiters = row_comment_delimiters;
12198                    current_range_rewrap_prefix = row_rewrap_prefix;
12199                }
12200                prev_row = row;
12201            }
12202
12203            ranges.push((
12204                language_settings.clone(),
12205                Point::new(current_range_start, 0)
12206                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12207                current_range_indent,
12208                current_range_comment_delimiters,
12209                current_range_rewrap_prefix,
12210                from_empty_selection,
12211            ));
12212
12213            ranges
12214        });
12215
12216        let mut edits = Vec::new();
12217        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12218
12219        for (
12220            language_settings,
12221            wrap_range,
12222            mut indent_size,
12223            comment_prefix,
12224            rewrap_prefix,
12225            from_empty_selection,
12226        ) in wrap_ranges
12227        {
12228            let mut start_row = wrap_range.start.row;
12229            let mut end_row = wrap_range.end.row;
12230
12231            // Skip selections that overlap with a range that has already been rewrapped.
12232            let selection_range = start_row..end_row;
12233            if rewrapped_row_ranges
12234                .iter()
12235                .any(|range| range.overlaps(&selection_range))
12236            {
12237                continue;
12238            }
12239
12240            let tab_size = language_settings.tab_size;
12241
12242            let (line_prefix, inside_comment) = match &comment_prefix {
12243                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12244                    (Some(prefix.as_str()), true)
12245                }
12246                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12247                    (Some(prefix.as_ref()), true)
12248                }
12249                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12250                    start: _,
12251                    end: _,
12252                    prefix,
12253                    tab_size,
12254                })) => {
12255                    indent_size.len += tab_size;
12256                    (Some(prefix.as_ref()), true)
12257                }
12258                None => (None, false),
12259            };
12260            let indent_prefix = indent_size.chars().collect::<String>();
12261            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12262
12263            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12264                RewrapBehavior::InComments => inside_comment,
12265                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12266                RewrapBehavior::Anywhere => true,
12267            };
12268
12269            let should_rewrap = options.override_language_settings
12270                || allow_rewrap_based_on_language
12271                || self.hard_wrap.is_some();
12272            if !should_rewrap {
12273                continue;
12274            }
12275
12276            if from_empty_selection {
12277                'expand_upwards: while start_row > 0 {
12278                    let prev_row = start_row - 1;
12279                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12280                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12281                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12282                    {
12283                        start_row = prev_row;
12284                    } else {
12285                        break 'expand_upwards;
12286                    }
12287                }
12288
12289                'expand_downwards: while end_row < buffer.max_point().row {
12290                    let next_row = end_row + 1;
12291                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12292                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12293                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12294                    {
12295                        end_row = next_row;
12296                    } else {
12297                        break 'expand_downwards;
12298                    }
12299                }
12300            }
12301
12302            let start = Point::new(start_row, 0);
12303            let start_offset = ToOffset::to_offset(&start, &buffer);
12304            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12305            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12306            let mut first_line_delimiter = None;
12307            let mut last_line_delimiter = None;
12308            let Some(lines_without_prefixes) = selection_text
12309                .lines()
12310                .enumerate()
12311                .map(|(ix, line)| {
12312                    let line_trimmed = line.trim_start();
12313                    if rewrap_prefix.is_some() && ix > 0 {
12314                        Ok(line_trimmed)
12315                    } else if let Some(
12316                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12317                            start,
12318                            prefix,
12319                            end,
12320                            tab_size,
12321                        })
12322                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12323                            start,
12324                            prefix,
12325                            end,
12326                            tab_size,
12327                        }),
12328                    ) = &comment_prefix
12329                    {
12330                        let line_trimmed = line_trimmed
12331                            .strip_prefix(start.as_ref())
12332                            .map(|s| {
12333                                let mut indent_size = indent_size;
12334                                indent_size.len -= tab_size;
12335                                let indent_prefix: String = indent_size.chars().collect();
12336                                first_line_delimiter = Some((indent_prefix, start));
12337                                s.trim_start()
12338                            })
12339                            .unwrap_or(line_trimmed);
12340                        let line_trimmed = line_trimmed
12341                            .strip_suffix(end.as_ref())
12342                            .map(|s| {
12343                                last_line_delimiter = Some(end);
12344                                s.trim_end()
12345                            })
12346                            .unwrap_or(line_trimmed);
12347                        let line_trimmed = line_trimmed
12348                            .strip_prefix(prefix.as_ref())
12349                            .unwrap_or(line_trimmed);
12350                        Ok(line_trimmed)
12351                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12352                        line_trimmed.strip_prefix(prefix).with_context(|| {
12353                            format!("line did not start with prefix {prefix:?}: {line:?}")
12354                        })
12355                    } else {
12356                        line_trimmed
12357                            .strip_prefix(&line_prefix.trim_start())
12358                            .with_context(|| {
12359                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12360                            })
12361                    }
12362                })
12363                .collect::<Result<Vec<_>, _>>()
12364                .log_err()
12365            else {
12366                continue;
12367            };
12368
12369            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12370                buffer
12371                    .language_settings_at(Point::new(start_row, 0), cx)
12372                    .preferred_line_length as usize
12373            });
12374
12375            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12376                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12377            } else {
12378                line_prefix.clone()
12379            };
12380
12381            let wrapped_text = {
12382                let mut wrapped_text = wrap_with_prefix(
12383                    line_prefix,
12384                    subsequent_lines_prefix,
12385                    lines_without_prefixes.join("\n"),
12386                    wrap_column,
12387                    tab_size,
12388                    options.preserve_existing_whitespace,
12389                );
12390
12391                if let Some((indent, delimiter)) = first_line_delimiter {
12392                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12393                }
12394                if let Some(last_line) = last_line_delimiter {
12395                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12396                }
12397
12398                wrapped_text
12399            };
12400
12401            // TODO: should always use char-based diff while still supporting cursor behavior that
12402            // matches vim.
12403            let mut diff_options = DiffOptions::default();
12404            if options.override_language_settings {
12405                diff_options.max_word_diff_len = 0;
12406                diff_options.max_word_diff_line_count = 0;
12407            } else {
12408                diff_options.max_word_diff_len = usize::MAX;
12409                diff_options.max_word_diff_line_count = usize::MAX;
12410            }
12411
12412            for (old_range, new_text) in
12413                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12414            {
12415                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12416                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12417                edits.push((edit_start..edit_end, new_text));
12418            }
12419
12420            rewrapped_row_ranges.push(start_row..=end_row);
12421        }
12422
12423        self.buffer
12424            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12425    }
12426
12427    pub fn cut_common(
12428        &mut self,
12429        cut_no_selection_line: bool,
12430        window: &mut Window,
12431        cx: &mut Context<Self>,
12432    ) -> ClipboardItem {
12433        let mut text = String::new();
12434        let buffer = self.buffer.read(cx).snapshot(cx);
12435        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12436        let mut clipboard_selections = Vec::with_capacity(selections.len());
12437        {
12438            let max_point = buffer.max_point();
12439            let mut is_first = true;
12440            for selection in &mut selections {
12441                let is_entire_line =
12442                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12443                if is_entire_line {
12444                    selection.start = Point::new(selection.start.row, 0);
12445                    if !selection.is_empty() && selection.end.column == 0 {
12446                        selection.end = cmp::min(max_point, selection.end);
12447                    } else {
12448                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12449                    }
12450                    selection.goal = SelectionGoal::None;
12451                }
12452                if is_first {
12453                    is_first = false;
12454                } else {
12455                    text += "\n";
12456                }
12457                let mut len = 0;
12458                for chunk in buffer.text_for_range(selection.start..selection.end) {
12459                    text.push_str(chunk);
12460                    len += chunk.len();
12461                }
12462                clipboard_selections.push(ClipboardSelection {
12463                    len,
12464                    is_entire_line,
12465                    first_line_indent: buffer
12466                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12467                        .len,
12468                });
12469            }
12470        }
12471
12472        self.transact(window, cx, |this, window, cx| {
12473            this.change_selections(Default::default(), window, cx, |s| {
12474                s.select(selections);
12475            });
12476            this.insert("", window, cx);
12477        });
12478        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12479    }
12480
12481    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12482        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12483        let item = self.cut_common(true, window, cx);
12484        cx.write_to_clipboard(item);
12485    }
12486
12487    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12488        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12489        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12490            s.move_with(|snapshot, sel| {
12491                if sel.is_empty() {
12492                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12493                }
12494                if sel.is_empty() {
12495                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12496                }
12497            });
12498        });
12499        let item = self.cut_common(false, window, cx);
12500        cx.set_global(KillRing(item))
12501    }
12502
12503    pub fn kill_ring_yank(
12504        &mut self,
12505        _: &KillRingYank,
12506        window: &mut Window,
12507        cx: &mut Context<Self>,
12508    ) {
12509        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12510        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12511            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12512                (kill_ring.text().to_string(), kill_ring.metadata_json())
12513            } else {
12514                return;
12515            }
12516        } else {
12517            return;
12518        };
12519        self.do_paste(&text, metadata, false, window, cx);
12520    }
12521
12522    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12523        self.do_copy(true, cx);
12524    }
12525
12526    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12527        self.do_copy(false, cx);
12528    }
12529
12530    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12531        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12532        let buffer = self.buffer.read(cx).read(cx);
12533        let mut text = String::new();
12534
12535        let mut clipboard_selections = Vec::with_capacity(selections.len());
12536        {
12537            let max_point = buffer.max_point();
12538            let mut is_first = true;
12539            for selection in &selections {
12540                let mut start = selection.start;
12541                let mut end = selection.end;
12542                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12543                let mut add_trailing_newline = false;
12544                if is_entire_line {
12545                    start = Point::new(start.row, 0);
12546                    let next_line_start = Point::new(end.row + 1, 0);
12547                    if next_line_start <= max_point {
12548                        end = next_line_start;
12549                    } else {
12550                        // We're on the last line without a trailing newline.
12551                        // Copy to the end of the line and add a newline afterwards.
12552                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12553                        add_trailing_newline = true;
12554                    }
12555                }
12556
12557                let mut trimmed_selections = Vec::new();
12558                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12559                    let row = MultiBufferRow(start.row);
12560                    let first_indent = buffer.indent_size_for_line(row);
12561                    if first_indent.len == 0 || start.column > first_indent.len {
12562                        trimmed_selections.push(start..end);
12563                    } else {
12564                        trimmed_selections.push(
12565                            Point::new(row.0, first_indent.len)
12566                                ..Point::new(row.0, buffer.line_len(row)),
12567                        );
12568                        for row in start.row + 1..=end.row {
12569                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12570                            if row == end.row {
12571                                line_len = end.column;
12572                            }
12573                            if line_len == 0 {
12574                                trimmed_selections
12575                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12576                                continue;
12577                            }
12578                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12579                            if row_indent_size.len >= first_indent.len {
12580                                trimmed_selections.push(
12581                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12582                                );
12583                            } else {
12584                                trimmed_selections.clear();
12585                                trimmed_selections.push(start..end);
12586                                break;
12587                            }
12588                        }
12589                    }
12590                } else {
12591                    trimmed_selections.push(start..end);
12592                }
12593
12594                for trimmed_range in trimmed_selections {
12595                    if is_first {
12596                        is_first = false;
12597                    } else {
12598                        text += "\n";
12599                    }
12600                    let mut len = 0;
12601                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12602                        text.push_str(chunk);
12603                        len += chunk.len();
12604                    }
12605                    if add_trailing_newline {
12606                        text.push('\n');
12607                        len += 1;
12608                    }
12609                    clipboard_selections.push(ClipboardSelection {
12610                        len,
12611                        is_entire_line,
12612                        first_line_indent: buffer
12613                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12614                            .len,
12615                    });
12616                }
12617            }
12618        }
12619
12620        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12621            text,
12622            clipboard_selections,
12623        ));
12624    }
12625
12626    pub fn do_paste(
12627        &mut self,
12628        text: &String,
12629        clipboard_selections: Option<Vec<ClipboardSelection>>,
12630        handle_entire_lines: bool,
12631        window: &mut Window,
12632        cx: &mut Context<Self>,
12633    ) {
12634        if self.read_only(cx) {
12635            return;
12636        }
12637
12638        let clipboard_text = Cow::Borrowed(text.as_str());
12639
12640        self.transact(window, cx, |this, window, cx| {
12641            let had_active_edit_prediction = this.has_active_edit_prediction();
12642            let display_map = this.display_snapshot(cx);
12643            let old_selections = this.selections.all::<usize>(&display_map);
12644            let cursor_offset = this.selections.last::<usize>(&display_map).head();
12645
12646            if let Some(mut clipboard_selections) = clipboard_selections {
12647                let all_selections_were_entire_line =
12648                    clipboard_selections.iter().all(|s| s.is_entire_line);
12649                let first_selection_indent_column =
12650                    clipboard_selections.first().map(|s| s.first_line_indent);
12651                if clipboard_selections.len() != old_selections.len() {
12652                    clipboard_selections.drain(..);
12653                }
12654                let mut auto_indent_on_paste = true;
12655
12656                this.buffer.update(cx, |buffer, cx| {
12657                    let snapshot = buffer.read(cx);
12658                    auto_indent_on_paste = snapshot
12659                        .language_settings_at(cursor_offset, cx)
12660                        .auto_indent_on_paste;
12661
12662                    let mut start_offset = 0;
12663                    let mut edits = Vec::new();
12664                    let mut original_indent_columns = Vec::new();
12665                    for (ix, selection) in old_selections.iter().enumerate() {
12666                        let to_insert;
12667                        let entire_line;
12668                        let original_indent_column;
12669                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12670                            let end_offset = start_offset + clipboard_selection.len;
12671                            to_insert = &clipboard_text[start_offset..end_offset];
12672                            entire_line = clipboard_selection.is_entire_line;
12673                            start_offset = end_offset + 1;
12674                            original_indent_column = Some(clipboard_selection.first_line_indent);
12675                        } else {
12676                            to_insert = &*clipboard_text;
12677                            entire_line = all_selections_were_entire_line;
12678                            original_indent_column = first_selection_indent_column
12679                        }
12680
12681                        let (range, to_insert) =
12682                            if selection.is_empty() && handle_entire_lines && entire_line {
12683                                // If the corresponding selection was empty when this slice of the
12684                                // clipboard text was written, then the entire line containing the
12685                                // selection was copied. If this selection is also currently empty,
12686                                // then paste the line before the current line of the buffer.
12687                                let column = selection.start.to_point(&snapshot).column as usize;
12688                                let line_start = selection.start - column;
12689                                (line_start..line_start, Cow::Borrowed(to_insert))
12690                            } else {
12691                                let language = snapshot.language_at(selection.head());
12692                                let range = selection.range();
12693                                if let Some(language) = language
12694                                    && language.name() == "Markdown".into()
12695                                {
12696                                    edit_for_markdown_paste(
12697                                        &snapshot,
12698                                        range,
12699                                        to_insert,
12700                                        url::Url::parse(to_insert).ok(),
12701                                    )
12702                                } else {
12703                                    (range, Cow::Borrowed(to_insert))
12704                                }
12705                            };
12706
12707                        edits.push((range, to_insert));
12708                        original_indent_columns.push(original_indent_column);
12709                    }
12710                    drop(snapshot);
12711
12712                    buffer.edit(
12713                        edits,
12714                        if auto_indent_on_paste {
12715                            Some(AutoindentMode::Block {
12716                                original_indent_columns,
12717                            })
12718                        } else {
12719                            None
12720                        },
12721                        cx,
12722                    );
12723                });
12724
12725                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12726                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12727            } else {
12728                let url = url::Url::parse(&clipboard_text).ok();
12729
12730                let auto_indent_mode = if !clipboard_text.is_empty() {
12731                    Some(AutoindentMode::Block {
12732                        original_indent_columns: Vec::new(),
12733                    })
12734                } else {
12735                    None
12736                };
12737
12738                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12739                    let snapshot = buffer.snapshot(cx);
12740
12741                    let anchors = old_selections
12742                        .iter()
12743                        .map(|s| {
12744                            let anchor = snapshot.anchor_after(s.head());
12745                            s.map(|_| anchor)
12746                        })
12747                        .collect::<Vec<_>>();
12748
12749                    let mut edits = Vec::new();
12750
12751                    for selection in old_selections.iter() {
12752                        let language = snapshot.language_at(selection.head());
12753                        let range = selection.range();
12754
12755                        let (edit_range, edit_text) = if let Some(language) = language
12756                            && language.name() == "Markdown".into()
12757                        {
12758                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12759                        } else {
12760                            (range, clipboard_text.clone())
12761                        };
12762
12763                        edits.push((edit_range, edit_text));
12764                    }
12765
12766                    drop(snapshot);
12767                    buffer.edit(edits, auto_indent_mode, cx);
12768
12769                    anchors
12770                });
12771
12772                this.change_selections(Default::default(), window, cx, |s| {
12773                    s.select_anchors(selection_anchors);
12774                });
12775            }
12776
12777            let trigger_in_words =
12778                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12779
12780            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12781        });
12782    }
12783
12784    pub fn diff_clipboard_with_selection(
12785        &mut self,
12786        _: &DiffClipboardWithSelection,
12787        window: &mut Window,
12788        cx: &mut Context<Self>,
12789    ) {
12790        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
12791
12792        if selections.is_empty() {
12793            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12794            return;
12795        };
12796
12797        let clipboard_text = match cx.read_from_clipboard() {
12798            Some(item) => match item.entries().first() {
12799                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12800                _ => None,
12801            },
12802            None => None,
12803        };
12804
12805        let Some(clipboard_text) = clipboard_text else {
12806            log::warn!("Clipboard doesn't contain text.");
12807            return;
12808        };
12809
12810        window.dispatch_action(
12811            Box::new(DiffClipboardWithSelectionData {
12812                clipboard_text,
12813                editor: cx.entity(),
12814            }),
12815            cx,
12816        );
12817    }
12818
12819    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12820        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12821        if let Some(item) = cx.read_from_clipboard() {
12822            let entries = item.entries();
12823
12824            match entries.first() {
12825                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12826                // of all the pasted entries.
12827                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12828                    .do_paste(
12829                        clipboard_string.text(),
12830                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12831                        true,
12832                        window,
12833                        cx,
12834                    ),
12835                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12836            }
12837        }
12838    }
12839
12840    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12841        if self.read_only(cx) {
12842            return;
12843        }
12844
12845        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12846
12847        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12848            if let Some((selections, _)) =
12849                self.selection_history.transaction(transaction_id).cloned()
12850            {
12851                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12852                    s.select_anchors(selections.to_vec());
12853                });
12854            } else {
12855                log::error!(
12856                    "No entry in selection_history found for undo. \
12857                     This may correspond to a bug where undo does not update the selection. \
12858                     If this is occurring, please add details to \
12859                     https://github.com/zed-industries/zed/issues/22692"
12860                );
12861            }
12862            self.request_autoscroll(Autoscroll::fit(), cx);
12863            self.unmark_text(window, cx);
12864            self.refresh_edit_prediction(true, false, window, cx);
12865            cx.emit(EditorEvent::Edited { transaction_id });
12866            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12867        }
12868    }
12869
12870    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12871        if self.read_only(cx) {
12872            return;
12873        }
12874
12875        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12876
12877        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12878            if let Some((_, Some(selections))) =
12879                self.selection_history.transaction(transaction_id).cloned()
12880            {
12881                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12882                    s.select_anchors(selections.to_vec());
12883                });
12884            } else {
12885                log::error!(
12886                    "No entry in selection_history found for redo. \
12887                     This may correspond to a bug where undo does not update the selection. \
12888                     If this is occurring, please add details to \
12889                     https://github.com/zed-industries/zed/issues/22692"
12890                );
12891            }
12892            self.request_autoscroll(Autoscroll::fit(), cx);
12893            self.unmark_text(window, cx);
12894            self.refresh_edit_prediction(true, false, window, cx);
12895            cx.emit(EditorEvent::Edited { transaction_id });
12896        }
12897    }
12898
12899    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12900        self.buffer
12901            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12902    }
12903
12904    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12905        self.buffer
12906            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12907    }
12908
12909    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12910        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12911        self.change_selections(Default::default(), window, cx, |s| {
12912            s.move_with(|map, selection| {
12913                let cursor = if selection.is_empty() {
12914                    movement::left(map, selection.start)
12915                } else {
12916                    selection.start
12917                };
12918                selection.collapse_to(cursor, SelectionGoal::None);
12919            });
12920        })
12921    }
12922
12923    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12924        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12925        self.change_selections(Default::default(), window, cx, |s| {
12926            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12927        })
12928    }
12929
12930    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12931        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12932        self.change_selections(Default::default(), window, cx, |s| {
12933            s.move_with(|map, selection| {
12934                let cursor = if selection.is_empty() {
12935                    movement::right(map, selection.end)
12936                } else {
12937                    selection.end
12938                };
12939                selection.collapse_to(cursor, SelectionGoal::None)
12940            });
12941        })
12942    }
12943
12944    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12945        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12946        self.change_selections(Default::default(), window, cx, |s| {
12947            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12948        });
12949    }
12950
12951    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12952        if self.take_rename(true, window, cx).is_some() {
12953            return;
12954        }
12955
12956        if self.mode.is_single_line() {
12957            cx.propagate();
12958            return;
12959        }
12960
12961        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12962
12963        let text_layout_details = &self.text_layout_details(window);
12964        let selection_count = self.selections.count();
12965        let first_selection = self.selections.first_anchor();
12966
12967        self.change_selections(Default::default(), window, cx, |s| {
12968            s.move_with(|map, selection| {
12969                if !selection.is_empty() {
12970                    selection.goal = SelectionGoal::None;
12971                }
12972                let (cursor, goal) = movement::up(
12973                    map,
12974                    selection.start,
12975                    selection.goal,
12976                    false,
12977                    text_layout_details,
12978                );
12979                selection.collapse_to(cursor, goal);
12980            });
12981        });
12982
12983        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12984        {
12985            cx.propagate();
12986        }
12987    }
12988
12989    pub fn move_up_by_lines(
12990        &mut self,
12991        action: &MoveUpByLines,
12992        window: &mut Window,
12993        cx: &mut Context<Self>,
12994    ) {
12995        if self.take_rename(true, window, cx).is_some() {
12996            return;
12997        }
12998
12999        if self.mode.is_single_line() {
13000            cx.propagate();
13001            return;
13002        }
13003
13004        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13005
13006        let text_layout_details = &self.text_layout_details(window);
13007
13008        self.change_selections(Default::default(), window, cx, |s| {
13009            s.move_with(|map, selection| {
13010                if !selection.is_empty() {
13011                    selection.goal = SelectionGoal::None;
13012                }
13013                let (cursor, goal) = movement::up_by_rows(
13014                    map,
13015                    selection.start,
13016                    action.lines,
13017                    selection.goal,
13018                    false,
13019                    text_layout_details,
13020                );
13021                selection.collapse_to(cursor, goal);
13022            });
13023        })
13024    }
13025
13026    pub fn move_down_by_lines(
13027        &mut self,
13028        action: &MoveDownByLines,
13029        window: &mut Window,
13030        cx: &mut Context<Self>,
13031    ) {
13032        if self.take_rename(true, window, cx).is_some() {
13033            return;
13034        }
13035
13036        if self.mode.is_single_line() {
13037            cx.propagate();
13038            return;
13039        }
13040
13041        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13042
13043        let text_layout_details = &self.text_layout_details(window);
13044
13045        self.change_selections(Default::default(), window, cx, |s| {
13046            s.move_with(|map, selection| {
13047                if !selection.is_empty() {
13048                    selection.goal = SelectionGoal::None;
13049                }
13050                let (cursor, goal) = movement::down_by_rows(
13051                    map,
13052                    selection.start,
13053                    action.lines,
13054                    selection.goal,
13055                    false,
13056                    text_layout_details,
13057                );
13058                selection.collapse_to(cursor, goal);
13059            });
13060        })
13061    }
13062
13063    pub fn select_down_by_lines(
13064        &mut self,
13065        action: &SelectDownByLines,
13066        window: &mut Window,
13067        cx: &mut Context<Self>,
13068    ) {
13069        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13070        let text_layout_details = &self.text_layout_details(window);
13071        self.change_selections(Default::default(), window, cx, |s| {
13072            s.move_heads_with(|map, head, goal| {
13073                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13074            })
13075        })
13076    }
13077
13078    pub fn select_up_by_lines(
13079        &mut self,
13080        action: &SelectUpByLines,
13081        window: &mut Window,
13082        cx: &mut Context<Self>,
13083    ) {
13084        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13085        let text_layout_details = &self.text_layout_details(window);
13086        self.change_selections(Default::default(), window, cx, |s| {
13087            s.move_heads_with(|map, head, goal| {
13088                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13089            })
13090        })
13091    }
13092
13093    pub fn select_page_up(
13094        &mut self,
13095        _: &SelectPageUp,
13096        window: &mut Window,
13097        cx: &mut Context<Self>,
13098    ) {
13099        let Some(row_count) = self.visible_row_count() else {
13100            return;
13101        };
13102
13103        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13104
13105        let text_layout_details = &self.text_layout_details(window);
13106
13107        self.change_selections(Default::default(), window, cx, |s| {
13108            s.move_heads_with(|map, head, goal| {
13109                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13110            })
13111        })
13112    }
13113
13114    pub fn move_page_up(
13115        &mut self,
13116        action: &MovePageUp,
13117        window: &mut Window,
13118        cx: &mut Context<Self>,
13119    ) {
13120        if self.take_rename(true, window, cx).is_some() {
13121            return;
13122        }
13123
13124        if self
13125            .context_menu
13126            .borrow_mut()
13127            .as_mut()
13128            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13129            .unwrap_or(false)
13130        {
13131            return;
13132        }
13133
13134        if matches!(self.mode, EditorMode::SingleLine) {
13135            cx.propagate();
13136            return;
13137        }
13138
13139        let Some(row_count) = self.visible_row_count() else {
13140            return;
13141        };
13142
13143        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13144
13145        let effects = if action.center_cursor {
13146            SelectionEffects::scroll(Autoscroll::center())
13147        } else {
13148            SelectionEffects::default()
13149        };
13150
13151        let text_layout_details = &self.text_layout_details(window);
13152
13153        self.change_selections(effects, window, cx, |s| {
13154            s.move_with(|map, selection| {
13155                if !selection.is_empty() {
13156                    selection.goal = SelectionGoal::None;
13157                }
13158                let (cursor, goal) = movement::up_by_rows(
13159                    map,
13160                    selection.end,
13161                    row_count,
13162                    selection.goal,
13163                    false,
13164                    text_layout_details,
13165                );
13166                selection.collapse_to(cursor, goal);
13167            });
13168        });
13169    }
13170
13171    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13172        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13173        let text_layout_details = &self.text_layout_details(window);
13174        self.change_selections(Default::default(), window, cx, |s| {
13175            s.move_heads_with(|map, head, goal| {
13176                movement::up(map, head, goal, false, text_layout_details)
13177            })
13178        })
13179    }
13180
13181    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13182        self.take_rename(true, window, cx);
13183
13184        if self.mode.is_single_line() {
13185            cx.propagate();
13186            return;
13187        }
13188
13189        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13190
13191        let text_layout_details = &self.text_layout_details(window);
13192        let selection_count = self.selections.count();
13193        let first_selection = self.selections.first_anchor();
13194
13195        self.change_selections(Default::default(), window, cx, |s| {
13196            s.move_with(|map, selection| {
13197                if !selection.is_empty() {
13198                    selection.goal = SelectionGoal::None;
13199                }
13200                let (cursor, goal) = movement::down(
13201                    map,
13202                    selection.end,
13203                    selection.goal,
13204                    false,
13205                    text_layout_details,
13206                );
13207                selection.collapse_to(cursor, goal);
13208            });
13209        });
13210
13211        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13212        {
13213            cx.propagate();
13214        }
13215    }
13216
13217    pub fn select_page_down(
13218        &mut self,
13219        _: &SelectPageDown,
13220        window: &mut Window,
13221        cx: &mut Context<Self>,
13222    ) {
13223        let Some(row_count) = self.visible_row_count() else {
13224            return;
13225        };
13226
13227        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13228
13229        let text_layout_details = &self.text_layout_details(window);
13230
13231        self.change_selections(Default::default(), window, cx, |s| {
13232            s.move_heads_with(|map, head, goal| {
13233                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13234            })
13235        })
13236    }
13237
13238    pub fn move_page_down(
13239        &mut self,
13240        action: &MovePageDown,
13241        window: &mut Window,
13242        cx: &mut Context<Self>,
13243    ) {
13244        if self.take_rename(true, window, cx).is_some() {
13245            return;
13246        }
13247
13248        if self
13249            .context_menu
13250            .borrow_mut()
13251            .as_mut()
13252            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13253            .unwrap_or(false)
13254        {
13255            return;
13256        }
13257
13258        if matches!(self.mode, EditorMode::SingleLine) {
13259            cx.propagate();
13260            return;
13261        }
13262
13263        let Some(row_count) = self.visible_row_count() else {
13264            return;
13265        };
13266
13267        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13268
13269        let effects = if action.center_cursor {
13270            SelectionEffects::scroll(Autoscroll::center())
13271        } else {
13272            SelectionEffects::default()
13273        };
13274
13275        let text_layout_details = &self.text_layout_details(window);
13276        self.change_selections(effects, window, cx, |s| {
13277            s.move_with(|map, selection| {
13278                if !selection.is_empty() {
13279                    selection.goal = SelectionGoal::None;
13280                }
13281                let (cursor, goal) = movement::down_by_rows(
13282                    map,
13283                    selection.end,
13284                    row_count,
13285                    selection.goal,
13286                    false,
13287                    text_layout_details,
13288                );
13289                selection.collapse_to(cursor, goal);
13290            });
13291        });
13292    }
13293
13294    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13295        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13296        let text_layout_details = &self.text_layout_details(window);
13297        self.change_selections(Default::default(), window, cx, |s| {
13298            s.move_heads_with(|map, head, goal| {
13299                movement::down(map, head, goal, false, text_layout_details)
13300            })
13301        });
13302    }
13303
13304    pub fn context_menu_first(
13305        &mut self,
13306        _: &ContextMenuFirst,
13307        window: &mut Window,
13308        cx: &mut Context<Self>,
13309    ) {
13310        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13311            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13312        }
13313    }
13314
13315    pub fn context_menu_prev(
13316        &mut self,
13317        _: &ContextMenuPrevious,
13318        window: &mut Window,
13319        cx: &mut Context<Self>,
13320    ) {
13321        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13322            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13323        }
13324    }
13325
13326    pub fn context_menu_next(
13327        &mut self,
13328        _: &ContextMenuNext,
13329        window: &mut Window,
13330        cx: &mut Context<Self>,
13331    ) {
13332        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13333            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13334        }
13335    }
13336
13337    pub fn context_menu_last(
13338        &mut self,
13339        _: &ContextMenuLast,
13340        window: &mut Window,
13341        cx: &mut Context<Self>,
13342    ) {
13343        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13344            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13345        }
13346    }
13347
13348    pub fn signature_help_prev(
13349        &mut self,
13350        _: &SignatureHelpPrevious,
13351        _: &mut Window,
13352        cx: &mut Context<Self>,
13353    ) {
13354        if let Some(popover) = self.signature_help_state.popover_mut() {
13355            if popover.current_signature == 0 {
13356                popover.current_signature = popover.signatures.len() - 1;
13357            } else {
13358                popover.current_signature -= 1;
13359            }
13360            cx.notify();
13361        }
13362    }
13363
13364    pub fn signature_help_next(
13365        &mut self,
13366        _: &SignatureHelpNext,
13367        _: &mut Window,
13368        cx: &mut Context<Self>,
13369    ) {
13370        if let Some(popover) = self.signature_help_state.popover_mut() {
13371            if popover.current_signature + 1 == popover.signatures.len() {
13372                popover.current_signature = 0;
13373            } else {
13374                popover.current_signature += 1;
13375            }
13376            cx.notify();
13377        }
13378    }
13379
13380    pub fn move_to_previous_word_start(
13381        &mut self,
13382        _: &MoveToPreviousWordStart,
13383        window: &mut Window,
13384        cx: &mut Context<Self>,
13385    ) {
13386        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13387        self.change_selections(Default::default(), window, cx, |s| {
13388            s.move_cursors_with(|map, head, _| {
13389                (
13390                    movement::previous_word_start(map, head),
13391                    SelectionGoal::None,
13392                )
13393            });
13394        })
13395    }
13396
13397    pub fn move_to_previous_subword_start(
13398        &mut self,
13399        _: &MoveToPreviousSubwordStart,
13400        window: &mut Window,
13401        cx: &mut Context<Self>,
13402    ) {
13403        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13404        self.change_selections(Default::default(), window, cx, |s| {
13405            s.move_cursors_with(|map, head, _| {
13406                (
13407                    movement::previous_subword_start(map, head),
13408                    SelectionGoal::None,
13409                )
13410            });
13411        })
13412    }
13413
13414    pub fn select_to_previous_word_start(
13415        &mut self,
13416        _: &SelectToPreviousWordStart,
13417        window: &mut Window,
13418        cx: &mut Context<Self>,
13419    ) {
13420        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13421        self.change_selections(Default::default(), window, cx, |s| {
13422            s.move_heads_with(|map, head, _| {
13423                (
13424                    movement::previous_word_start(map, head),
13425                    SelectionGoal::None,
13426                )
13427            });
13428        })
13429    }
13430
13431    pub fn select_to_previous_subword_start(
13432        &mut self,
13433        _: &SelectToPreviousSubwordStart,
13434        window: &mut Window,
13435        cx: &mut Context<Self>,
13436    ) {
13437        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13438        self.change_selections(Default::default(), window, cx, |s| {
13439            s.move_heads_with(|map, head, _| {
13440                (
13441                    movement::previous_subword_start(map, head),
13442                    SelectionGoal::None,
13443                )
13444            });
13445        })
13446    }
13447
13448    pub fn delete_to_previous_word_start(
13449        &mut self,
13450        action: &DeleteToPreviousWordStart,
13451        window: &mut Window,
13452        cx: &mut Context<Self>,
13453    ) {
13454        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13455        self.transact(window, cx, |this, window, cx| {
13456            this.select_autoclose_pair(window, cx);
13457            this.change_selections(Default::default(), window, cx, |s| {
13458                s.move_with(|map, selection| {
13459                    if selection.is_empty() {
13460                        let mut cursor = if action.ignore_newlines {
13461                            movement::previous_word_start(map, selection.head())
13462                        } else {
13463                            movement::previous_word_start_or_newline(map, selection.head())
13464                        };
13465                        cursor = movement::adjust_greedy_deletion(
13466                            map,
13467                            selection.head(),
13468                            cursor,
13469                            action.ignore_brackets,
13470                        );
13471                        selection.set_head(cursor, SelectionGoal::None);
13472                    }
13473                });
13474            });
13475            this.insert("", window, cx);
13476        });
13477    }
13478
13479    pub fn delete_to_previous_subword_start(
13480        &mut self,
13481        _: &DeleteToPreviousSubwordStart,
13482        window: &mut Window,
13483        cx: &mut Context<Self>,
13484    ) {
13485        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13486        self.transact(window, cx, |this, window, cx| {
13487            this.select_autoclose_pair(window, cx);
13488            this.change_selections(Default::default(), window, cx, |s| {
13489                s.move_with(|map, selection| {
13490                    if selection.is_empty() {
13491                        let mut cursor = movement::previous_subword_start(map, selection.head());
13492                        cursor =
13493                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13494                        selection.set_head(cursor, SelectionGoal::None);
13495                    }
13496                });
13497            });
13498            this.insert("", window, cx);
13499        });
13500    }
13501
13502    pub fn move_to_next_word_end(
13503        &mut self,
13504        _: &MoveToNextWordEnd,
13505        window: &mut Window,
13506        cx: &mut Context<Self>,
13507    ) {
13508        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13509        self.change_selections(Default::default(), window, cx, |s| {
13510            s.move_cursors_with(|map, head, _| {
13511                (movement::next_word_end(map, head), SelectionGoal::None)
13512            });
13513        })
13514    }
13515
13516    pub fn move_to_next_subword_end(
13517        &mut self,
13518        _: &MoveToNextSubwordEnd,
13519        window: &mut Window,
13520        cx: &mut Context<Self>,
13521    ) {
13522        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13523        self.change_selections(Default::default(), window, cx, |s| {
13524            s.move_cursors_with(|map, head, _| {
13525                (movement::next_subword_end(map, head), SelectionGoal::None)
13526            });
13527        })
13528    }
13529
13530    pub fn select_to_next_word_end(
13531        &mut self,
13532        _: &SelectToNextWordEnd,
13533        window: &mut Window,
13534        cx: &mut Context<Self>,
13535    ) {
13536        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13537        self.change_selections(Default::default(), window, cx, |s| {
13538            s.move_heads_with(|map, head, _| {
13539                (movement::next_word_end(map, head), SelectionGoal::None)
13540            });
13541        })
13542    }
13543
13544    pub fn select_to_next_subword_end(
13545        &mut self,
13546        _: &SelectToNextSubwordEnd,
13547        window: &mut Window,
13548        cx: &mut Context<Self>,
13549    ) {
13550        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13551        self.change_selections(Default::default(), window, cx, |s| {
13552            s.move_heads_with(|map, head, _| {
13553                (movement::next_subword_end(map, head), SelectionGoal::None)
13554            });
13555        })
13556    }
13557
13558    pub fn delete_to_next_word_end(
13559        &mut self,
13560        action: &DeleteToNextWordEnd,
13561        window: &mut Window,
13562        cx: &mut Context<Self>,
13563    ) {
13564        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13565        self.transact(window, cx, |this, window, cx| {
13566            this.change_selections(Default::default(), window, cx, |s| {
13567                s.move_with(|map, selection| {
13568                    if selection.is_empty() {
13569                        let mut cursor = if action.ignore_newlines {
13570                            movement::next_word_end(map, selection.head())
13571                        } else {
13572                            movement::next_word_end_or_newline(map, selection.head())
13573                        };
13574                        cursor = movement::adjust_greedy_deletion(
13575                            map,
13576                            selection.head(),
13577                            cursor,
13578                            action.ignore_brackets,
13579                        );
13580                        selection.set_head(cursor, SelectionGoal::None);
13581                    }
13582                });
13583            });
13584            this.insert("", window, cx);
13585        });
13586    }
13587
13588    pub fn delete_to_next_subword_end(
13589        &mut self,
13590        _: &DeleteToNextSubwordEnd,
13591        window: &mut Window,
13592        cx: &mut Context<Self>,
13593    ) {
13594        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13595        self.transact(window, cx, |this, window, cx| {
13596            this.change_selections(Default::default(), window, cx, |s| {
13597                s.move_with(|map, selection| {
13598                    if selection.is_empty() {
13599                        let mut cursor = movement::next_subword_end(map, selection.head());
13600                        cursor =
13601                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13602                        selection.set_head(cursor, SelectionGoal::None);
13603                    }
13604                });
13605            });
13606            this.insert("", window, cx);
13607        });
13608    }
13609
13610    pub fn move_to_beginning_of_line(
13611        &mut self,
13612        action: &MoveToBeginningOfLine,
13613        window: &mut Window,
13614        cx: &mut Context<Self>,
13615    ) {
13616        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13617        self.change_selections(Default::default(), window, cx, |s| {
13618            s.move_cursors_with(|map, head, _| {
13619                (
13620                    movement::indented_line_beginning(
13621                        map,
13622                        head,
13623                        action.stop_at_soft_wraps,
13624                        action.stop_at_indent,
13625                    ),
13626                    SelectionGoal::None,
13627                )
13628            });
13629        })
13630    }
13631
13632    pub fn select_to_beginning_of_line(
13633        &mut self,
13634        action: &SelectToBeginningOfLine,
13635        window: &mut Window,
13636        cx: &mut Context<Self>,
13637    ) {
13638        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13639        self.change_selections(Default::default(), window, cx, |s| {
13640            s.move_heads_with(|map, head, _| {
13641                (
13642                    movement::indented_line_beginning(
13643                        map,
13644                        head,
13645                        action.stop_at_soft_wraps,
13646                        action.stop_at_indent,
13647                    ),
13648                    SelectionGoal::None,
13649                )
13650            });
13651        });
13652    }
13653
13654    pub fn delete_to_beginning_of_line(
13655        &mut self,
13656        action: &DeleteToBeginningOfLine,
13657        window: &mut Window,
13658        cx: &mut Context<Self>,
13659    ) {
13660        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13661        self.transact(window, cx, |this, window, cx| {
13662            this.change_selections(Default::default(), window, cx, |s| {
13663                s.move_with(|_, selection| {
13664                    selection.reversed = true;
13665                });
13666            });
13667
13668            this.select_to_beginning_of_line(
13669                &SelectToBeginningOfLine {
13670                    stop_at_soft_wraps: false,
13671                    stop_at_indent: action.stop_at_indent,
13672                },
13673                window,
13674                cx,
13675            );
13676            this.backspace(&Backspace, window, cx);
13677        });
13678    }
13679
13680    pub fn move_to_end_of_line(
13681        &mut self,
13682        action: &MoveToEndOfLine,
13683        window: &mut Window,
13684        cx: &mut Context<Self>,
13685    ) {
13686        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13687        self.change_selections(Default::default(), window, cx, |s| {
13688            s.move_cursors_with(|map, head, _| {
13689                (
13690                    movement::line_end(map, head, action.stop_at_soft_wraps),
13691                    SelectionGoal::None,
13692                )
13693            });
13694        })
13695    }
13696
13697    pub fn select_to_end_of_line(
13698        &mut self,
13699        action: &SelectToEndOfLine,
13700        window: &mut Window,
13701        cx: &mut Context<Self>,
13702    ) {
13703        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13704        self.change_selections(Default::default(), window, cx, |s| {
13705            s.move_heads_with(|map, head, _| {
13706                (
13707                    movement::line_end(map, head, action.stop_at_soft_wraps),
13708                    SelectionGoal::None,
13709                )
13710            });
13711        })
13712    }
13713
13714    pub fn delete_to_end_of_line(
13715        &mut self,
13716        _: &DeleteToEndOfLine,
13717        window: &mut Window,
13718        cx: &mut Context<Self>,
13719    ) {
13720        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13721        self.transact(window, cx, |this, window, cx| {
13722            this.select_to_end_of_line(
13723                &SelectToEndOfLine {
13724                    stop_at_soft_wraps: false,
13725                },
13726                window,
13727                cx,
13728            );
13729            this.delete(&Delete, window, cx);
13730        });
13731    }
13732
13733    pub fn cut_to_end_of_line(
13734        &mut self,
13735        action: &CutToEndOfLine,
13736        window: &mut Window,
13737        cx: &mut Context<Self>,
13738    ) {
13739        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13740        self.transact(window, cx, |this, window, cx| {
13741            this.select_to_end_of_line(
13742                &SelectToEndOfLine {
13743                    stop_at_soft_wraps: false,
13744                },
13745                window,
13746                cx,
13747            );
13748            if !action.stop_at_newlines {
13749                this.change_selections(Default::default(), window, cx, |s| {
13750                    s.move_with(|_, sel| {
13751                        if sel.is_empty() {
13752                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13753                        }
13754                    });
13755                });
13756            }
13757            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13758            let item = this.cut_common(false, window, cx);
13759            cx.write_to_clipboard(item);
13760        });
13761    }
13762
13763    pub fn move_to_start_of_paragraph(
13764        &mut self,
13765        _: &MoveToStartOfParagraph,
13766        window: &mut Window,
13767        cx: &mut Context<Self>,
13768    ) {
13769        if matches!(self.mode, EditorMode::SingleLine) {
13770            cx.propagate();
13771            return;
13772        }
13773        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13774        self.change_selections(Default::default(), window, cx, |s| {
13775            s.move_with(|map, selection| {
13776                selection.collapse_to(
13777                    movement::start_of_paragraph(map, selection.head(), 1),
13778                    SelectionGoal::None,
13779                )
13780            });
13781        })
13782    }
13783
13784    pub fn move_to_end_of_paragraph(
13785        &mut self,
13786        _: &MoveToEndOfParagraph,
13787        window: &mut Window,
13788        cx: &mut Context<Self>,
13789    ) {
13790        if matches!(self.mode, EditorMode::SingleLine) {
13791            cx.propagate();
13792            return;
13793        }
13794        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13795        self.change_selections(Default::default(), window, cx, |s| {
13796            s.move_with(|map, selection| {
13797                selection.collapse_to(
13798                    movement::end_of_paragraph(map, selection.head(), 1),
13799                    SelectionGoal::None,
13800                )
13801            });
13802        })
13803    }
13804
13805    pub fn select_to_start_of_paragraph(
13806        &mut self,
13807        _: &SelectToStartOfParagraph,
13808        window: &mut Window,
13809        cx: &mut Context<Self>,
13810    ) {
13811        if matches!(self.mode, EditorMode::SingleLine) {
13812            cx.propagate();
13813            return;
13814        }
13815        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13816        self.change_selections(Default::default(), window, cx, |s| {
13817            s.move_heads_with(|map, head, _| {
13818                (
13819                    movement::start_of_paragraph(map, head, 1),
13820                    SelectionGoal::None,
13821                )
13822            });
13823        })
13824    }
13825
13826    pub fn select_to_end_of_paragraph(
13827        &mut self,
13828        _: &SelectToEndOfParagraph,
13829        window: &mut Window,
13830        cx: &mut Context<Self>,
13831    ) {
13832        if matches!(self.mode, EditorMode::SingleLine) {
13833            cx.propagate();
13834            return;
13835        }
13836        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13837        self.change_selections(Default::default(), window, cx, |s| {
13838            s.move_heads_with(|map, head, _| {
13839                (
13840                    movement::end_of_paragraph(map, head, 1),
13841                    SelectionGoal::None,
13842                )
13843            });
13844        })
13845    }
13846
13847    pub fn move_to_start_of_excerpt(
13848        &mut self,
13849        _: &MoveToStartOfExcerpt,
13850        window: &mut Window,
13851        cx: &mut Context<Self>,
13852    ) {
13853        if matches!(self.mode, EditorMode::SingleLine) {
13854            cx.propagate();
13855            return;
13856        }
13857        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13858        self.change_selections(Default::default(), window, cx, |s| {
13859            s.move_with(|map, selection| {
13860                selection.collapse_to(
13861                    movement::start_of_excerpt(
13862                        map,
13863                        selection.head(),
13864                        workspace::searchable::Direction::Prev,
13865                    ),
13866                    SelectionGoal::None,
13867                )
13868            });
13869        })
13870    }
13871
13872    pub fn move_to_start_of_next_excerpt(
13873        &mut self,
13874        _: &MoveToStartOfNextExcerpt,
13875        window: &mut Window,
13876        cx: &mut Context<Self>,
13877    ) {
13878        if matches!(self.mode, EditorMode::SingleLine) {
13879            cx.propagate();
13880            return;
13881        }
13882
13883        self.change_selections(Default::default(), window, cx, |s| {
13884            s.move_with(|map, selection| {
13885                selection.collapse_to(
13886                    movement::start_of_excerpt(
13887                        map,
13888                        selection.head(),
13889                        workspace::searchable::Direction::Next,
13890                    ),
13891                    SelectionGoal::None,
13892                )
13893            });
13894        })
13895    }
13896
13897    pub fn move_to_end_of_excerpt(
13898        &mut self,
13899        _: &MoveToEndOfExcerpt,
13900        window: &mut Window,
13901        cx: &mut Context<Self>,
13902    ) {
13903        if matches!(self.mode, EditorMode::SingleLine) {
13904            cx.propagate();
13905            return;
13906        }
13907        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13908        self.change_selections(Default::default(), window, cx, |s| {
13909            s.move_with(|map, selection| {
13910                selection.collapse_to(
13911                    movement::end_of_excerpt(
13912                        map,
13913                        selection.head(),
13914                        workspace::searchable::Direction::Next,
13915                    ),
13916                    SelectionGoal::None,
13917                )
13918            });
13919        })
13920    }
13921
13922    pub fn move_to_end_of_previous_excerpt(
13923        &mut self,
13924        _: &MoveToEndOfPreviousExcerpt,
13925        window: &mut Window,
13926        cx: &mut Context<Self>,
13927    ) {
13928        if matches!(self.mode, EditorMode::SingleLine) {
13929            cx.propagate();
13930            return;
13931        }
13932        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13933        self.change_selections(Default::default(), window, cx, |s| {
13934            s.move_with(|map, selection| {
13935                selection.collapse_to(
13936                    movement::end_of_excerpt(
13937                        map,
13938                        selection.head(),
13939                        workspace::searchable::Direction::Prev,
13940                    ),
13941                    SelectionGoal::None,
13942                )
13943            });
13944        })
13945    }
13946
13947    pub fn select_to_start_of_excerpt(
13948        &mut self,
13949        _: &SelectToStartOfExcerpt,
13950        window: &mut Window,
13951        cx: &mut Context<Self>,
13952    ) {
13953        if matches!(self.mode, EditorMode::SingleLine) {
13954            cx.propagate();
13955            return;
13956        }
13957        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13958        self.change_selections(Default::default(), window, cx, |s| {
13959            s.move_heads_with(|map, head, _| {
13960                (
13961                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13962                    SelectionGoal::None,
13963                )
13964            });
13965        })
13966    }
13967
13968    pub fn select_to_start_of_next_excerpt(
13969        &mut self,
13970        _: &SelectToStartOfNextExcerpt,
13971        window: &mut Window,
13972        cx: &mut Context<Self>,
13973    ) {
13974        if matches!(self.mode, EditorMode::SingleLine) {
13975            cx.propagate();
13976            return;
13977        }
13978        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13979        self.change_selections(Default::default(), window, cx, |s| {
13980            s.move_heads_with(|map, head, _| {
13981                (
13982                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13983                    SelectionGoal::None,
13984                )
13985            });
13986        })
13987    }
13988
13989    pub fn select_to_end_of_excerpt(
13990        &mut self,
13991        _: &SelectToEndOfExcerpt,
13992        window: &mut Window,
13993        cx: &mut Context<Self>,
13994    ) {
13995        if matches!(self.mode, EditorMode::SingleLine) {
13996            cx.propagate();
13997            return;
13998        }
13999        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14000        self.change_selections(Default::default(), window, cx, |s| {
14001            s.move_heads_with(|map, head, _| {
14002                (
14003                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14004                    SelectionGoal::None,
14005                )
14006            });
14007        })
14008    }
14009
14010    pub fn select_to_end_of_previous_excerpt(
14011        &mut self,
14012        _: &SelectToEndOfPreviousExcerpt,
14013        window: &mut Window,
14014        cx: &mut Context<Self>,
14015    ) {
14016        if matches!(self.mode, EditorMode::SingleLine) {
14017            cx.propagate();
14018            return;
14019        }
14020        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14021        self.change_selections(Default::default(), window, cx, |s| {
14022            s.move_heads_with(|map, head, _| {
14023                (
14024                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14025                    SelectionGoal::None,
14026                )
14027            });
14028        })
14029    }
14030
14031    pub fn move_to_beginning(
14032        &mut self,
14033        _: &MoveToBeginning,
14034        window: &mut Window,
14035        cx: &mut Context<Self>,
14036    ) {
14037        if matches!(self.mode, EditorMode::SingleLine) {
14038            cx.propagate();
14039            return;
14040        }
14041        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14042        self.change_selections(Default::default(), window, cx, |s| {
14043            s.select_ranges(vec![0..0]);
14044        });
14045    }
14046
14047    pub fn select_to_beginning(
14048        &mut self,
14049        _: &SelectToBeginning,
14050        window: &mut Window,
14051        cx: &mut Context<Self>,
14052    ) {
14053        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14054        selection.set_head(Point::zero(), SelectionGoal::None);
14055        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14056        self.change_selections(Default::default(), window, cx, |s| {
14057            s.select(vec![selection]);
14058        });
14059    }
14060
14061    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14062        if matches!(self.mode, EditorMode::SingleLine) {
14063            cx.propagate();
14064            return;
14065        }
14066        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14067        let cursor = self.buffer.read(cx).read(cx).len();
14068        self.change_selections(Default::default(), window, cx, |s| {
14069            s.select_ranges(vec![cursor..cursor])
14070        });
14071    }
14072
14073    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14074        self.nav_history = nav_history;
14075    }
14076
14077    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14078        self.nav_history.as_ref()
14079    }
14080
14081    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14082        self.push_to_nav_history(
14083            self.selections.newest_anchor().head(),
14084            None,
14085            false,
14086            true,
14087            cx,
14088        );
14089    }
14090
14091    fn push_to_nav_history(
14092        &mut self,
14093        cursor_anchor: Anchor,
14094        new_position: Option<Point>,
14095        is_deactivate: bool,
14096        always: bool,
14097        cx: &mut Context<Self>,
14098    ) {
14099        if let Some(nav_history) = self.nav_history.as_mut() {
14100            let buffer = self.buffer.read(cx).read(cx);
14101            let cursor_position = cursor_anchor.to_point(&buffer);
14102            let scroll_state = self.scroll_manager.anchor();
14103            let scroll_top_row = scroll_state.top_row(&buffer);
14104            drop(buffer);
14105
14106            if let Some(new_position) = new_position {
14107                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14108                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14109                    return;
14110                }
14111            }
14112
14113            nav_history.push(
14114                Some(NavigationData {
14115                    cursor_anchor,
14116                    cursor_position,
14117                    scroll_anchor: scroll_state,
14118                    scroll_top_row,
14119                }),
14120                cx,
14121            );
14122            cx.emit(EditorEvent::PushedToNavHistory {
14123                anchor: cursor_anchor,
14124                is_deactivate,
14125            })
14126        }
14127    }
14128
14129    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14130        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14131        let buffer = self.buffer.read(cx).snapshot(cx);
14132        let mut selection = self.selections.first::<usize>(&self.display_snapshot(cx));
14133        selection.set_head(buffer.len(), SelectionGoal::None);
14134        self.change_selections(Default::default(), window, cx, |s| {
14135            s.select(vec![selection]);
14136        });
14137    }
14138
14139    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14140        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14141        let end = self.buffer.read(cx).read(cx).len();
14142        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14143            s.select_ranges(vec![0..end]);
14144        });
14145    }
14146
14147    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14148        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14149        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14150        let mut selections = self.selections.all::<Point>(&display_map);
14151        let max_point = display_map.buffer_snapshot().max_point();
14152        for selection in &mut selections {
14153            let rows = selection.spanned_rows(true, &display_map);
14154            selection.start = Point::new(rows.start.0, 0);
14155            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14156            selection.reversed = false;
14157        }
14158        self.change_selections(Default::default(), window, cx, |s| {
14159            s.select(selections);
14160        });
14161    }
14162
14163    pub fn split_selection_into_lines(
14164        &mut self,
14165        action: &SplitSelectionIntoLines,
14166        window: &mut Window,
14167        cx: &mut Context<Self>,
14168    ) {
14169        let selections = self
14170            .selections
14171            .all::<Point>(&self.display_snapshot(cx))
14172            .into_iter()
14173            .map(|selection| selection.start..selection.end)
14174            .collect::<Vec<_>>();
14175        self.unfold_ranges(&selections, true, true, cx);
14176
14177        let mut new_selection_ranges = Vec::new();
14178        {
14179            let buffer = self.buffer.read(cx).read(cx);
14180            for selection in selections {
14181                for row in selection.start.row..selection.end.row {
14182                    let line_start = Point::new(row, 0);
14183                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14184
14185                    if action.keep_selections {
14186                        // Keep the selection range for each line
14187                        let selection_start = if row == selection.start.row {
14188                            selection.start
14189                        } else {
14190                            line_start
14191                        };
14192                        new_selection_ranges.push(selection_start..line_end);
14193                    } else {
14194                        // Collapse to cursor at end of line
14195                        new_selection_ranges.push(line_end..line_end);
14196                    }
14197                }
14198
14199                let is_multiline_selection = selection.start.row != selection.end.row;
14200                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14201                // so this action feels more ergonomic when paired with other selection operations
14202                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14203                if !should_skip_last {
14204                    if action.keep_selections {
14205                        if is_multiline_selection {
14206                            let line_start = Point::new(selection.end.row, 0);
14207                            new_selection_ranges.push(line_start..selection.end);
14208                        } else {
14209                            new_selection_ranges.push(selection.start..selection.end);
14210                        }
14211                    } else {
14212                        new_selection_ranges.push(selection.end..selection.end);
14213                    }
14214                }
14215            }
14216        }
14217        self.change_selections(Default::default(), window, cx, |s| {
14218            s.select_ranges(new_selection_ranges);
14219        });
14220    }
14221
14222    pub fn add_selection_above(
14223        &mut self,
14224        action: &AddSelectionAbove,
14225        window: &mut Window,
14226        cx: &mut Context<Self>,
14227    ) {
14228        self.add_selection(true, action.skip_soft_wrap, window, cx);
14229    }
14230
14231    pub fn add_selection_below(
14232        &mut self,
14233        action: &AddSelectionBelow,
14234        window: &mut Window,
14235        cx: &mut Context<Self>,
14236    ) {
14237        self.add_selection(false, action.skip_soft_wrap, window, cx);
14238    }
14239
14240    fn add_selection(
14241        &mut self,
14242        above: bool,
14243        skip_soft_wrap: bool,
14244        window: &mut Window,
14245        cx: &mut Context<Self>,
14246    ) {
14247        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14248
14249        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14250        let all_selections = self.selections.all::<Point>(&display_map);
14251        let text_layout_details = self.text_layout_details(window);
14252
14253        let (mut columnar_selections, new_selections_to_columnarize) = {
14254            if let Some(state) = self.add_selections_state.as_ref() {
14255                let columnar_selection_ids: HashSet<_> = state
14256                    .groups
14257                    .iter()
14258                    .flat_map(|group| group.stack.iter())
14259                    .copied()
14260                    .collect();
14261
14262                all_selections
14263                    .into_iter()
14264                    .partition(|s| columnar_selection_ids.contains(&s.id))
14265            } else {
14266                (Vec::new(), all_selections)
14267            }
14268        };
14269
14270        let mut state = self
14271            .add_selections_state
14272            .take()
14273            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14274
14275        for selection in new_selections_to_columnarize {
14276            let range = selection.display_range(&display_map).sorted();
14277            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14278            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14279            let positions = start_x.min(end_x)..start_x.max(end_x);
14280            let mut stack = Vec::new();
14281            for row in range.start.row().0..=range.end.row().0 {
14282                if let Some(selection) = self.selections.build_columnar_selection(
14283                    &display_map,
14284                    DisplayRow(row),
14285                    &positions,
14286                    selection.reversed,
14287                    &text_layout_details,
14288                ) {
14289                    stack.push(selection.id);
14290                    columnar_selections.push(selection);
14291                }
14292            }
14293            if !stack.is_empty() {
14294                if above {
14295                    stack.reverse();
14296                }
14297                state.groups.push(AddSelectionsGroup { above, stack });
14298            }
14299        }
14300
14301        let mut final_selections = Vec::new();
14302        let end_row = if above {
14303            DisplayRow(0)
14304        } else {
14305            display_map.max_point().row()
14306        };
14307
14308        let mut last_added_item_per_group = HashMap::default();
14309        for group in state.groups.iter_mut() {
14310            if let Some(last_id) = group.stack.last() {
14311                last_added_item_per_group.insert(*last_id, group);
14312            }
14313        }
14314
14315        for selection in columnar_selections {
14316            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14317                if above == group.above {
14318                    let range = selection.display_range(&display_map).sorted();
14319                    debug_assert_eq!(range.start.row(), range.end.row());
14320                    let mut row = range.start.row();
14321                    let positions =
14322                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14323                            Pixels::from(start)..Pixels::from(end)
14324                        } else {
14325                            let start_x =
14326                                display_map.x_for_display_point(range.start, &text_layout_details);
14327                            let end_x =
14328                                display_map.x_for_display_point(range.end, &text_layout_details);
14329                            start_x.min(end_x)..start_x.max(end_x)
14330                        };
14331
14332                    let mut maybe_new_selection = None;
14333                    let direction = if above { -1 } else { 1 };
14334
14335                    while row != end_row {
14336                        if skip_soft_wrap {
14337                            row = display_map
14338                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14339                                .row();
14340                        } else if above {
14341                            row.0 -= 1;
14342                        } else {
14343                            row.0 += 1;
14344                        }
14345
14346                        if let Some(new_selection) = self.selections.build_columnar_selection(
14347                            &display_map,
14348                            row,
14349                            &positions,
14350                            selection.reversed,
14351                            &text_layout_details,
14352                        ) {
14353                            maybe_new_selection = Some(new_selection);
14354                            break;
14355                        }
14356                    }
14357
14358                    if let Some(new_selection) = maybe_new_selection {
14359                        group.stack.push(new_selection.id);
14360                        if above {
14361                            final_selections.push(new_selection);
14362                            final_selections.push(selection);
14363                        } else {
14364                            final_selections.push(selection);
14365                            final_selections.push(new_selection);
14366                        }
14367                    } else {
14368                        final_selections.push(selection);
14369                    }
14370                } else {
14371                    group.stack.pop();
14372                }
14373            } else {
14374                final_selections.push(selection);
14375            }
14376        }
14377
14378        self.change_selections(Default::default(), window, cx, |s| {
14379            s.select(final_selections);
14380        });
14381
14382        let final_selection_ids: HashSet<_> = self
14383            .selections
14384            .all::<Point>(&display_map)
14385            .iter()
14386            .map(|s| s.id)
14387            .collect();
14388        state.groups.retain_mut(|group| {
14389            // selections might get merged above so we remove invalid items from stacks
14390            group.stack.retain(|id| final_selection_ids.contains(id));
14391
14392            // single selection in stack can be treated as initial state
14393            group.stack.len() > 1
14394        });
14395
14396        if !state.groups.is_empty() {
14397            self.add_selections_state = Some(state);
14398        }
14399    }
14400
14401    fn select_match_ranges(
14402        &mut self,
14403        range: Range<usize>,
14404        reversed: bool,
14405        replace_newest: bool,
14406        auto_scroll: Option<Autoscroll>,
14407        window: &mut Window,
14408        cx: &mut Context<Editor>,
14409    ) {
14410        self.unfold_ranges(
14411            std::slice::from_ref(&range),
14412            false,
14413            auto_scroll.is_some(),
14414            cx,
14415        );
14416        let effects = if let Some(scroll) = auto_scroll {
14417            SelectionEffects::scroll(scroll)
14418        } else {
14419            SelectionEffects::no_scroll()
14420        };
14421        self.change_selections(effects, window, cx, |s| {
14422            if replace_newest {
14423                s.delete(s.newest_anchor().id);
14424            }
14425            if reversed {
14426                s.insert_range(range.end..range.start);
14427            } else {
14428                s.insert_range(range);
14429            }
14430        });
14431    }
14432
14433    pub fn select_next_match_internal(
14434        &mut self,
14435        display_map: &DisplaySnapshot,
14436        replace_newest: bool,
14437        autoscroll: Option<Autoscroll>,
14438        window: &mut Window,
14439        cx: &mut Context<Self>,
14440    ) -> Result<()> {
14441        let buffer = display_map.buffer_snapshot();
14442        let mut selections = self.selections.all::<usize>(&display_map);
14443        if let Some(mut select_next_state) = self.select_next_state.take() {
14444            let query = &select_next_state.query;
14445            if !select_next_state.done {
14446                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14447                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14448                let mut next_selected_range = None;
14449
14450                let bytes_after_last_selection =
14451                    buffer.bytes_in_range(last_selection.end..buffer.len());
14452                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14453                let query_matches = query
14454                    .stream_find_iter(bytes_after_last_selection)
14455                    .map(|result| (last_selection.end, result))
14456                    .chain(
14457                        query
14458                            .stream_find_iter(bytes_before_first_selection)
14459                            .map(|result| (0, result)),
14460                    );
14461
14462                for (start_offset, query_match) in query_matches {
14463                    let query_match = query_match.unwrap(); // can only fail due to I/O
14464                    let offset_range =
14465                        start_offset + query_match.start()..start_offset + query_match.end();
14466
14467                    if !select_next_state.wordwise
14468                        || (!buffer.is_inside_word(offset_range.start, None)
14469                            && !buffer.is_inside_word(offset_range.end, None))
14470                    {
14471                        let idx = selections
14472                            .partition_point(|selection| selection.end <= offset_range.start);
14473                        let overlaps = selections
14474                            .get(idx)
14475                            .map_or(false, |selection| selection.start < offset_range.end);
14476
14477                        if !overlaps {
14478                            next_selected_range = Some(offset_range);
14479                            break;
14480                        }
14481                    }
14482                }
14483
14484                if let Some(next_selected_range) = next_selected_range {
14485                    self.select_match_ranges(
14486                        next_selected_range,
14487                        last_selection.reversed,
14488                        replace_newest,
14489                        autoscroll,
14490                        window,
14491                        cx,
14492                    );
14493                } else {
14494                    select_next_state.done = true;
14495                }
14496            }
14497
14498            self.select_next_state = Some(select_next_state);
14499        } else {
14500            let mut only_carets = true;
14501            let mut same_text_selected = true;
14502            let mut selected_text = None;
14503
14504            let mut selections_iter = selections.iter().peekable();
14505            while let Some(selection) = selections_iter.next() {
14506                if selection.start != selection.end {
14507                    only_carets = false;
14508                }
14509
14510                if same_text_selected {
14511                    if selected_text.is_none() {
14512                        selected_text =
14513                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14514                    }
14515
14516                    if let Some(next_selection) = selections_iter.peek() {
14517                        if next_selection.range().len() == selection.range().len() {
14518                            let next_selected_text = buffer
14519                                .text_for_range(next_selection.range())
14520                                .collect::<String>();
14521                            if Some(next_selected_text) != selected_text {
14522                                same_text_selected = false;
14523                                selected_text = None;
14524                            }
14525                        } else {
14526                            same_text_selected = false;
14527                            selected_text = None;
14528                        }
14529                    }
14530                }
14531            }
14532
14533            if only_carets {
14534                for selection in &mut selections {
14535                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14536                    selection.start = word_range.start;
14537                    selection.end = word_range.end;
14538                    selection.goal = SelectionGoal::None;
14539                    selection.reversed = false;
14540                    self.select_match_ranges(
14541                        selection.start..selection.end,
14542                        selection.reversed,
14543                        replace_newest,
14544                        autoscroll,
14545                        window,
14546                        cx,
14547                    );
14548                }
14549
14550                if selections.len() == 1 {
14551                    let selection = selections
14552                        .last()
14553                        .expect("ensured that there's only one selection");
14554                    let query = buffer
14555                        .text_for_range(selection.start..selection.end)
14556                        .collect::<String>();
14557                    let is_empty = query.is_empty();
14558                    let select_state = SelectNextState {
14559                        query: AhoCorasick::new(&[query])?,
14560                        wordwise: true,
14561                        done: is_empty,
14562                    };
14563                    self.select_next_state = Some(select_state);
14564                } else {
14565                    self.select_next_state = None;
14566                }
14567            } else if let Some(selected_text) = selected_text {
14568                self.select_next_state = Some(SelectNextState {
14569                    query: AhoCorasick::new(&[selected_text])?,
14570                    wordwise: false,
14571                    done: false,
14572                });
14573                self.select_next_match_internal(
14574                    display_map,
14575                    replace_newest,
14576                    autoscroll,
14577                    window,
14578                    cx,
14579                )?;
14580            }
14581        }
14582        Ok(())
14583    }
14584
14585    pub fn select_all_matches(
14586        &mut self,
14587        _action: &SelectAllMatches,
14588        window: &mut Window,
14589        cx: &mut Context<Self>,
14590    ) -> Result<()> {
14591        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14592
14593        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14594
14595        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14596        let Some(select_next_state) = self.select_next_state.as_mut() else {
14597            return Ok(());
14598        };
14599        if select_next_state.done {
14600            return Ok(());
14601        }
14602
14603        let mut new_selections = Vec::new();
14604
14605        let reversed = self.selections.oldest::<usize>(&display_map).reversed;
14606        let buffer = display_map.buffer_snapshot();
14607        let query_matches = select_next_state
14608            .query
14609            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14610
14611        for query_match in query_matches.into_iter() {
14612            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14613            let offset_range = if reversed {
14614                query_match.end()..query_match.start()
14615            } else {
14616                query_match.start()..query_match.end()
14617            };
14618
14619            if !select_next_state.wordwise
14620                || (!buffer.is_inside_word(offset_range.start, None)
14621                    && !buffer.is_inside_word(offset_range.end, None))
14622            {
14623                new_selections.push(offset_range.start..offset_range.end);
14624            }
14625        }
14626
14627        select_next_state.done = true;
14628
14629        if new_selections.is_empty() {
14630            log::error!("bug: new_selections is empty in select_all_matches");
14631            return Ok(());
14632        }
14633
14634        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14635        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14636            selections.select_ranges(new_selections)
14637        });
14638
14639        Ok(())
14640    }
14641
14642    pub fn select_next(
14643        &mut self,
14644        action: &SelectNext,
14645        window: &mut Window,
14646        cx: &mut Context<Self>,
14647    ) -> Result<()> {
14648        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14649        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14650        self.select_next_match_internal(
14651            &display_map,
14652            action.replace_newest,
14653            Some(Autoscroll::newest()),
14654            window,
14655            cx,
14656        )?;
14657        Ok(())
14658    }
14659
14660    pub fn select_previous(
14661        &mut self,
14662        action: &SelectPrevious,
14663        window: &mut Window,
14664        cx: &mut Context<Self>,
14665    ) -> Result<()> {
14666        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14667        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14668        let buffer = display_map.buffer_snapshot();
14669        let mut selections = self.selections.all::<usize>(&display_map);
14670        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14671            let query = &select_prev_state.query;
14672            if !select_prev_state.done {
14673                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14674                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14675                let mut next_selected_range = None;
14676                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14677                let bytes_before_last_selection =
14678                    buffer.reversed_bytes_in_range(0..last_selection.start);
14679                let bytes_after_first_selection =
14680                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14681                let query_matches = query
14682                    .stream_find_iter(bytes_before_last_selection)
14683                    .map(|result| (last_selection.start, result))
14684                    .chain(
14685                        query
14686                            .stream_find_iter(bytes_after_first_selection)
14687                            .map(|result| (buffer.len(), result)),
14688                    );
14689                for (end_offset, query_match) in query_matches {
14690                    let query_match = query_match.unwrap(); // can only fail due to I/O
14691                    let offset_range =
14692                        end_offset - query_match.end()..end_offset - query_match.start();
14693
14694                    if !select_prev_state.wordwise
14695                        || (!buffer.is_inside_word(offset_range.start, None)
14696                            && !buffer.is_inside_word(offset_range.end, None))
14697                    {
14698                        next_selected_range = Some(offset_range);
14699                        break;
14700                    }
14701                }
14702
14703                if let Some(next_selected_range) = next_selected_range {
14704                    self.select_match_ranges(
14705                        next_selected_range,
14706                        last_selection.reversed,
14707                        action.replace_newest,
14708                        Some(Autoscroll::newest()),
14709                        window,
14710                        cx,
14711                    );
14712                } else {
14713                    select_prev_state.done = true;
14714                }
14715            }
14716
14717            self.select_prev_state = Some(select_prev_state);
14718        } else {
14719            let mut only_carets = true;
14720            let mut same_text_selected = true;
14721            let mut selected_text = None;
14722
14723            let mut selections_iter = selections.iter().peekable();
14724            while let Some(selection) = selections_iter.next() {
14725                if selection.start != selection.end {
14726                    only_carets = false;
14727                }
14728
14729                if same_text_selected {
14730                    if selected_text.is_none() {
14731                        selected_text =
14732                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14733                    }
14734
14735                    if let Some(next_selection) = selections_iter.peek() {
14736                        if next_selection.range().len() == selection.range().len() {
14737                            let next_selected_text = buffer
14738                                .text_for_range(next_selection.range())
14739                                .collect::<String>();
14740                            if Some(next_selected_text) != selected_text {
14741                                same_text_selected = false;
14742                                selected_text = None;
14743                            }
14744                        } else {
14745                            same_text_selected = false;
14746                            selected_text = None;
14747                        }
14748                    }
14749                }
14750            }
14751
14752            if only_carets {
14753                for selection in &mut selections {
14754                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14755                    selection.start = word_range.start;
14756                    selection.end = word_range.end;
14757                    selection.goal = SelectionGoal::None;
14758                    selection.reversed = false;
14759                    self.select_match_ranges(
14760                        selection.start..selection.end,
14761                        selection.reversed,
14762                        action.replace_newest,
14763                        Some(Autoscroll::newest()),
14764                        window,
14765                        cx,
14766                    );
14767                }
14768                if selections.len() == 1 {
14769                    let selection = selections
14770                        .last()
14771                        .expect("ensured that there's only one selection");
14772                    let query = buffer
14773                        .text_for_range(selection.start..selection.end)
14774                        .collect::<String>();
14775                    let is_empty = query.is_empty();
14776                    let select_state = SelectNextState {
14777                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14778                        wordwise: true,
14779                        done: is_empty,
14780                    };
14781                    self.select_prev_state = Some(select_state);
14782                } else {
14783                    self.select_prev_state = None;
14784                }
14785            } else if let Some(selected_text) = selected_text {
14786                self.select_prev_state = Some(SelectNextState {
14787                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14788                    wordwise: false,
14789                    done: false,
14790                });
14791                self.select_previous(action, window, cx)?;
14792            }
14793        }
14794        Ok(())
14795    }
14796
14797    pub fn find_next_match(
14798        &mut self,
14799        _: &FindNextMatch,
14800        window: &mut Window,
14801        cx: &mut Context<Self>,
14802    ) -> Result<()> {
14803        let selections = self.selections.disjoint_anchors_arc();
14804        match selections.first() {
14805            Some(first) if selections.len() >= 2 => {
14806                self.change_selections(Default::default(), window, cx, |s| {
14807                    s.select_ranges([first.range()]);
14808                });
14809            }
14810            _ => self.select_next(
14811                &SelectNext {
14812                    replace_newest: true,
14813                },
14814                window,
14815                cx,
14816            )?,
14817        }
14818        Ok(())
14819    }
14820
14821    pub fn find_previous_match(
14822        &mut self,
14823        _: &FindPreviousMatch,
14824        window: &mut Window,
14825        cx: &mut Context<Self>,
14826    ) -> Result<()> {
14827        let selections = self.selections.disjoint_anchors_arc();
14828        match selections.last() {
14829            Some(last) if selections.len() >= 2 => {
14830                self.change_selections(Default::default(), window, cx, |s| {
14831                    s.select_ranges([last.range()]);
14832                });
14833            }
14834            _ => self.select_previous(
14835                &SelectPrevious {
14836                    replace_newest: true,
14837                },
14838                window,
14839                cx,
14840            )?,
14841        }
14842        Ok(())
14843    }
14844
14845    pub fn toggle_comments(
14846        &mut self,
14847        action: &ToggleComments,
14848        window: &mut Window,
14849        cx: &mut Context<Self>,
14850    ) {
14851        if self.read_only(cx) {
14852            return;
14853        }
14854        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14855        let text_layout_details = &self.text_layout_details(window);
14856        self.transact(window, cx, |this, window, cx| {
14857            let mut selections = this
14858                .selections
14859                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
14860            let mut edits = Vec::new();
14861            let mut selection_edit_ranges = Vec::new();
14862            let mut last_toggled_row = None;
14863            let snapshot = this.buffer.read(cx).read(cx);
14864            let empty_str: Arc<str> = Arc::default();
14865            let mut suffixes_inserted = Vec::new();
14866            let ignore_indent = action.ignore_indent;
14867
14868            fn comment_prefix_range(
14869                snapshot: &MultiBufferSnapshot,
14870                row: MultiBufferRow,
14871                comment_prefix: &str,
14872                comment_prefix_whitespace: &str,
14873                ignore_indent: bool,
14874            ) -> Range<Point> {
14875                let indent_size = if ignore_indent {
14876                    0
14877                } else {
14878                    snapshot.indent_size_for_line(row).len
14879                };
14880
14881                let start = Point::new(row.0, indent_size);
14882
14883                let mut line_bytes = snapshot
14884                    .bytes_in_range(start..snapshot.max_point())
14885                    .flatten()
14886                    .copied();
14887
14888                // If this line currently begins with the line comment prefix, then record
14889                // the range containing the prefix.
14890                if line_bytes
14891                    .by_ref()
14892                    .take(comment_prefix.len())
14893                    .eq(comment_prefix.bytes())
14894                {
14895                    // Include any whitespace that matches the comment prefix.
14896                    let matching_whitespace_len = line_bytes
14897                        .zip(comment_prefix_whitespace.bytes())
14898                        .take_while(|(a, b)| a == b)
14899                        .count() as u32;
14900                    let end = Point::new(
14901                        start.row,
14902                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14903                    );
14904                    start..end
14905                } else {
14906                    start..start
14907                }
14908            }
14909
14910            fn comment_suffix_range(
14911                snapshot: &MultiBufferSnapshot,
14912                row: MultiBufferRow,
14913                comment_suffix: &str,
14914                comment_suffix_has_leading_space: bool,
14915            ) -> Range<Point> {
14916                let end = Point::new(row.0, snapshot.line_len(row));
14917                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14918
14919                let mut line_end_bytes = snapshot
14920                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14921                    .flatten()
14922                    .copied();
14923
14924                let leading_space_len = if suffix_start_column > 0
14925                    && line_end_bytes.next() == Some(b' ')
14926                    && comment_suffix_has_leading_space
14927                {
14928                    1
14929                } else {
14930                    0
14931                };
14932
14933                // If this line currently begins with the line comment prefix, then record
14934                // the range containing the prefix.
14935                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14936                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14937                    start..end
14938                } else {
14939                    end..end
14940                }
14941            }
14942
14943            // TODO: Handle selections that cross excerpts
14944            for selection in &mut selections {
14945                let start_column = snapshot
14946                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14947                    .len;
14948                let language = if let Some(language) =
14949                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14950                {
14951                    language
14952                } else {
14953                    continue;
14954                };
14955
14956                selection_edit_ranges.clear();
14957
14958                // If multiple selections contain a given row, avoid processing that
14959                // row more than once.
14960                let mut start_row = MultiBufferRow(selection.start.row);
14961                if last_toggled_row == Some(start_row) {
14962                    start_row = start_row.next_row();
14963                }
14964                let end_row =
14965                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14966                        MultiBufferRow(selection.end.row - 1)
14967                    } else {
14968                        MultiBufferRow(selection.end.row)
14969                    };
14970                last_toggled_row = Some(end_row);
14971
14972                if start_row > end_row {
14973                    continue;
14974                }
14975
14976                // If the language has line comments, toggle those.
14977                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14978
14979                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14980                if ignore_indent {
14981                    full_comment_prefixes = full_comment_prefixes
14982                        .into_iter()
14983                        .map(|s| Arc::from(s.trim_end()))
14984                        .collect();
14985                }
14986
14987                if !full_comment_prefixes.is_empty() {
14988                    let first_prefix = full_comment_prefixes
14989                        .first()
14990                        .expect("prefixes is non-empty");
14991                    let prefix_trimmed_lengths = full_comment_prefixes
14992                        .iter()
14993                        .map(|p| p.trim_end_matches(' ').len())
14994                        .collect::<SmallVec<[usize; 4]>>();
14995
14996                    let mut all_selection_lines_are_comments = true;
14997
14998                    for row in start_row.0..=end_row.0 {
14999                        let row = MultiBufferRow(row);
15000                        if start_row < end_row && snapshot.is_line_blank(row) {
15001                            continue;
15002                        }
15003
15004                        let prefix_range = full_comment_prefixes
15005                            .iter()
15006                            .zip(prefix_trimmed_lengths.iter().copied())
15007                            .map(|(prefix, trimmed_prefix_len)| {
15008                                comment_prefix_range(
15009                                    snapshot.deref(),
15010                                    row,
15011                                    &prefix[..trimmed_prefix_len],
15012                                    &prefix[trimmed_prefix_len..],
15013                                    ignore_indent,
15014                                )
15015                            })
15016                            .max_by_key(|range| range.end.column - range.start.column)
15017                            .expect("prefixes is non-empty");
15018
15019                        if prefix_range.is_empty() {
15020                            all_selection_lines_are_comments = false;
15021                        }
15022
15023                        selection_edit_ranges.push(prefix_range);
15024                    }
15025
15026                    if all_selection_lines_are_comments {
15027                        edits.extend(
15028                            selection_edit_ranges
15029                                .iter()
15030                                .cloned()
15031                                .map(|range| (range, empty_str.clone())),
15032                        );
15033                    } else {
15034                        let min_column = selection_edit_ranges
15035                            .iter()
15036                            .map(|range| range.start.column)
15037                            .min()
15038                            .unwrap_or(0);
15039                        edits.extend(selection_edit_ranges.iter().map(|range| {
15040                            let position = Point::new(range.start.row, min_column);
15041                            (position..position, first_prefix.clone())
15042                        }));
15043                    }
15044                } else if let Some(BlockCommentConfig {
15045                    start: full_comment_prefix,
15046                    end: comment_suffix,
15047                    ..
15048                }) = language.block_comment()
15049                {
15050                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15051                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15052                    let prefix_range = comment_prefix_range(
15053                        snapshot.deref(),
15054                        start_row,
15055                        comment_prefix,
15056                        comment_prefix_whitespace,
15057                        ignore_indent,
15058                    );
15059                    let suffix_range = comment_suffix_range(
15060                        snapshot.deref(),
15061                        end_row,
15062                        comment_suffix.trim_start_matches(' '),
15063                        comment_suffix.starts_with(' '),
15064                    );
15065
15066                    if prefix_range.is_empty() || suffix_range.is_empty() {
15067                        edits.push((
15068                            prefix_range.start..prefix_range.start,
15069                            full_comment_prefix.clone(),
15070                        ));
15071                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15072                        suffixes_inserted.push((end_row, comment_suffix.len()));
15073                    } else {
15074                        edits.push((prefix_range, empty_str.clone()));
15075                        edits.push((suffix_range, empty_str.clone()));
15076                    }
15077                } else {
15078                    continue;
15079                }
15080            }
15081
15082            drop(snapshot);
15083            this.buffer.update(cx, |buffer, cx| {
15084                buffer.edit(edits, None, cx);
15085            });
15086
15087            // Adjust selections so that they end before any comment suffixes that
15088            // were inserted.
15089            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15090            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15091            let snapshot = this.buffer.read(cx).read(cx);
15092            for selection in &mut selections {
15093                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15094                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15095                        Ordering::Less => {
15096                            suffixes_inserted.next();
15097                            continue;
15098                        }
15099                        Ordering::Greater => break,
15100                        Ordering::Equal => {
15101                            if selection.end.column == snapshot.line_len(row) {
15102                                if selection.is_empty() {
15103                                    selection.start.column -= suffix_len as u32;
15104                                }
15105                                selection.end.column -= suffix_len as u32;
15106                            }
15107                            break;
15108                        }
15109                    }
15110                }
15111            }
15112
15113            drop(snapshot);
15114            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15115
15116            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15117            let selections_on_single_row = selections.windows(2).all(|selections| {
15118                selections[0].start.row == selections[1].start.row
15119                    && selections[0].end.row == selections[1].end.row
15120                    && selections[0].start.row == selections[0].end.row
15121            });
15122            let selections_selecting = selections
15123                .iter()
15124                .any(|selection| selection.start != selection.end);
15125            let advance_downwards = action.advance_downwards
15126                && selections_on_single_row
15127                && !selections_selecting
15128                && !matches!(this.mode, EditorMode::SingleLine);
15129
15130            if advance_downwards {
15131                let snapshot = this.buffer.read(cx).snapshot(cx);
15132
15133                this.change_selections(Default::default(), window, cx, |s| {
15134                    s.move_cursors_with(|display_snapshot, display_point, _| {
15135                        let mut point = display_point.to_point(display_snapshot);
15136                        point.row += 1;
15137                        point = snapshot.clip_point(point, Bias::Left);
15138                        let display_point = point.to_display_point(display_snapshot);
15139                        let goal = SelectionGoal::HorizontalPosition(
15140                            display_snapshot
15141                                .x_for_display_point(display_point, text_layout_details)
15142                                .into(),
15143                        );
15144                        (display_point, goal)
15145                    })
15146                });
15147            }
15148        });
15149    }
15150
15151    pub fn select_enclosing_symbol(
15152        &mut self,
15153        _: &SelectEnclosingSymbol,
15154        window: &mut Window,
15155        cx: &mut Context<Self>,
15156    ) {
15157        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15158
15159        let buffer = self.buffer.read(cx).snapshot(cx);
15160        let old_selections = self
15161            .selections
15162            .all::<usize>(&self.display_snapshot(cx))
15163            .into_boxed_slice();
15164
15165        fn update_selection(
15166            selection: &Selection<usize>,
15167            buffer_snap: &MultiBufferSnapshot,
15168        ) -> Option<Selection<usize>> {
15169            let cursor = selection.head();
15170            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15171            for symbol in symbols.iter().rev() {
15172                let start = symbol.range.start.to_offset(buffer_snap);
15173                let end = symbol.range.end.to_offset(buffer_snap);
15174                let new_range = start..end;
15175                if start < selection.start || end > selection.end {
15176                    return Some(Selection {
15177                        id: selection.id,
15178                        start: new_range.start,
15179                        end: new_range.end,
15180                        goal: SelectionGoal::None,
15181                        reversed: selection.reversed,
15182                    });
15183                }
15184            }
15185            None
15186        }
15187
15188        let mut selected_larger_symbol = false;
15189        let new_selections = old_selections
15190            .iter()
15191            .map(|selection| match update_selection(selection, &buffer) {
15192                Some(new_selection) => {
15193                    if new_selection.range() != selection.range() {
15194                        selected_larger_symbol = true;
15195                    }
15196                    new_selection
15197                }
15198                None => selection.clone(),
15199            })
15200            .collect::<Vec<_>>();
15201
15202        if selected_larger_symbol {
15203            self.change_selections(Default::default(), window, cx, |s| {
15204                s.select(new_selections);
15205            });
15206        }
15207    }
15208
15209    pub fn select_larger_syntax_node(
15210        &mut self,
15211        _: &SelectLargerSyntaxNode,
15212        window: &mut Window,
15213        cx: &mut Context<Self>,
15214    ) {
15215        let Some(visible_row_count) = self.visible_row_count() else {
15216            return;
15217        };
15218        let old_selections: Box<[_]> = self
15219            .selections
15220            .all::<usize>(&self.display_snapshot(cx))
15221            .into();
15222        if old_selections.is_empty() {
15223            return;
15224        }
15225
15226        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15227
15228        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15229        let buffer = self.buffer.read(cx).snapshot(cx);
15230
15231        let mut selected_larger_node = false;
15232        let mut new_selections = old_selections
15233            .iter()
15234            .map(|selection| {
15235                let old_range = selection.start..selection.end;
15236
15237                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15238                    // manually select word at selection
15239                    if ["string_content", "inline"].contains(&node.kind()) {
15240                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15241                        // ignore if word is already selected
15242                        if !word_range.is_empty() && old_range != word_range {
15243                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15244                            // only select word if start and end point belongs to same word
15245                            if word_range == last_word_range {
15246                                selected_larger_node = true;
15247                                return Selection {
15248                                    id: selection.id,
15249                                    start: word_range.start,
15250                                    end: word_range.end,
15251                                    goal: SelectionGoal::None,
15252                                    reversed: selection.reversed,
15253                                };
15254                            }
15255                        }
15256                    }
15257                }
15258
15259                let mut new_range = old_range.clone();
15260                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15261                    new_range = range;
15262                    if !node.is_named() {
15263                        continue;
15264                    }
15265                    if !display_map.intersects_fold(new_range.start)
15266                        && !display_map.intersects_fold(new_range.end)
15267                    {
15268                        break;
15269                    }
15270                }
15271
15272                selected_larger_node |= new_range != old_range;
15273                Selection {
15274                    id: selection.id,
15275                    start: new_range.start,
15276                    end: new_range.end,
15277                    goal: SelectionGoal::None,
15278                    reversed: selection.reversed,
15279                }
15280            })
15281            .collect::<Vec<_>>();
15282
15283        if !selected_larger_node {
15284            return; // don't put this call in the history
15285        }
15286
15287        // scroll based on transformation done to the last selection created by the user
15288        let (last_old, last_new) = old_selections
15289            .last()
15290            .zip(new_selections.last().cloned())
15291            .expect("old_selections isn't empty");
15292
15293        // revert selection
15294        let is_selection_reversed = {
15295            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15296            new_selections.last_mut().expect("checked above").reversed =
15297                should_newest_selection_be_reversed;
15298            should_newest_selection_be_reversed
15299        };
15300
15301        if selected_larger_node {
15302            self.select_syntax_node_history.disable_clearing = true;
15303            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15304                s.select(new_selections.clone());
15305            });
15306            self.select_syntax_node_history.disable_clearing = false;
15307        }
15308
15309        let start_row = last_new.start.to_display_point(&display_map).row().0;
15310        let end_row = last_new.end.to_display_point(&display_map).row().0;
15311        let selection_height = end_row - start_row + 1;
15312        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15313
15314        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15315        let scroll_behavior = if fits_on_the_screen {
15316            self.request_autoscroll(Autoscroll::fit(), cx);
15317            SelectSyntaxNodeScrollBehavior::FitSelection
15318        } else if is_selection_reversed {
15319            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15320            SelectSyntaxNodeScrollBehavior::CursorTop
15321        } else {
15322            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15323            SelectSyntaxNodeScrollBehavior::CursorBottom
15324        };
15325
15326        self.select_syntax_node_history.push((
15327            old_selections,
15328            scroll_behavior,
15329            is_selection_reversed,
15330        ));
15331    }
15332
15333    pub fn select_smaller_syntax_node(
15334        &mut self,
15335        _: &SelectSmallerSyntaxNode,
15336        window: &mut Window,
15337        cx: &mut Context<Self>,
15338    ) {
15339        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15340
15341        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15342            self.select_syntax_node_history.pop()
15343        {
15344            if let Some(selection) = selections.last_mut() {
15345                selection.reversed = is_selection_reversed;
15346            }
15347
15348            self.select_syntax_node_history.disable_clearing = true;
15349            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15350                s.select(selections.to_vec());
15351            });
15352            self.select_syntax_node_history.disable_clearing = false;
15353
15354            match scroll_behavior {
15355                SelectSyntaxNodeScrollBehavior::CursorTop => {
15356                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15357                }
15358                SelectSyntaxNodeScrollBehavior::FitSelection => {
15359                    self.request_autoscroll(Autoscroll::fit(), cx);
15360                }
15361                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15362                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15363                }
15364            }
15365        }
15366    }
15367
15368    pub fn unwrap_syntax_node(
15369        &mut self,
15370        _: &UnwrapSyntaxNode,
15371        window: &mut Window,
15372        cx: &mut Context<Self>,
15373    ) {
15374        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15375
15376        let buffer = self.buffer.read(cx).snapshot(cx);
15377        let selections = self
15378            .selections
15379            .all::<usize>(&self.display_snapshot(cx))
15380            .into_iter()
15381            // subtracting the offset requires sorting
15382            .sorted_by_key(|i| i.start);
15383
15384        let full_edits = selections
15385            .into_iter()
15386            .filter_map(|selection| {
15387                let child = if selection.is_empty()
15388                    && let Some((_, ancestor_range)) =
15389                        buffer.syntax_ancestor(selection.start..selection.end)
15390                {
15391                    ancestor_range
15392                } else {
15393                    selection.range()
15394                };
15395
15396                let mut parent = child.clone();
15397                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15398                    parent = ancestor_range;
15399                    if parent.start < child.start || parent.end > child.end {
15400                        break;
15401                    }
15402                }
15403
15404                if parent == child {
15405                    return None;
15406                }
15407                let text = buffer.text_for_range(child).collect::<String>();
15408                Some((selection.id, parent, text))
15409            })
15410            .collect::<Vec<_>>();
15411        if full_edits.is_empty() {
15412            return;
15413        }
15414
15415        self.transact(window, cx, |this, window, cx| {
15416            this.buffer.update(cx, |buffer, cx| {
15417                buffer.edit(
15418                    full_edits
15419                        .iter()
15420                        .map(|(_, p, t)| (p.clone(), t.clone()))
15421                        .collect::<Vec<_>>(),
15422                    None,
15423                    cx,
15424                );
15425            });
15426            this.change_selections(Default::default(), window, cx, |s| {
15427                let mut offset = 0;
15428                let mut selections = vec![];
15429                for (id, parent, text) in full_edits {
15430                    let start = parent.start - offset;
15431                    offset += parent.len() - text.len();
15432                    selections.push(Selection {
15433                        id,
15434                        start,
15435                        end: start + text.len(),
15436                        reversed: false,
15437                        goal: Default::default(),
15438                    });
15439                }
15440                s.select(selections);
15441            });
15442        });
15443    }
15444
15445    pub fn select_next_syntax_node(
15446        &mut self,
15447        _: &SelectNextSyntaxNode,
15448        window: &mut Window,
15449        cx: &mut Context<Self>,
15450    ) {
15451        let old_selections: Box<[_]> = self
15452            .selections
15453            .all::<usize>(&self.display_snapshot(cx))
15454            .into();
15455        if old_selections.is_empty() {
15456            return;
15457        }
15458
15459        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15460
15461        let buffer = self.buffer.read(cx).snapshot(cx);
15462        let mut selected_sibling = false;
15463
15464        let new_selections = old_selections
15465            .iter()
15466            .map(|selection| {
15467                let old_range = selection.start..selection.end;
15468
15469                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15470                    let new_range = node.byte_range();
15471                    selected_sibling = true;
15472                    Selection {
15473                        id: selection.id,
15474                        start: new_range.start,
15475                        end: new_range.end,
15476                        goal: SelectionGoal::None,
15477                        reversed: selection.reversed,
15478                    }
15479                } else {
15480                    selection.clone()
15481                }
15482            })
15483            .collect::<Vec<_>>();
15484
15485        if selected_sibling {
15486            self.change_selections(
15487                SelectionEffects::scroll(Autoscroll::fit()),
15488                window,
15489                cx,
15490                |s| {
15491                    s.select(new_selections);
15492                },
15493            );
15494        }
15495    }
15496
15497    pub fn select_prev_syntax_node(
15498        &mut self,
15499        _: &SelectPreviousSyntaxNode,
15500        window: &mut Window,
15501        cx: &mut Context<Self>,
15502    ) {
15503        let old_selections: Box<[_]> = self
15504            .selections
15505            .all::<usize>(&self.display_snapshot(cx))
15506            .into();
15507        if old_selections.is_empty() {
15508            return;
15509        }
15510
15511        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15512
15513        let buffer = self.buffer.read(cx).snapshot(cx);
15514        let mut selected_sibling = false;
15515
15516        let new_selections = old_selections
15517            .iter()
15518            .map(|selection| {
15519                let old_range = selection.start..selection.end;
15520
15521                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15522                    let new_range = node.byte_range();
15523                    selected_sibling = true;
15524                    Selection {
15525                        id: selection.id,
15526                        start: new_range.start,
15527                        end: new_range.end,
15528                        goal: SelectionGoal::None,
15529                        reversed: selection.reversed,
15530                    }
15531                } else {
15532                    selection.clone()
15533                }
15534            })
15535            .collect::<Vec<_>>();
15536
15537        if selected_sibling {
15538            self.change_selections(
15539                SelectionEffects::scroll(Autoscroll::fit()),
15540                window,
15541                cx,
15542                |s| {
15543                    s.select(new_selections);
15544                },
15545            );
15546        }
15547    }
15548
15549    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15550        if !EditorSettings::get_global(cx).gutter.runnables {
15551            self.clear_tasks();
15552            return Task::ready(());
15553        }
15554        let project = self.project().map(Entity::downgrade);
15555        let task_sources = self.lsp_task_sources(cx);
15556        let multi_buffer = self.buffer.downgrade();
15557        cx.spawn_in(window, async move |editor, cx| {
15558            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15559            let Some(project) = project.and_then(|p| p.upgrade()) else {
15560                return;
15561            };
15562            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15563                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15564            }) else {
15565                return;
15566            };
15567
15568            let hide_runnables = project
15569                .update(cx, |project, _| project.is_via_collab())
15570                .unwrap_or(true);
15571            if hide_runnables {
15572                return;
15573            }
15574            let new_rows =
15575                cx.background_spawn({
15576                    let snapshot = display_snapshot.clone();
15577                    async move {
15578                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15579                    }
15580                })
15581                    .await;
15582            let Ok(lsp_tasks) =
15583                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15584            else {
15585                return;
15586            };
15587            let lsp_tasks = lsp_tasks.await;
15588
15589            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15590                lsp_tasks
15591                    .into_iter()
15592                    .flat_map(|(kind, tasks)| {
15593                        tasks.into_iter().filter_map(move |(location, task)| {
15594                            Some((kind.clone(), location?, task))
15595                        })
15596                    })
15597                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15598                        let buffer = location.target.buffer;
15599                        let buffer_snapshot = buffer.read(cx).snapshot();
15600                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15601                            |(excerpt_id, snapshot, _)| {
15602                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15603                                    display_snapshot
15604                                        .buffer_snapshot()
15605                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15606                                } else {
15607                                    None
15608                                }
15609                            },
15610                        );
15611                        if let Some(offset) = offset {
15612                            let task_buffer_range =
15613                                location.target.range.to_point(&buffer_snapshot);
15614                            let context_buffer_range =
15615                                task_buffer_range.to_offset(&buffer_snapshot);
15616                            let context_range = BufferOffset(context_buffer_range.start)
15617                                ..BufferOffset(context_buffer_range.end);
15618
15619                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15620                                .or_insert_with(|| RunnableTasks {
15621                                    templates: Vec::new(),
15622                                    offset,
15623                                    column: task_buffer_range.start.column,
15624                                    extra_variables: HashMap::default(),
15625                                    context_range,
15626                                })
15627                                .templates
15628                                .push((kind, task.original_task().clone()));
15629                        }
15630
15631                        acc
15632                    })
15633            }) else {
15634                return;
15635            };
15636
15637            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15638                buffer.language_settings(cx).tasks.prefer_lsp
15639            }) else {
15640                return;
15641            };
15642
15643            let rows = Self::runnable_rows(
15644                project,
15645                display_snapshot,
15646                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15647                new_rows,
15648                cx.clone(),
15649            )
15650            .await;
15651            editor
15652                .update(cx, |editor, _| {
15653                    editor.clear_tasks();
15654                    for (key, mut value) in rows {
15655                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15656                            value.templates.extend(lsp_tasks.templates);
15657                        }
15658
15659                        editor.insert_tasks(key, value);
15660                    }
15661                    for (key, value) in lsp_tasks_by_rows {
15662                        editor.insert_tasks(key, value);
15663                    }
15664                })
15665                .ok();
15666        })
15667    }
15668    fn fetch_runnable_ranges(
15669        snapshot: &DisplaySnapshot,
15670        range: Range<Anchor>,
15671    ) -> Vec<language::RunnableRange> {
15672        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15673    }
15674
15675    fn runnable_rows(
15676        project: Entity<Project>,
15677        snapshot: DisplaySnapshot,
15678        prefer_lsp: bool,
15679        runnable_ranges: Vec<RunnableRange>,
15680        cx: AsyncWindowContext,
15681    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15682        cx.spawn(async move |cx| {
15683            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15684            for mut runnable in runnable_ranges {
15685                let Some(tasks) = cx
15686                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15687                    .ok()
15688                else {
15689                    continue;
15690                };
15691                let mut tasks = tasks.await;
15692
15693                if prefer_lsp {
15694                    tasks.retain(|(task_kind, _)| {
15695                        !matches!(task_kind, TaskSourceKind::Language { .. })
15696                    });
15697                }
15698                if tasks.is_empty() {
15699                    continue;
15700                }
15701
15702                let point = runnable
15703                    .run_range
15704                    .start
15705                    .to_point(&snapshot.buffer_snapshot());
15706                let Some(row) = snapshot
15707                    .buffer_snapshot()
15708                    .buffer_line_for_row(MultiBufferRow(point.row))
15709                    .map(|(_, range)| range.start.row)
15710                else {
15711                    continue;
15712                };
15713
15714                let context_range =
15715                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15716                runnable_rows.push((
15717                    (runnable.buffer_id, row),
15718                    RunnableTasks {
15719                        templates: tasks,
15720                        offset: snapshot
15721                            .buffer_snapshot()
15722                            .anchor_before(runnable.run_range.start),
15723                        context_range,
15724                        column: point.column,
15725                        extra_variables: runnable.extra_captures,
15726                    },
15727                ));
15728            }
15729            runnable_rows
15730        })
15731    }
15732
15733    fn templates_with_tags(
15734        project: &Entity<Project>,
15735        runnable: &mut Runnable,
15736        cx: &mut App,
15737    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15738        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15739            let (worktree_id, file) = project
15740                .buffer_for_id(runnable.buffer, cx)
15741                .and_then(|buffer| buffer.read(cx).file())
15742                .map(|file| (file.worktree_id(cx), file.clone()))
15743                .unzip();
15744
15745            (
15746                project.task_store().read(cx).task_inventory().cloned(),
15747                worktree_id,
15748                file,
15749            )
15750        });
15751
15752        let tags = mem::take(&mut runnable.tags);
15753        let language = runnable.language.clone();
15754        cx.spawn(async move |cx| {
15755            let mut templates_with_tags = Vec::new();
15756            if let Some(inventory) = inventory {
15757                for RunnableTag(tag) in tags {
15758                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15759                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15760                    }) else {
15761                        return templates_with_tags;
15762                    };
15763                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15764                        move |(_, template)| {
15765                            template.tags.iter().any(|source_tag| source_tag == &tag)
15766                        },
15767                    ));
15768                }
15769            }
15770            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15771
15772            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15773                // Strongest source wins; if we have worktree tag binding, prefer that to
15774                // global and language bindings;
15775                // if we have a global binding, prefer that to language binding.
15776                let first_mismatch = templates_with_tags
15777                    .iter()
15778                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15779                if let Some(index) = first_mismatch {
15780                    templates_with_tags.truncate(index);
15781                }
15782            }
15783
15784            templates_with_tags
15785        })
15786    }
15787
15788    pub fn move_to_enclosing_bracket(
15789        &mut self,
15790        _: &MoveToEnclosingBracket,
15791        window: &mut Window,
15792        cx: &mut Context<Self>,
15793    ) {
15794        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15795        self.change_selections(Default::default(), window, cx, |s| {
15796            s.move_offsets_with(|snapshot, selection| {
15797                let Some(enclosing_bracket_ranges) =
15798                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15799                else {
15800                    return;
15801                };
15802
15803                let mut best_length = usize::MAX;
15804                let mut best_inside = false;
15805                let mut best_in_bracket_range = false;
15806                let mut best_destination = None;
15807                for (open, close) in enclosing_bracket_ranges {
15808                    let close = close.to_inclusive();
15809                    let length = close.end() - open.start;
15810                    let inside = selection.start >= open.end && selection.end <= *close.start();
15811                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15812                        || close.contains(&selection.head());
15813
15814                    // If best is next to a bracket and current isn't, skip
15815                    if !in_bracket_range && best_in_bracket_range {
15816                        continue;
15817                    }
15818
15819                    // Prefer smaller lengths unless best is inside and current isn't
15820                    if length > best_length && (best_inside || !inside) {
15821                        continue;
15822                    }
15823
15824                    best_length = length;
15825                    best_inside = inside;
15826                    best_in_bracket_range = in_bracket_range;
15827                    best_destination = Some(
15828                        if close.contains(&selection.start) && close.contains(&selection.end) {
15829                            if inside { open.end } else { open.start }
15830                        } else if inside {
15831                            *close.start()
15832                        } else {
15833                            *close.end()
15834                        },
15835                    );
15836                }
15837
15838                if let Some(destination) = best_destination {
15839                    selection.collapse_to(destination, SelectionGoal::None);
15840                }
15841            })
15842        });
15843    }
15844
15845    pub fn undo_selection(
15846        &mut self,
15847        _: &UndoSelection,
15848        window: &mut Window,
15849        cx: &mut Context<Self>,
15850    ) {
15851        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15852        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15853            self.selection_history.mode = SelectionHistoryMode::Undoing;
15854            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15855                this.end_selection(window, cx);
15856                this.change_selections(
15857                    SelectionEffects::scroll(Autoscroll::newest()),
15858                    window,
15859                    cx,
15860                    |s| s.select_anchors(entry.selections.to_vec()),
15861                );
15862            });
15863            self.selection_history.mode = SelectionHistoryMode::Normal;
15864
15865            self.select_next_state = entry.select_next_state;
15866            self.select_prev_state = entry.select_prev_state;
15867            self.add_selections_state = entry.add_selections_state;
15868        }
15869    }
15870
15871    pub fn redo_selection(
15872        &mut self,
15873        _: &RedoSelection,
15874        window: &mut Window,
15875        cx: &mut Context<Self>,
15876    ) {
15877        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15878        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15879            self.selection_history.mode = SelectionHistoryMode::Redoing;
15880            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15881                this.end_selection(window, cx);
15882                this.change_selections(
15883                    SelectionEffects::scroll(Autoscroll::newest()),
15884                    window,
15885                    cx,
15886                    |s| s.select_anchors(entry.selections.to_vec()),
15887                );
15888            });
15889            self.selection_history.mode = SelectionHistoryMode::Normal;
15890
15891            self.select_next_state = entry.select_next_state;
15892            self.select_prev_state = entry.select_prev_state;
15893            self.add_selections_state = entry.add_selections_state;
15894        }
15895    }
15896
15897    pub fn expand_excerpts(
15898        &mut self,
15899        action: &ExpandExcerpts,
15900        _: &mut Window,
15901        cx: &mut Context<Self>,
15902    ) {
15903        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15904    }
15905
15906    pub fn expand_excerpts_down(
15907        &mut self,
15908        action: &ExpandExcerptsDown,
15909        _: &mut Window,
15910        cx: &mut Context<Self>,
15911    ) {
15912        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15913    }
15914
15915    pub fn expand_excerpts_up(
15916        &mut self,
15917        action: &ExpandExcerptsUp,
15918        _: &mut Window,
15919        cx: &mut Context<Self>,
15920    ) {
15921        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15922    }
15923
15924    pub fn expand_excerpts_for_direction(
15925        &mut self,
15926        lines: u32,
15927        direction: ExpandExcerptDirection,
15928
15929        cx: &mut Context<Self>,
15930    ) {
15931        let selections = self.selections.disjoint_anchors_arc();
15932
15933        let lines = if lines == 0 {
15934            EditorSettings::get_global(cx).expand_excerpt_lines
15935        } else {
15936            lines
15937        };
15938
15939        self.buffer.update(cx, |buffer, cx| {
15940            let snapshot = buffer.snapshot(cx);
15941            let mut excerpt_ids = selections
15942                .iter()
15943                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15944                .collect::<Vec<_>>();
15945            excerpt_ids.sort();
15946            excerpt_ids.dedup();
15947            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15948        })
15949    }
15950
15951    pub fn expand_excerpt(
15952        &mut self,
15953        excerpt: ExcerptId,
15954        direction: ExpandExcerptDirection,
15955        window: &mut Window,
15956        cx: &mut Context<Self>,
15957    ) {
15958        let current_scroll_position = self.scroll_position(cx);
15959        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15960        let mut scroll = None;
15961
15962        if direction == ExpandExcerptDirection::Down {
15963            let multi_buffer = self.buffer.read(cx);
15964            let snapshot = multi_buffer.snapshot(cx);
15965            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15966                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15967                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
15968            {
15969                let buffer_snapshot = buffer.read(cx).snapshot();
15970                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15971                let last_row = buffer_snapshot.max_point().row;
15972                let lines_below = last_row.saturating_sub(excerpt_end_row);
15973                if lines_below >= lines_to_expand {
15974                    scroll = Some(
15975                        current_scroll_position
15976                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
15977                    );
15978                }
15979            }
15980        }
15981        if direction == ExpandExcerptDirection::Up
15982            && self
15983                .buffer
15984                .read(cx)
15985                .snapshot(cx)
15986                .excerpt_before(excerpt)
15987                .is_none()
15988        {
15989            scroll = Some(current_scroll_position);
15990        }
15991
15992        self.buffer.update(cx, |buffer, cx| {
15993            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15994        });
15995
15996        if let Some(new_scroll_position) = scroll {
15997            self.set_scroll_position(new_scroll_position, window, cx);
15998        }
15999    }
16000
16001    pub fn go_to_singleton_buffer_point(
16002        &mut self,
16003        point: Point,
16004        window: &mut Window,
16005        cx: &mut Context<Self>,
16006    ) {
16007        self.go_to_singleton_buffer_range(point..point, window, cx);
16008    }
16009
16010    pub fn go_to_singleton_buffer_range(
16011        &mut self,
16012        range: Range<Point>,
16013        window: &mut Window,
16014        cx: &mut Context<Self>,
16015    ) {
16016        let multibuffer = self.buffer().read(cx);
16017        let Some(buffer) = multibuffer.as_singleton() else {
16018            return;
16019        };
16020        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16021            return;
16022        };
16023        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16024            return;
16025        };
16026        self.change_selections(
16027            SelectionEffects::default().nav_history(true),
16028            window,
16029            cx,
16030            |s| s.select_anchor_ranges([start..end]),
16031        );
16032    }
16033
16034    pub fn go_to_diagnostic(
16035        &mut self,
16036        action: &GoToDiagnostic,
16037        window: &mut Window,
16038        cx: &mut Context<Self>,
16039    ) {
16040        if !self.diagnostics_enabled() {
16041            return;
16042        }
16043        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16044        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16045    }
16046
16047    pub fn go_to_prev_diagnostic(
16048        &mut self,
16049        action: &GoToPreviousDiagnostic,
16050        window: &mut Window,
16051        cx: &mut Context<Self>,
16052    ) {
16053        if !self.diagnostics_enabled() {
16054            return;
16055        }
16056        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16057        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16058    }
16059
16060    pub fn go_to_diagnostic_impl(
16061        &mut self,
16062        direction: Direction,
16063        severity: GoToDiagnosticSeverityFilter,
16064        window: &mut Window,
16065        cx: &mut Context<Self>,
16066    ) {
16067        let buffer = self.buffer.read(cx).snapshot(cx);
16068        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
16069
16070        let mut active_group_id = None;
16071        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16072            && active_group.active_range.start.to_offset(&buffer) == selection.start
16073        {
16074            active_group_id = Some(active_group.group_id);
16075        }
16076
16077        fn filtered<'a>(
16078            severity: GoToDiagnosticSeverityFilter,
16079            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
16080        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
16081            diagnostics
16082                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16083                .filter(|entry| entry.range.start != entry.range.end)
16084                .filter(|entry| !entry.diagnostic.is_unnecessary)
16085        }
16086
16087        let before = filtered(
16088            severity,
16089            buffer
16090                .diagnostics_in_range(0..selection.start)
16091                .filter(|entry| entry.range.start <= selection.start),
16092        );
16093        let after = filtered(
16094            severity,
16095            buffer
16096                .diagnostics_in_range(selection.start..buffer.len())
16097                .filter(|entry| entry.range.start >= selection.start),
16098        );
16099
16100        let mut found: Option<DiagnosticEntryRef<usize>> = None;
16101        if direction == Direction::Prev {
16102            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16103            {
16104                for diagnostic in prev_diagnostics.into_iter().rev() {
16105                    if diagnostic.range.start != selection.start
16106                        || active_group_id
16107                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16108                    {
16109                        found = Some(diagnostic);
16110                        break 'outer;
16111                    }
16112                }
16113            }
16114        } else {
16115            for diagnostic in after.chain(before) {
16116                if diagnostic.range.start != selection.start
16117                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16118                {
16119                    found = Some(diagnostic);
16120                    break;
16121                }
16122            }
16123        }
16124        let Some(next_diagnostic) = found else {
16125            return;
16126        };
16127
16128        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16129        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16130            return;
16131        };
16132        let snapshot = self.snapshot(window, cx);
16133        if snapshot.intersects_fold(next_diagnostic.range.start) {
16134            self.unfold_ranges(
16135                std::slice::from_ref(&next_diagnostic.range),
16136                true,
16137                false,
16138                cx,
16139            );
16140        }
16141        self.change_selections(Default::default(), window, cx, |s| {
16142            s.select_ranges(vec![
16143                next_diagnostic.range.start..next_diagnostic.range.start,
16144            ])
16145        });
16146        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16147        self.refresh_edit_prediction(false, true, window, cx);
16148    }
16149
16150    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16151        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16152        let snapshot = self.snapshot(window, cx);
16153        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16154        self.go_to_hunk_before_or_after_position(
16155            &snapshot,
16156            selection.head(),
16157            Direction::Next,
16158            window,
16159            cx,
16160        );
16161    }
16162
16163    pub fn go_to_hunk_before_or_after_position(
16164        &mut self,
16165        snapshot: &EditorSnapshot,
16166        position: Point,
16167        direction: Direction,
16168        window: &mut Window,
16169        cx: &mut Context<Editor>,
16170    ) {
16171        let row = if direction == Direction::Next {
16172            self.hunk_after_position(snapshot, position)
16173                .map(|hunk| hunk.row_range.start)
16174        } else {
16175            self.hunk_before_position(snapshot, position)
16176        };
16177
16178        if let Some(row) = row {
16179            let destination = Point::new(row.0, 0);
16180            let autoscroll = Autoscroll::center();
16181
16182            self.unfold_ranges(&[destination..destination], false, false, cx);
16183            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16184                s.select_ranges([destination..destination]);
16185            });
16186        }
16187    }
16188
16189    fn hunk_after_position(
16190        &mut self,
16191        snapshot: &EditorSnapshot,
16192        position: Point,
16193    ) -> Option<MultiBufferDiffHunk> {
16194        snapshot
16195            .buffer_snapshot()
16196            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16197            .find(|hunk| hunk.row_range.start.0 > position.row)
16198            .or_else(|| {
16199                snapshot
16200                    .buffer_snapshot()
16201                    .diff_hunks_in_range(Point::zero()..position)
16202                    .find(|hunk| hunk.row_range.end.0 < position.row)
16203            })
16204    }
16205
16206    fn go_to_prev_hunk(
16207        &mut self,
16208        _: &GoToPreviousHunk,
16209        window: &mut Window,
16210        cx: &mut Context<Self>,
16211    ) {
16212        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16213        let snapshot = self.snapshot(window, cx);
16214        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16215        self.go_to_hunk_before_or_after_position(
16216            &snapshot,
16217            selection.head(),
16218            Direction::Prev,
16219            window,
16220            cx,
16221        );
16222    }
16223
16224    fn hunk_before_position(
16225        &mut self,
16226        snapshot: &EditorSnapshot,
16227        position: Point,
16228    ) -> Option<MultiBufferRow> {
16229        snapshot
16230            .buffer_snapshot()
16231            .diff_hunk_before(position)
16232            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16233    }
16234
16235    fn go_to_next_change(
16236        &mut self,
16237        _: &GoToNextChange,
16238        window: &mut Window,
16239        cx: &mut Context<Self>,
16240    ) {
16241        if let Some(selections) = self
16242            .change_list
16243            .next_change(1, Direction::Next)
16244            .map(|s| s.to_vec())
16245        {
16246            self.change_selections(Default::default(), window, cx, |s| {
16247                let map = s.display_map();
16248                s.select_display_ranges(selections.iter().map(|a| {
16249                    let point = a.to_display_point(&map);
16250                    point..point
16251                }))
16252            })
16253        }
16254    }
16255
16256    fn go_to_previous_change(
16257        &mut self,
16258        _: &GoToPreviousChange,
16259        window: &mut Window,
16260        cx: &mut Context<Self>,
16261    ) {
16262        if let Some(selections) = self
16263            .change_list
16264            .next_change(1, Direction::Prev)
16265            .map(|s| s.to_vec())
16266        {
16267            self.change_selections(Default::default(), window, cx, |s| {
16268                let map = s.display_map();
16269                s.select_display_ranges(selections.iter().map(|a| {
16270                    let point = a.to_display_point(&map);
16271                    point..point
16272                }))
16273            })
16274        }
16275    }
16276
16277    pub fn go_to_next_document_highlight(
16278        &mut self,
16279        _: &GoToNextDocumentHighlight,
16280        window: &mut Window,
16281        cx: &mut Context<Self>,
16282    ) {
16283        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16284    }
16285
16286    pub fn go_to_prev_document_highlight(
16287        &mut self,
16288        _: &GoToPreviousDocumentHighlight,
16289        window: &mut Window,
16290        cx: &mut Context<Self>,
16291    ) {
16292        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16293    }
16294
16295    pub fn go_to_document_highlight_before_or_after_position(
16296        &mut self,
16297        direction: Direction,
16298        window: &mut Window,
16299        cx: &mut Context<Editor>,
16300    ) {
16301        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16302        let snapshot = self.snapshot(window, cx);
16303        let buffer = &snapshot.buffer_snapshot();
16304        let position = self
16305            .selections
16306            .newest::<Point>(&snapshot.display_snapshot)
16307            .head();
16308        let anchor_position = buffer.anchor_after(position);
16309
16310        // Get all document highlights (both read and write)
16311        let mut all_highlights = Vec::new();
16312
16313        if let Some((_, read_highlights)) = self
16314            .background_highlights
16315            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16316        {
16317            all_highlights.extend(read_highlights.iter());
16318        }
16319
16320        if let Some((_, write_highlights)) = self
16321            .background_highlights
16322            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16323        {
16324            all_highlights.extend(write_highlights.iter());
16325        }
16326
16327        if all_highlights.is_empty() {
16328            return;
16329        }
16330
16331        // Sort highlights by position
16332        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16333
16334        let target_highlight = match direction {
16335            Direction::Next => {
16336                // Find the first highlight after the current position
16337                all_highlights
16338                    .iter()
16339                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16340            }
16341            Direction::Prev => {
16342                // Find the last highlight before the current position
16343                all_highlights
16344                    .iter()
16345                    .rev()
16346                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16347            }
16348        };
16349
16350        if let Some(highlight) = target_highlight {
16351            let destination = highlight.start.to_point(buffer);
16352            let autoscroll = Autoscroll::center();
16353
16354            self.unfold_ranges(&[destination..destination], false, false, cx);
16355            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16356                s.select_ranges([destination..destination]);
16357            });
16358        }
16359    }
16360
16361    fn go_to_line<T: 'static>(
16362        &mut self,
16363        position: Anchor,
16364        highlight_color: Option<Hsla>,
16365        window: &mut Window,
16366        cx: &mut Context<Self>,
16367    ) {
16368        let snapshot = self.snapshot(window, cx).display_snapshot;
16369        let position = position.to_point(&snapshot.buffer_snapshot());
16370        let start = snapshot
16371            .buffer_snapshot()
16372            .clip_point(Point::new(position.row, 0), Bias::Left);
16373        let end = start + Point::new(1, 0);
16374        let start = snapshot.buffer_snapshot().anchor_before(start);
16375        let end = snapshot.buffer_snapshot().anchor_before(end);
16376
16377        self.highlight_rows::<T>(
16378            start..end,
16379            highlight_color
16380                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16381            Default::default(),
16382            cx,
16383        );
16384
16385        if self.buffer.read(cx).is_singleton() {
16386            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16387        }
16388    }
16389
16390    pub fn go_to_definition(
16391        &mut self,
16392        _: &GoToDefinition,
16393        window: &mut Window,
16394        cx: &mut Context<Self>,
16395    ) -> Task<Result<Navigated>> {
16396        let definition =
16397            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16398        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16399        cx.spawn_in(window, async move |editor, cx| {
16400            if definition.await? == Navigated::Yes {
16401                return Ok(Navigated::Yes);
16402            }
16403            match fallback_strategy {
16404                GoToDefinitionFallback::None => Ok(Navigated::No),
16405                GoToDefinitionFallback::FindAllReferences => {
16406                    match editor.update_in(cx, |editor, window, cx| {
16407                        editor.find_all_references(&FindAllReferences, window, cx)
16408                    })? {
16409                        Some(references) => references.await,
16410                        None => Ok(Navigated::No),
16411                    }
16412                }
16413            }
16414        })
16415    }
16416
16417    pub fn go_to_declaration(
16418        &mut self,
16419        _: &GoToDeclaration,
16420        window: &mut Window,
16421        cx: &mut Context<Self>,
16422    ) -> Task<Result<Navigated>> {
16423        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16424    }
16425
16426    pub fn go_to_declaration_split(
16427        &mut self,
16428        _: &GoToDeclaration,
16429        window: &mut Window,
16430        cx: &mut Context<Self>,
16431    ) -> Task<Result<Navigated>> {
16432        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16433    }
16434
16435    pub fn go_to_implementation(
16436        &mut self,
16437        _: &GoToImplementation,
16438        window: &mut Window,
16439        cx: &mut Context<Self>,
16440    ) -> Task<Result<Navigated>> {
16441        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16442    }
16443
16444    pub fn go_to_implementation_split(
16445        &mut self,
16446        _: &GoToImplementationSplit,
16447        window: &mut Window,
16448        cx: &mut Context<Self>,
16449    ) -> Task<Result<Navigated>> {
16450        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16451    }
16452
16453    pub fn go_to_type_definition(
16454        &mut self,
16455        _: &GoToTypeDefinition,
16456        window: &mut Window,
16457        cx: &mut Context<Self>,
16458    ) -> Task<Result<Navigated>> {
16459        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16460    }
16461
16462    pub fn go_to_definition_split(
16463        &mut self,
16464        _: &GoToDefinitionSplit,
16465        window: &mut Window,
16466        cx: &mut Context<Self>,
16467    ) -> Task<Result<Navigated>> {
16468        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16469    }
16470
16471    pub fn go_to_type_definition_split(
16472        &mut self,
16473        _: &GoToTypeDefinitionSplit,
16474        window: &mut Window,
16475        cx: &mut Context<Self>,
16476    ) -> Task<Result<Navigated>> {
16477        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16478    }
16479
16480    fn go_to_definition_of_kind(
16481        &mut self,
16482        kind: GotoDefinitionKind,
16483        split: bool,
16484        window: &mut Window,
16485        cx: &mut Context<Self>,
16486    ) -> Task<Result<Navigated>> {
16487        let Some(provider) = self.semantics_provider.clone() else {
16488            return Task::ready(Ok(Navigated::No));
16489        };
16490        let head = self
16491            .selections
16492            .newest::<usize>(&self.display_snapshot(cx))
16493            .head();
16494        let buffer = self.buffer.read(cx);
16495        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16496            return Task::ready(Ok(Navigated::No));
16497        };
16498        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16499            return Task::ready(Ok(Navigated::No));
16500        };
16501
16502        cx.spawn_in(window, async move |editor, cx| {
16503            let Some(definitions) = definitions.await? else {
16504                return Ok(Navigated::No);
16505            };
16506            let navigated = editor
16507                .update_in(cx, |editor, window, cx| {
16508                    editor.navigate_to_hover_links(
16509                        Some(kind),
16510                        definitions
16511                            .into_iter()
16512                            .filter(|location| {
16513                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16514                            })
16515                            .map(HoverLink::Text)
16516                            .collect::<Vec<_>>(),
16517                        split,
16518                        window,
16519                        cx,
16520                    )
16521                })?
16522                .await?;
16523            anyhow::Ok(navigated)
16524        })
16525    }
16526
16527    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16528        let selection = self.selections.newest_anchor();
16529        let head = selection.head();
16530        let tail = selection.tail();
16531
16532        let Some((buffer, start_position)) =
16533            self.buffer.read(cx).text_anchor_for_position(head, cx)
16534        else {
16535            return;
16536        };
16537
16538        let end_position = if head != tail {
16539            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16540                return;
16541            };
16542            Some(pos)
16543        } else {
16544            None
16545        };
16546
16547        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16548            let url = if let Some(end_pos) = end_position {
16549                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16550            } else {
16551                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16552            };
16553
16554            if let Some(url) = url {
16555                cx.update(|window, cx| {
16556                    if parse_zed_link(&url, cx).is_some() {
16557                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16558                    } else {
16559                        cx.open_url(&url);
16560                    }
16561                })?;
16562            }
16563
16564            anyhow::Ok(())
16565        });
16566
16567        url_finder.detach();
16568    }
16569
16570    pub fn open_selected_filename(
16571        &mut self,
16572        _: &OpenSelectedFilename,
16573        window: &mut Window,
16574        cx: &mut Context<Self>,
16575    ) {
16576        let Some(workspace) = self.workspace() else {
16577            return;
16578        };
16579
16580        let position = self.selections.newest_anchor().head();
16581
16582        let Some((buffer, buffer_position)) =
16583            self.buffer.read(cx).text_anchor_for_position(position, cx)
16584        else {
16585            return;
16586        };
16587
16588        let project = self.project.clone();
16589
16590        cx.spawn_in(window, async move |_, cx| {
16591            let result = find_file(&buffer, project, buffer_position, cx).await;
16592
16593            if let Some((_, path)) = result {
16594                workspace
16595                    .update_in(cx, |workspace, window, cx| {
16596                        workspace.open_resolved_path(path, window, cx)
16597                    })?
16598                    .await?;
16599            }
16600            anyhow::Ok(())
16601        })
16602        .detach();
16603    }
16604
16605    pub(crate) fn navigate_to_hover_links(
16606        &mut self,
16607        kind: Option<GotoDefinitionKind>,
16608        definitions: Vec<HoverLink>,
16609        split: bool,
16610        window: &mut Window,
16611        cx: &mut Context<Editor>,
16612    ) -> Task<Result<Navigated>> {
16613        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16614        let mut first_url_or_file = None;
16615        let definitions: Vec<_> = definitions
16616            .into_iter()
16617            .filter_map(|def| match def {
16618                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16619                HoverLink::InlayHint(lsp_location, server_id) => {
16620                    let computation =
16621                        self.compute_target_location(lsp_location, server_id, window, cx);
16622                    Some(cx.background_spawn(computation))
16623                }
16624                HoverLink::Url(url) => {
16625                    first_url_or_file = Some(Either::Left(url));
16626                    None
16627                }
16628                HoverLink::File(path) => {
16629                    first_url_or_file = Some(Either::Right(path));
16630                    None
16631                }
16632            })
16633            .collect();
16634
16635        let workspace = self.workspace();
16636
16637        cx.spawn_in(window, async move |editor, cx| {
16638            let locations: Vec<Location> = future::join_all(definitions)
16639                .await
16640                .into_iter()
16641                .filter_map(|location| location.transpose())
16642                .collect::<Result<_>>()
16643                .context("location tasks")?;
16644            let mut locations = cx.update(|_, cx| {
16645                locations
16646                    .into_iter()
16647                    .map(|location| {
16648                        let buffer = location.buffer.read(cx);
16649                        (location.buffer, location.range.to_point(buffer))
16650                    })
16651                    .into_group_map()
16652            })?;
16653            let mut num_locations = 0;
16654            for ranges in locations.values_mut() {
16655                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16656                ranges.dedup();
16657                num_locations += ranges.len();
16658            }
16659
16660            if num_locations > 1 {
16661                let Some(workspace) = workspace else {
16662                    return Ok(Navigated::No);
16663                };
16664
16665                let tab_kind = match kind {
16666                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16667                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16668                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16669                    Some(GotoDefinitionKind::Type) => "Types",
16670                };
16671                let title = editor
16672                    .update_in(cx, |_, _, cx| {
16673                        let target = locations
16674                            .iter()
16675                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16676                            .map(|(buffer, location)| {
16677                                buffer
16678                                    .read(cx)
16679                                    .text_for_range(location.clone())
16680                                    .collect::<String>()
16681                            })
16682                            .filter(|text| !text.contains('\n'))
16683                            .unique()
16684                            .take(3)
16685                            .join(", ");
16686                        if target.is_empty() {
16687                            tab_kind.to_owned()
16688                        } else {
16689                            format!("{tab_kind} for {target}")
16690                        }
16691                    })
16692                    .context("buffer title")?;
16693
16694                let opened = workspace
16695                    .update_in(cx, |workspace, window, cx| {
16696                        Self::open_locations_in_multibuffer(
16697                            workspace,
16698                            locations,
16699                            title,
16700                            split,
16701                            MultibufferSelectionMode::First,
16702                            window,
16703                            cx,
16704                        )
16705                    })
16706                    .is_ok();
16707
16708                anyhow::Ok(Navigated::from_bool(opened))
16709            } else if num_locations == 0 {
16710                // If there is one url or file, open it directly
16711                match first_url_or_file {
16712                    Some(Either::Left(url)) => {
16713                        cx.update(|_, cx| cx.open_url(&url))?;
16714                        Ok(Navigated::Yes)
16715                    }
16716                    Some(Either::Right(path)) => {
16717                        let Some(workspace) = workspace else {
16718                            return Ok(Navigated::No);
16719                        };
16720
16721                        workspace
16722                            .update_in(cx, |workspace, window, cx| {
16723                                workspace.open_resolved_path(path, window, cx)
16724                            })?
16725                            .await?;
16726                        Ok(Navigated::Yes)
16727                    }
16728                    None => Ok(Navigated::No),
16729                }
16730            } else {
16731                let Some(workspace) = workspace else {
16732                    return Ok(Navigated::No);
16733                };
16734
16735                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16736                let target_range = target_ranges.first().unwrap().clone();
16737
16738                editor.update_in(cx, |editor, window, cx| {
16739                    let range = target_range.to_point(target_buffer.read(cx));
16740                    let range = editor.range_for_match(&range, false);
16741                    let range = collapse_multiline_range(range);
16742
16743                    if !split
16744                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16745                    {
16746                        editor.go_to_singleton_buffer_range(range, window, cx);
16747                    } else {
16748                        let pane = workspace.read(cx).active_pane().clone();
16749                        window.defer(cx, move |window, cx| {
16750                            let target_editor: Entity<Self> =
16751                                workspace.update(cx, |workspace, cx| {
16752                                    let pane = if split {
16753                                        workspace.adjacent_pane(window, cx)
16754                                    } else {
16755                                        workspace.active_pane().clone()
16756                                    };
16757
16758                                    workspace.open_project_item(
16759                                        pane,
16760                                        target_buffer.clone(),
16761                                        true,
16762                                        true,
16763                                        window,
16764                                        cx,
16765                                    )
16766                                });
16767                            target_editor.update(cx, |target_editor, cx| {
16768                                // When selecting a definition in a different buffer, disable the nav history
16769                                // to avoid creating a history entry at the previous cursor location.
16770                                pane.update(cx, |pane, _| pane.disable_history());
16771                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16772                                pane.update(cx, |pane, _| pane.enable_history());
16773                            });
16774                        });
16775                    }
16776                    Navigated::Yes
16777                })
16778            }
16779        })
16780    }
16781
16782    fn compute_target_location(
16783        &self,
16784        lsp_location: lsp::Location,
16785        server_id: LanguageServerId,
16786        window: &mut Window,
16787        cx: &mut Context<Self>,
16788    ) -> Task<anyhow::Result<Option<Location>>> {
16789        let Some(project) = self.project.clone() else {
16790            return Task::ready(Ok(None));
16791        };
16792
16793        cx.spawn_in(window, async move |editor, cx| {
16794            let location_task = editor.update(cx, |_, cx| {
16795                project.update(cx, |project, cx| {
16796                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16797                })
16798            })?;
16799            let location = Some({
16800                let target_buffer_handle = location_task.await.context("open local buffer")?;
16801                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16802                    let target_start = target_buffer
16803                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16804                    let target_end = target_buffer
16805                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16806                    target_buffer.anchor_after(target_start)
16807                        ..target_buffer.anchor_before(target_end)
16808                })?;
16809                Location {
16810                    buffer: target_buffer_handle,
16811                    range,
16812                }
16813            });
16814            Ok(location)
16815        })
16816    }
16817
16818    fn go_to_next_reference(
16819        &mut self,
16820        _: &GoToNextReference,
16821        window: &mut Window,
16822        cx: &mut Context<Self>,
16823    ) {
16824        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
16825        if let Some(task) = task {
16826            task.detach();
16827        };
16828    }
16829
16830    fn go_to_prev_reference(
16831        &mut self,
16832        _: &GoToPreviousReference,
16833        window: &mut Window,
16834        cx: &mut Context<Self>,
16835    ) {
16836        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
16837        if let Some(task) = task {
16838            task.detach();
16839        };
16840    }
16841
16842    pub fn go_to_reference_before_or_after_position(
16843        &mut self,
16844        direction: Direction,
16845        count: usize,
16846        window: &mut Window,
16847        cx: &mut Context<Self>,
16848    ) -> Option<Task<Result<()>>> {
16849        let selection = self.selections.newest_anchor();
16850        let head = selection.head();
16851
16852        let multi_buffer = self.buffer.read(cx);
16853
16854        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
16855        let workspace = self.workspace()?;
16856        let project = workspace.read(cx).project().clone();
16857        let references =
16858            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
16859        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
16860            let Some(locations) = references.await? else {
16861                return Ok(());
16862            };
16863
16864            if locations.is_empty() {
16865                // totally normal - the cursor may be on something which is not
16866                // a symbol (e.g. a keyword)
16867                log::info!("no references found under cursor");
16868                return Ok(());
16869            }
16870
16871            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
16872
16873            let multi_buffer_snapshot =
16874                multi_buffer.read_with(cx, |multi_buffer, cx| multi_buffer.snapshot(cx))?;
16875
16876            let (locations, current_location_index) =
16877                multi_buffer.update(cx, |multi_buffer, cx| {
16878                    let mut locations = locations
16879                        .into_iter()
16880                        .filter_map(|loc| {
16881                            let start = multi_buffer.buffer_anchor_to_anchor(
16882                                &loc.buffer,
16883                                loc.range.start,
16884                                cx,
16885                            )?;
16886                            let end = multi_buffer.buffer_anchor_to_anchor(
16887                                &loc.buffer,
16888                                loc.range.end,
16889                                cx,
16890                            )?;
16891                            Some(start..end)
16892                        })
16893                        .collect::<Vec<_>>();
16894
16895                    // There is an O(n) implementation, but given this list will be
16896                    // small (usually <100 items), the extra O(log(n)) factor isn't
16897                    // worth the (surprisingly large amount of) extra complexity.
16898                    locations
16899                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
16900
16901                    let head_offset = head.to_offset(&multi_buffer_snapshot);
16902
16903                    let current_location_index = locations.iter().position(|loc| {
16904                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
16905                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
16906                    });
16907
16908                    (locations, current_location_index)
16909                })?;
16910
16911            let Some(current_location_index) = current_location_index else {
16912                // This indicates something has gone wrong, because we already
16913                // handle the "no references" case above
16914                log::error!(
16915                    "failed to find current reference under cursor. Total references: {}",
16916                    locations.len()
16917                );
16918                return Ok(());
16919            };
16920
16921            let destination_location_index = match direction {
16922                Direction::Next => (current_location_index + count) % locations.len(),
16923                Direction::Prev => {
16924                    (current_location_index + locations.len() - count % locations.len())
16925                        % locations.len()
16926                }
16927            };
16928
16929            // TODO(cameron): is this needed?
16930            // the thinking is to avoid "jumping to the current location" (avoid
16931            // polluting "jumplist" in vim terms)
16932            if current_location_index == destination_location_index {
16933                return Ok(());
16934            }
16935
16936            let Range { start, end } = locations[destination_location_index];
16937
16938            editor.update_in(cx, |editor, window, cx| {
16939                let effects = SelectionEffects::default();
16940
16941                editor.unfold_ranges(&[start..end], false, false, cx);
16942                editor.change_selections(effects, window, cx, |s| {
16943                    s.select_ranges([start..start]);
16944                });
16945            })?;
16946
16947            Ok(())
16948        }))
16949    }
16950
16951    pub fn find_all_references(
16952        &mut self,
16953        _: &FindAllReferences,
16954        window: &mut Window,
16955        cx: &mut Context<Self>,
16956    ) -> Option<Task<Result<Navigated>>> {
16957        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
16958        let multi_buffer = self.buffer.read(cx);
16959        let head = selection.head();
16960
16961        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16962        let head_anchor = multi_buffer_snapshot.anchor_at(
16963            head,
16964            if head < selection.tail() {
16965                Bias::Right
16966            } else {
16967                Bias::Left
16968            },
16969        );
16970
16971        match self
16972            .find_all_references_task_sources
16973            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16974        {
16975            Ok(_) => {
16976                log::info!(
16977                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16978                );
16979                return None;
16980            }
16981            Err(i) => {
16982                self.find_all_references_task_sources.insert(i, head_anchor);
16983            }
16984        }
16985
16986        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16987        let workspace = self.workspace()?;
16988        let project = workspace.read(cx).project().clone();
16989        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16990        Some(cx.spawn_in(window, async move |editor, cx| {
16991            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16992                if let Ok(i) = editor
16993                    .find_all_references_task_sources
16994                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16995                {
16996                    editor.find_all_references_task_sources.remove(i);
16997                }
16998            });
16999
17000            let Some(locations) = references.await? else {
17001                return anyhow::Ok(Navigated::No);
17002            };
17003            let mut locations = cx.update(|_, cx| {
17004                locations
17005                    .into_iter()
17006                    .map(|location| {
17007                        let buffer = location.buffer.read(cx);
17008                        (location.buffer, location.range.to_point(buffer))
17009                    })
17010                    .into_group_map()
17011            })?;
17012            if locations.is_empty() {
17013                return anyhow::Ok(Navigated::No);
17014            }
17015            for ranges in locations.values_mut() {
17016                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17017                ranges.dedup();
17018            }
17019
17020            workspace.update_in(cx, |workspace, window, cx| {
17021                let target = locations
17022                    .iter()
17023                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17024                    .map(|(buffer, location)| {
17025                        buffer
17026                            .read(cx)
17027                            .text_for_range(location.clone())
17028                            .collect::<String>()
17029                    })
17030                    .filter(|text| !text.contains('\n'))
17031                    .unique()
17032                    .take(3)
17033                    .join(", ");
17034                let title = if target.is_empty() {
17035                    "References".to_owned()
17036                } else {
17037                    format!("References to {target}")
17038                };
17039                Self::open_locations_in_multibuffer(
17040                    workspace,
17041                    locations,
17042                    title,
17043                    false,
17044                    MultibufferSelectionMode::First,
17045                    window,
17046                    cx,
17047                );
17048                Navigated::Yes
17049            })
17050        }))
17051    }
17052
17053    /// Opens a multibuffer with the given project locations in it
17054    pub fn open_locations_in_multibuffer(
17055        workspace: &mut Workspace,
17056        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
17057        title: String,
17058        split: bool,
17059        multibuffer_selection_mode: MultibufferSelectionMode,
17060        window: &mut Window,
17061        cx: &mut Context<Workspace>,
17062    ) {
17063        if locations.is_empty() {
17064            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
17065            return;
17066        }
17067
17068        let capability = workspace.project().read(cx).capability();
17069        let mut ranges = <Vec<Range<Anchor>>>::new();
17070
17071        // a key to find existing multibuffer editors with the same set of locations
17072        // to prevent us from opening more and more multibuffer tabs for searches and the like
17073        let mut key = (title.clone(), vec![]);
17074        let excerpt_buffer = cx.new(|cx| {
17075            let key = &mut key.1;
17076            let mut multibuffer = MultiBuffer::new(capability);
17077            for (buffer, mut ranges_for_buffer) in locations {
17078                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17079                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17080                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17081                    PathKey::for_buffer(&buffer, cx),
17082                    buffer.clone(),
17083                    ranges_for_buffer,
17084                    multibuffer_context_lines(cx),
17085                    cx,
17086                );
17087                ranges.extend(new_ranges)
17088            }
17089
17090            multibuffer.with_title(title)
17091        });
17092        let existing = workspace.active_pane().update(cx, |pane, cx| {
17093            pane.items()
17094                .filter_map(|item| item.downcast::<Editor>())
17095                .find(|editor| {
17096                    editor
17097                        .read(cx)
17098                        .lookup_key
17099                        .as_ref()
17100                        .and_then(|it| {
17101                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17102                        })
17103                        .is_some_and(|it| *it == key)
17104                })
17105        });
17106        let editor = existing.unwrap_or_else(|| {
17107            cx.new(|cx| {
17108                let mut editor = Editor::for_multibuffer(
17109                    excerpt_buffer,
17110                    Some(workspace.project().clone()),
17111                    window,
17112                    cx,
17113                );
17114                editor.lookup_key = Some(Box::new(key));
17115                editor
17116            })
17117        });
17118        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17119            MultibufferSelectionMode::First => {
17120                if let Some(first_range) = ranges.first() {
17121                    editor.change_selections(
17122                        SelectionEffects::no_scroll(),
17123                        window,
17124                        cx,
17125                        |selections| {
17126                            selections.clear_disjoint();
17127                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17128                        },
17129                    );
17130                }
17131                editor.highlight_background::<Self>(
17132                    &ranges,
17133                    |theme| theme.colors().editor_highlighted_line_background,
17134                    cx,
17135                );
17136            }
17137            MultibufferSelectionMode::All => {
17138                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17139                    selections.clear_disjoint();
17140                    selections.select_anchor_ranges(ranges);
17141                });
17142            }
17143        });
17144
17145        let item = Box::new(editor);
17146        let item_id = item.item_id();
17147
17148        if split {
17149            let pane = workspace.adjacent_pane(window, cx);
17150            workspace.add_item(pane, item, None, true, true, window, cx);
17151        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
17152            let (preview_item_id, preview_item_idx) =
17153                workspace.active_pane().read_with(cx, |pane, _| {
17154                    (pane.preview_item_id(), pane.preview_item_idx())
17155                });
17156
17157            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
17158
17159            if let Some(preview_item_id) = preview_item_id {
17160                workspace.active_pane().update(cx, |pane, cx| {
17161                    pane.remove_item(preview_item_id, false, false, window, cx);
17162                });
17163            }
17164        } else {
17165            workspace.add_item_to_active_pane(item, None, true, window, cx);
17166        }
17167        workspace.active_pane().update(cx, |pane, cx| {
17168            pane.set_preview_item_id(Some(item_id), cx);
17169        });
17170    }
17171
17172    pub fn rename(
17173        &mut self,
17174        _: &Rename,
17175        window: &mut Window,
17176        cx: &mut Context<Self>,
17177    ) -> Option<Task<Result<()>>> {
17178        use language::ToOffset as _;
17179
17180        let provider = self.semantics_provider.clone()?;
17181        let selection = self.selections.newest_anchor().clone();
17182        let (cursor_buffer, cursor_buffer_position) = self
17183            .buffer
17184            .read(cx)
17185            .text_anchor_for_position(selection.head(), cx)?;
17186        let (tail_buffer, cursor_buffer_position_end) = self
17187            .buffer
17188            .read(cx)
17189            .text_anchor_for_position(selection.tail(), cx)?;
17190        if tail_buffer != cursor_buffer {
17191            return None;
17192        }
17193
17194        let snapshot = cursor_buffer.read(cx).snapshot();
17195        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17196        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17197        let prepare_rename = provider
17198            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17199            .unwrap_or_else(|| Task::ready(Ok(None)));
17200        drop(snapshot);
17201
17202        Some(cx.spawn_in(window, async move |this, cx| {
17203            let rename_range = if let Some(range) = prepare_rename.await? {
17204                Some(range)
17205            } else {
17206                this.update(cx, |this, cx| {
17207                    let buffer = this.buffer.read(cx).snapshot(cx);
17208                    let mut buffer_highlights = this
17209                        .document_highlights_for_position(selection.head(), &buffer)
17210                        .filter(|highlight| {
17211                            highlight.start.excerpt_id == selection.head().excerpt_id
17212                                && highlight.end.excerpt_id == selection.head().excerpt_id
17213                        });
17214                    buffer_highlights
17215                        .next()
17216                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17217                })?
17218            };
17219            if let Some(rename_range) = rename_range {
17220                this.update_in(cx, |this, window, cx| {
17221                    let snapshot = cursor_buffer.read(cx).snapshot();
17222                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17223                    let cursor_offset_in_rename_range =
17224                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17225                    let cursor_offset_in_rename_range_end =
17226                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17227
17228                    this.take_rename(false, window, cx);
17229                    let buffer = this.buffer.read(cx).read(cx);
17230                    let cursor_offset = selection.head().to_offset(&buffer);
17231                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
17232                    let rename_end = rename_start + rename_buffer_range.len();
17233                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17234                    let mut old_highlight_id = None;
17235                    let old_name: Arc<str> = buffer
17236                        .chunks(rename_start..rename_end, true)
17237                        .map(|chunk| {
17238                            if old_highlight_id.is_none() {
17239                                old_highlight_id = chunk.syntax_highlight_id;
17240                            }
17241                            chunk.text
17242                        })
17243                        .collect::<String>()
17244                        .into();
17245
17246                    drop(buffer);
17247
17248                    // Position the selection in the rename editor so that it matches the current selection.
17249                    this.show_local_selections = false;
17250                    let rename_editor = cx.new(|cx| {
17251                        let mut editor = Editor::single_line(window, cx);
17252                        editor.buffer.update(cx, |buffer, cx| {
17253                            buffer.edit([(0..0, old_name.clone())], None, cx)
17254                        });
17255                        let rename_selection_range = match cursor_offset_in_rename_range
17256                            .cmp(&cursor_offset_in_rename_range_end)
17257                        {
17258                            Ordering::Equal => {
17259                                editor.select_all(&SelectAll, window, cx);
17260                                return editor;
17261                            }
17262                            Ordering::Less => {
17263                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17264                            }
17265                            Ordering::Greater => {
17266                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17267                            }
17268                        };
17269                        if rename_selection_range.end > old_name.len() {
17270                            editor.select_all(&SelectAll, window, cx);
17271                        } else {
17272                            editor.change_selections(Default::default(), window, cx, |s| {
17273                                s.select_ranges([rename_selection_range]);
17274                            });
17275                        }
17276                        editor
17277                    });
17278                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17279                        if e == &EditorEvent::Focused {
17280                            cx.emit(EditorEvent::FocusedIn)
17281                        }
17282                    })
17283                    .detach();
17284
17285                    let write_highlights =
17286                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17287                    let read_highlights =
17288                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17289                    let ranges = write_highlights
17290                        .iter()
17291                        .flat_map(|(_, ranges)| ranges.iter())
17292                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17293                        .cloned()
17294                        .collect();
17295
17296                    this.highlight_text::<Rename>(
17297                        ranges,
17298                        HighlightStyle {
17299                            fade_out: Some(0.6),
17300                            ..Default::default()
17301                        },
17302                        cx,
17303                    );
17304                    let rename_focus_handle = rename_editor.focus_handle(cx);
17305                    window.focus(&rename_focus_handle);
17306                    let block_id = this.insert_blocks(
17307                        [BlockProperties {
17308                            style: BlockStyle::Flex,
17309                            placement: BlockPlacement::Below(range.start),
17310                            height: Some(1),
17311                            render: Arc::new({
17312                                let rename_editor = rename_editor.clone();
17313                                move |cx: &mut BlockContext| {
17314                                    let mut text_style = cx.editor_style.text.clone();
17315                                    if let Some(highlight_style) = old_highlight_id
17316                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17317                                    {
17318                                        text_style = text_style.highlight(highlight_style);
17319                                    }
17320                                    div()
17321                                        .block_mouse_except_scroll()
17322                                        .pl(cx.anchor_x)
17323                                        .child(EditorElement::new(
17324                                            &rename_editor,
17325                                            EditorStyle {
17326                                                background: cx.theme().system().transparent,
17327                                                local_player: cx.editor_style.local_player,
17328                                                text: text_style,
17329                                                scrollbar_width: cx.editor_style.scrollbar_width,
17330                                                syntax: cx.editor_style.syntax.clone(),
17331                                                status: cx.editor_style.status.clone(),
17332                                                inlay_hints_style: HighlightStyle {
17333                                                    font_weight: Some(FontWeight::BOLD),
17334                                                    ..make_inlay_hints_style(cx.app)
17335                                                },
17336                                                edit_prediction_styles: make_suggestion_styles(
17337                                                    cx.app,
17338                                                ),
17339                                                ..EditorStyle::default()
17340                                            },
17341                                        ))
17342                                        .into_any_element()
17343                                }
17344                            }),
17345                            priority: 0,
17346                        }],
17347                        Some(Autoscroll::fit()),
17348                        cx,
17349                    )[0];
17350                    this.pending_rename = Some(RenameState {
17351                        range,
17352                        old_name,
17353                        editor: rename_editor,
17354                        block_id,
17355                    });
17356                })?;
17357            }
17358
17359            Ok(())
17360        }))
17361    }
17362
17363    pub fn confirm_rename(
17364        &mut self,
17365        _: &ConfirmRename,
17366        window: &mut Window,
17367        cx: &mut Context<Self>,
17368    ) -> Option<Task<Result<()>>> {
17369        let rename = self.take_rename(false, window, cx)?;
17370        let workspace = self.workspace()?.downgrade();
17371        let (buffer, start) = self
17372            .buffer
17373            .read(cx)
17374            .text_anchor_for_position(rename.range.start, cx)?;
17375        let (end_buffer, _) = self
17376            .buffer
17377            .read(cx)
17378            .text_anchor_for_position(rename.range.end, cx)?;
17379        if buffer != end_buffer {
17380            return None;
17381        }
17382
17383        let old_name = rename.old_name;
17384        let new_name = rename.editor.read(cx).text(cx);
17385
17386        let rename = self.semantics_provider.as_ref()?.perform_rename(
17387            &buffer,
17388            start,
17389            new_name.clone(),
17390            cx,
17391        )?;
17392
17393        Some(cx.spawn_in(window, async move |editor, cx| {
17394            let project_transaction = rename.await?;
17395            Self::open_project_transaction(
17396                &editor,
17397                workspace,
17398                project_transaction,
17399                format!("Rename: {}{}", old_name, new_name),
17400                cx,
17401            )
17402            .await?;
17403
17404            editor.update(cx, |editor, cx| {
17405                editor.refresh_document_highlights(cx);
17406            })?;
17407            Ok(())
17408        }))
17409    }
17410
17411    fn take_rename(
17412        &mut self,
17413        moving_cursor: bool,
17414        window: &mut Window,
17415        cx: &mut Context<Self>,
17416    ) -> Option<RenameState> {
17417        let rename = self.pending_rename.take()?;
17418        if rename.editor.focus_handle(cx).is_focused(window) {
17419            window.focus(&self.focus_handle);
17420        }
17421
17422        self.remove_blocks(
17423            [rename.block_id].into_iter().collect(),
17424            Some(Autoscroll::fit()),
17425            cx,
17426        );
17427        self.clear_highlights::<Rename>(cx);
17428        self.show_local_selections = true;
17429
17430        if moving_cursor {
17431            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17432                editor
17433                    .selections
17434                    .newest::<usize>(&editor.display_snapshot(cx))
17435                    .head()
17436            });
17437
17438            // Update the selection to match the position of the selection inside
17439            // the rename editor.
17440            let snapshot = self.buffer.read(cx).read(cx);
17441            let rename_range = rename.range.to_offset(&snapshot);
17442            let cursor_in_editor = snapshot
17443                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17444                .min(rename_range.end);
17445            drop(snapshot);
17446
17447            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17448                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17449            });
17450        } else {
17451            self.refresh_document_highlights(cx);
17452        }
17453
17454        Some(rename)
17455    }
17456
17457    pub fn pending_rename(&self) -> Option<&RenameState> {
17458        self.pending_rename.as_ref()
17459    }
17460
17461    fn format(
17462        &mut self,
17463        _: &Format,
17464        window: &mut Window,
17465        cx: &mut Context<Self>,
17466    ) -> Option<Task<Result<()>>> {
17467        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17468
17469        let project = match &self.project {
17470            Some(project) => project.clone(),
17471            None => return None,
17472        };
17473
17474        Some(self.perform_format(
17475            project,
17476            FormatTrigger::Manual,
17477            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17478            window,
17479            cx,
17480        ))
17481    }
17482
17483    fn format_selections(
17484        &mut self,
17485        _: &FormatSelections,
17486        window: &mut Window,
17487        cx: &mut Context<Self>,
17488    ) -> Option<Task<Result<()>>> {
17489        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17490
17491        let project = match &self.project {
17492            Some(project) => project.clone(),
17493            None => return None,
17494        };
17495
17496        let ranges = self
17497            .selections
17498            .all_adjusted(&self.display_snapshot(cx))
17499            .into_iter()
17500            .map(|selection| selection.range())
17501            .collect_vec();
17502
17503        Some(self.perform_format(
17504            project,
17505            FormatTrigger::Manual,
17506            FormatTarget::Ranges(ranges),
17507            window,
17508            cx,
17509        ))
17510    }
17511
17512    fn perform_format(
17513        &mut self,
17514        project: Entity<Project>,
17515        trigger: FormatTrigger,
17516        target: FormatTarget,
17517        window: &mut Window,
17518        cx: &mut Context<Self>,
17519    ) -> Task<Result<()>> {
17520        let buffer = self.buffer.clone();
17521        let (buffers, target) = match target {
17522            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17523            FormatTarget::Ranges(selection_ranges) => {
17524                let multi_buffer = buffer.read(cx);
17525                let snapshot = multi_buffer.read(cx);
17526                let mut buffers = HashSet::default();
17527                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17528                    BTreeMap::new();
17529                for selection_range in selection_ranges {
17530                    for (buffer, buffer_range, _) in
17531                        snapshot.range_to_buffer_ranges(selection_range)
17532                    {
17533                        let buffer_id = buffer.remote_id();
17534                        let start = buffer.anchor_before(buffer_range.start);
17535                        let end = buffer.anchor_after(buffer_range.end);
17536                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17537                        buffer_id_to_ranges
17538                            .entry(buffer_id)
17539                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17540                            .or_insert_with(|| vec![start..end]);
17541                    }
17542                }
17543                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17544            }
17545        };
17546
17547        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17548        let selections_prev = transaction_id_prev
17549            .and_then(|transaction_id_prev| {
17550                // default to selections as they were after the last edit, if we have them,
17551                // instead of how they are now.
17552                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17553                // will take you back to where you made the last edit, instead of staying where you scrolled
17554                self.selection_history
17555                    .transaction(transaction_id_prev)
17556                    .map(|t| t.0.clone())
17557            })
17558            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17559
17560        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17561        let format = project.update(cx, |project, cx| {
17562            project.format(buffers, target, true, trigger, cx)
17563        });
17564
17565        cx.spawn_in(window, async move |editor, cx| {
17566            let transaction = futures::select_biased! {
17567                transaction = format.log_err().fuse() => transaction,
17568                () = timeout => {
17569                    log::warn!("timed out waiting for formatting");
17570                    None
17571                }
17572            };
17573
17574            buffer
17575                .update(cx, |buffer, cx| {
17576                    if let Some(transaction) = transaction
17577                        && !buffer.is_singleton()
17578                    {
17579                        buffer.push_transaction(&transaction.0, cx);
17580                    }
17581                    cx.notify();
17582                })
17583                .ok();
17584
17585            if let Some(transaction_id_now) =
17586                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17587            {
17588                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17589                if has_new_transaction {
17590                    _ = editor.update(cx, |editor, _| {
17591                        editor
17592                            .selection_history
17593                            .insert_transaction(transaction_id_now, selections_prev);
17594                    });
17595                }
17596            }
17597
17598            Ok(())
17599        })
17600    }
17601
17602    fn organize_imports(
17603        &mut self,
17604        _: &OrganizeImports,
17605        window: &mut Window,
17606        cx: &mut Context<Self>,
17607    ) -> Option<Task<Result<()>>> {
17608        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17609        let project = match &self.project {
17610            Some(project) => project.clone(),
17611            None => return None,
17612        };
17613        Some(self.perform_code_action_kind(
17614            project,
17615            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17616            window,
17617            cx,
17618        ))
17619    }
17620
17621    fn perform_code_action_kind(
17622        &mut self,
17623        project: Entity<Project>,
17624        kind: CodeActionKind,
17625        window: &mut Window,
17626        cx: &mut Context<Self>,
17627    ) -> Task<Result<()>> {
17628        let buffer = self.buffer.clone();
17629        let buffers = buffer.read(cx).all_buffers();
17630        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17631        let apply_action = project.update(cx, |project, cx| {
17632            project.apply_code_action_kind(buffers, kind, true, cx)
17633        });
17634        cx.spawn_in(window, async move |_, cx| {
17635            let transaction = futures::select_biased! {
17636                () = timeout => {
17637                    log::warn!("timed out waiting for executing code action");
17638                    None
17639                }
17640                transaction = apply_action.log_err().fuse() => transaction,
17641            };
17642            buffer
17643                .update(cx, |buffer, cx| {
17644                    // check if we need this
17645                    if let Some(transaction) = transaction
17646                        && !buffer.is_singleton()
17647                    {
17648                        buffer.push_transaction(&transaction.0, cx);
17649                    }
17650                    cx.notify();
17651                })
17652                .ok();
17653            Ok(())
17654        })
17655    }
17656
17657    pub fn restart_language_server(
17658        &mut self,
17659        _: &RestartLanguageServer,
17660        _: &mut Window,
17661        cx: &mut Context<Self>,
17662    ) {
17663        if let Some(project) = self.project.clone() {
17664            self.buffer.update(cx, |multi_buffer, cx| {
17665                project.update(cx, |project, cx| {
17666                    project.restart_language_servers_for_buffers(
17667                        multi_buffer.all_buffers().into_iter().collect(),
17668                        HashSet::default(),
17669                        cx,
17670                    );
17671                });
17672            })
17673        }
17674    }
17675
17676    pub fn stop_language_server(
17677        &mut self,
17678        _: &StopLanguageServer,
17679        _: &mut Window,
17680        cx: &mut Context<Self>,
17681    ) {
17682        if let Some(project) = self.project.clone() {
17683            self.buffer.update(cx, |multi_buffer, cx| {
17684                project.update(cx, |project, cx| {
17685                    project.stop_language_servers_for_buffers(
17686                        multi_buffer.all_buffers().into_iter().collect(),
17687                        HashSet::default(),
17688                        cx,
17689                    );
17690                });
17691            });
17692            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
17693        }
17694    }
17695
17696    fn cancel_language_server_work(
17697        workspace: &mut Workspace,
17698        _: &actions::CancelLanguageServerWork,
17699        _: &mut Window,
17700        cx: &mut Context<Workspace>,
17701    ) {
17702        let project = workspace.project();
17703        let buffers = workspace
17704            .active_item(cx)
17705            .and_then(|item| item.act_as::<Editor>(cx))
17706            .map_or(HashSet::default(), |editor| {
17707                editor.read(cx).buffer.read(cx).all_buffers()
17708            });
17709        project.update(cx, |project, cx| {
17710            project.cancel_language_server_work_for_buffers(buffers, cx);
17711        });
17712    }
17713
17714    fn show_character_palette(
17715        &mut self,
17716        _: &ShowCharacterPalette,
17717        window: &mut Window,
17718        _: &mut Context<Self>,
17719    ) {
17720        window.show_character_palette();
17721    }
17722
17723    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17724        if !self.diagnostics_enabled() {
17725            return;
17726        }
17727
17728        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17729            let buffer = self.buffer.read(cx).snapshot(cx);
17730            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17731            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17732            let is_valid = buffer
17733                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17734                .any(|entry| {
17735                    entry.diagnostic.is_primary
17736                        && !entry.range.is_empty()
17737                        && entry.range.start == primary_range_start
17738                        && entry.diagnostic.message == active_diagnostics.active_message
17739                });
17740
17741            if !is_valid {
17742                self.dismiss_diagnostics(cx);
17743            }
17744        }
17745    }
17746
17747    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17748        match &self.active_diagnostics {
17749            ActiveDiagnostic::Group(group) => Some(group),
17750            _ => None,
17751        }
17752    }
17753
17754    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17755        if !self.diagnostics_enabled() {
17756            return;
17757        }
17758        self.dismiss_diagnostics(cx);
17759        self.active_diagnostics = ActiveDiagnostic::All;
17760    }
17761
17762    fn activate_diagnostics(
17763        &mut self,
17764        buffer_id: BufferId,
17765        diagnostic: DiagnosticEntryRef<'_, usize>,
17766        window: &mut Window,
17767        cx: &mut Context<Self>,
17768    ) {
17769        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17770            return;
17771        }
17772        self.dismiss_diagnostics(cx);
17773        let snapshot = self.snapshot(window, cx);
17774        let buffer = self.buffer.read(cx).snapshot(cx);
17775        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17776            return;
17777        };
17778
17779        let diagnostic_group = buffer
17780            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17781            .collect::<Vec<_>>();
17782
17783        let blocks =
17784            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17785
17786        let blocks = self.display_map.update(cx, |display_map, cx| {
17787            display_map.insert_blocks(blocks, cx).into_iter().collect()
17788        });
17789        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17790            active_range: buffer.anchor_before(diagnostic.range.start)
17791                ..buffer.anchor_after(diagnostic.range.end),
17792            active_message: diagnostic.diagnostic.message.clone(),
17793            group_id: diagnostic.diagnostic.group_id,
17794            blocks,
17795        });
17796        cx.notify();
17797    }
17798
17799    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17800        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17801            return;
17802        };
17803
17804        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17805        if let ActiveDiagnostic::Group(group) = prev {
17806            self.display_map.update(cx, |display_map, cx| {
17807                display_map.remove_blocks(group.blocks, cx);
17808            });
17809            cx.notify();
17810        }
17811    }
17812
17813    /// Disable inline diagnostics rendering for this editor.
17814    pub fn disable_inline_diagnostics(&mut self) {
17815        self.inline_diagnostics_enabled = false;
17816        self.inline_diagnostics_update = Task::ready(());
17817        self.inline_diagnostics.clear();
17818    }
17819
17820    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17821        self.diagnostics_enabled = false;
17822        self.dismiss_diagnostics(cx);
17823        self.inline_diagnostics_update = Task::ready(());
17824        self.inline_diagnostics.clear();
17825    }
17826
17827    pub fn disable_word_completions(&mut self) {
17828        self.word_completions_enabled = false;
17829    }
17830
17831    pub fn diagnostics_enabled(&self) -> bool {
17832        self.diagnostics_enabled && self.mode.is_full()
17833    }
17834
17835    pub fn inline_diagnostics_enabled(&self) -> bool {
17836        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17837    }
17838
17839    pub fn show_inline_diagnostics(&self) -> bool {
17840        self.show_inline_diagnostics
17841    }
17842
17843    pub fn toggle_inline_diagnostics(
17844        &mut self,
17845        _: &ToggleInlineDiagnostics,
17846        window: &mut Window,
17847        cx: &mut Context<Editor>,
17848    ) {
17849        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17850        self.refresh_inline_diagnostics(false, window, cx);
17851    }
17852
17853    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17854        self.diagnostics_max_severity = severity;
17855        self.display_map.update(cx, |display_map, _| {
17856            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17857        });
17858    }
17859
17860    pub fn toggle_diagnostics(
17861        &mut self,
17862        _: &ToggleDiagnostics,
17863        window: &mut Window,
17864        cx: &mut Context<Editor>,
17865    ) {
17866        if !self.diagnostics_enabled() {
17867            return;
17868        }
17869
17870        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17871            EditorSettings::get_global(cx)
17872                .diagnostics_max_severity
17873                .filter(|severity| severity != &DiagnosticSeverity::Off)
17874                .unwrap_or(DiagnosticSeverity::Hint)
17875        } else {
17876            DiagnosticSeverity::Off
17877        };
17878        self.set_max_diagnostics_severity(new_severity, cx);
17879        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17880            self.active_diagnostics = ActiveDiagnostic::None;
17881            self.inline_diagnostics_update = Task::ready(());
17882            self.inline_diagnostics.clear();
17883        } else {
17884            self.refresh_inline_diagnostics(false, window, cx);
17885        }
17886
17887        cx.notify();
17888    }
17889
17890    pub fn toggle_minimap(
17891        &mut self,
17892        _: &ToggleMinimap,
17893        window: &mut Window,
17894        cx: &mut Context<Editor>,
17895    ) {
17896        if self.supports_minimap(cx) {
17897            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17898        }
17899    }
17900
17901    fn refresh_inline_diagnostics(
17902        &mut self,
17903        debounce: bool,
17904        window: &mut Window,
17905        cx: &mut Context<Self>,
17906    ) {
17907        let max_severity = ProjectSettings::get_global(cx)
17908            .diagnostics
17909            .inline
17910            .max_severity
17911            .unwrap_or(self.diagnostics_max_severity);
17912
17913        if !self.inline_diagnostics_enabled()
17914            || !self.diagnostics_enabled()
17915            || !self.show_inline_diagnostics
17916            || max_severity == DiagnosticSeverity::Off
17917        {
17918            self.inline_diagnostics_update = Task::ready(());
17919            self.inline_diagnostics.clear();
17920            return;
17921        }
17922
17923        let debounce_ms = ProjectSettings::get_global(cx)
17924            .diagnostics
17925            .inline
17926            .update_debounce_ms;
17927        let debounce = if debounce && debounce_ms > 0 {
17928            Some(Duration::from_millis(debounce_ms))
17929        } else {
17930            None
17931        };
17932        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17933            if let Some(debounce) = debounce {
17934                cx.background_executor().timer(debounce).await;
17935            }
17936            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17937                editor
17938                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17939                    .ok()
17940            }) else {
17941                return;
17942            };
17943
17944            let new_inline_diagnostics = cx
17945                .background_spawn(async move {
17946                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17947                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17948                        let message = diagnostic_entry
17949                            .diagnostic
17950                            .message
17951                            .split_once('\n')
17952                            .map(|(line, _)| line)
17953                            .map(SharedString::new)
17954                            .unwrap_or_else(|| {
17955                                SharedString::new(&*diagnostic_entry.diagnostic.message)
17956                            });
17957                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17958                        let (Ok(i) | Err(i)) = inline_diagnostics
17959                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17960                        inline_diagnostics.insert(
17961                            i,
17962                            (
17963                                start_anchor,
17964                                InlineDiagnostic {
17965                                    message,
17966                                    group_id: diagnostic_entry.diagnostic.group_id,
17967                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17968                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17969                                    severity: diagnostic_entry.diagnostic.severity,
17970                                },
17971                            ),
17972                        );
17973                    }
17974                    inline_diagnostics
17975                })
17976                .await;
17977
17978            editor
17979                .update(cx, |editor, cx| {
17980                    editor.inline_diagnostics = new_inline_diagnostics;
17981                    cx.notify();
17982                })
17983                .ok();
17984        });
17985    }
17986
17987    fn pull_diagnostics(
17988        &mut self,
17989        buffer_id: Option<BufferId>,
17990        window: &Window,
17991        cx: &mut Context<Self>,
17992    ) -> Option<()> {
17993        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
17994            return None;
17995        }
17996        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17997            .diagnostics
17998            .lsp_pull_diagnostics;
17999        if !pull_diagnostics_settings.enabled {
18000            return None;
18001        }
18002        let project = self.project()?.downgrade();
18003        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
18004        let mut buffers = self.buffer.read(cx).all_buffers();
18005        buffers.retain(|buffer| {
18006            let buffer_id_to_retain = buffer.read(cx).remote_id();
18007            buffer_id.is_none_or(|buffer_id| buffer_id == buffer_id_to_retain)
18008                && self.registered_buffers.contains_key(&buffer_id_to_retain)
18009        });
18010        if buffers.is_empty() {
18011            self.pull_diagnostics_task = Task::ready(());
18012            return None;
18013        }
18014
18015        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
18016            cx.background_executor().timer(debounce).await;
18017
18018            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
18019                buffers
18020                    .into_iter()
18021                    .filter_map(|buffer| {
18022                        project
18023                            .update(cx, |project, cx| {
18024                                project.lsp_store().update(cx, |lsp_store, cx| {
18025                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
18026                                })
18027                            })
18028                            .ok()
18029                    })
18030                    .collect::<FuturesUnordered<_>>()
18031            }) else {
18032                return;
18033            };
18034
18035            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
18036                match pull_task {
18037                    Ok(()) => {
18038                        if editor
18039                            .update_in(cx, |editor, window, cx| {
18040                                editor.update_diagnostics_state(window, cx);
18041                            })
18042                            .is_err()
18043                        {
18044                            return;
18045                        }
18046                    }
18047                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
18048                }
18049            }
18050        });
18051
18052        Some(())
18053    }
18054
18055    pub fn set_selections_from_remote(
18056        &mut self,
18057        selections: Vec<Selection<Anchor>>,
18058        pending_selection: Option<Selection<Anchor>>,
18059        window: &mut Window,
18060        cx: &mut Context<Self>,
18061    ) {
18062        let old_cursor_position = self.selections.newest_anchor().head();
18063        self.selections.change_with(cx, |s| {
18064            s.select_anchors(selections);
18065            if let Some(pending_selection) = pending_selection {
18066                s.set_pending(pending_selection, SelectMode::Character);
18067            } else {
18068                s.clear_pending();
18069            }
18070        });
18071        self.selections_did_change(
18072            false,
18073            &old_cursor_position,
18074            SelectionEffects::default(),
18075            window,
18076            cx,
18077        );
18078    }
18079
18080    pub fn transact(
18081        &mut self,
18082        window: &mut Window,
18083        cx: &mut Context<Self>,
18084        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
18085    ) -> Option<TransactionId> {
18086        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18087            this.start_transaction_at(Instant::now(), window, cx);
18088            update(this, window, cx);
18089            this.end_transaction_at(Instant::now(), cx)
18090        })
18091    }
18092
18093    pub fn start_transaction_at(
18094        &mut self,
18095        now: Instant,
18096        window: &mut Window,
18097        cx: &mut Context<Self>,
18098    ) -> Option<TransactionId> {
18099        self.end_selection(window, cx);
18100        if let Some(tx_id) = self
18101            .buffer
18102            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18103        {
18104            self.selection_history
18105                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18106            cx.emit(EditorEvent::TransactionBegun {
18107                transaction_id: tx_id,
18108            });
18109            Some(tx_id)
18110        } else {
18111            None
18112        }
18113    }
18114
18115    pub fn end_transaction_at(
18116        &mut self,
18117        now: Instant,
18118        cx: &mut Context<Self>,
18119    ) -> Option<TransactionId> {
18120        if let Some(transaction_id) = self
18121            .buffer
18122            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18123        {
18124            if let Some((_, end_selections)) =
18125                self.selection_history.transaction_mut(transaction_id)
18126            {
18127                *end_selections = Some(self.selections.disjoint_anchors_arc());
18128            } else {
18129                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18130            }
18131
18132            cx.emit(EditorEvent::Edited { transaction_id });
18133            Some(transaction_id)
18134        } else {
18135            None
18136        }
18137    }
18138
18139    pub fn modify_transaction_selection_history(
18140        &mut self,
18141        transaction_id: TransactionId,
18142        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18143    ) -> bool {
18144        self.selection_history
18145            .transaction_mut(transaction_id)
18146            .map(modify)
18147            .is_some()
18148    }
18149
18150    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18151        if self.selection_mark_mode {
18152            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18153                s.move_with(|_, sel| {
18154                    sel.collapse_to(sel.head(), SelectionGoal::None);
18155                });
18156            })
18157        }
18158        self.selection_mark_mode = true;
18159        cx.notify();
18160    }
18161
18162    pub fn swap_selection_ends(
18163        &mut self,
18164        _: &actions::SwapSelectionEnds,
18165        window: &mut Window,
18166        cx: &mut Context<Self>,
18167    ) {
18168        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18169            s.move_with(|_, sel| {
18170                if sel.start != sel.end {
18171                    sel.reversed = !sel.reversed
18172                }
18173            });
18174        });
18175        self.request_autoscroll(Autoscroll::newest(), cx);
18176        cx.notify();
18177    }
18178
18179    pub fn toggle_focus(
18180        workspace: &mut Workspace,
18181        _: &actions::ToggleFocus,
18182        window: &mut Window,
18183        cx: &mut Context<Workspace>,
18184    ) {
18185        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18186            return;
18187        };
18188        workspace.activate_item(&item, true, true, window, cx);
18189    }
18190
18191    pub fn toggle_fold(
18192        &mut self,
18193        _: &actions::ToggleFold,
18194        window: &mut Window,
18195        cx: &mut Context<Self>,
18196    ) {
18197        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18198            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18199            let selection = self.selections.newest::<Point>(&display_map);
18200
18201            let range = if selection.is_empty() {
18202                let point = selection.head().to_display_point(&display_map);
18203                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18204                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18205                    .to_point(&display_map);
18206                start..end
18207            } else {
18208                selection.range()
18209            };
18210            if display_map.folds_in_range(range).next().is_some() {
18211                self.unfold_lines(&Default::default(), window, cx)
18212            } else {
18213                self.fold(&Default::default(), window, cx)
18214            }
18215        } else {
18216            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18217            let buffer_ids: HashSet<_> = self
18218                .selections
18219                .disjoint_anchor_ranges()
18220                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18221                .collect();
18222
18223            let should_unfold = buffer_ids
18224                .iter()
18225                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18226
18227            for buffer_id in buffer_ids {
18228                if should_unfold {
18229                    self.unfold_buffer(buffer_id, cx);
18230                } else {
18231                    self.fold_buffer(buffer_id, cx);
18232                }
18233            }
18234        }
18235    }
18236
18237    pub fn toggle_fold_recursive(
18238        &mut self,
18239        _: &actions::ToggleFoldRecursive,
18240        window: &mut Window,
18241        cx: &mut Context<Self>,
18242    ) {
18243        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
18244
18245        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18246        let range = if selection.is_empty() {
18247            let point = selection.head().to_display_point(&display_map);
18248            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18249            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18250                .to_point(&display_map);
18251            start..end
18252        } else {
18253            selection.range()
18254        };
18255        if display_map.folds_in_range(range).next().is_some() {
18256            self.unfold_recursive(&Default::default(), window, cx)
18257        } else {
18258            self.fold_recursive(&Default::default(), window, cx)
18259        }
18260    }
18261
18262    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18263        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18264            let mut to_fold = Vec::new();
18265            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18266            let selections = self.selections.all_adjusted(&display_map);
18267
18268            for selection in selections {
18269                let range = selection.range().sorted();
18270                let buffer_start_row = range.start.row;
18271
18272                if range.start.row != range.end.row {
18273                    let mut found = false;
18274                    let mut row = range.start.row;
18275                    while row <= range.end.row {
18276                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18277                        {
18278                            found = true;
18279                            row = crease.range().end.row + 1;
18280                            to_fold.push(crease);
18281                        } else {
18282                            row += 1
18283                        }
18284                    }
18285                    if found {
18286                        continue;
18287                    }
18288                }
18289
18290                for row in (0..=range.start.row).rev() {
18291                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18292                        && crease.range().end.row >= buffer_start_row
18293                    {
18294                        to_fold.push(crease);
18295                        if row <= range.start.row {
18296                            break;
18297                        }
18298                    }
18299                }
18300            }
18301
18302            self.fold_creases(to_fold, true, window, cx);
18303        } else {
18304            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18305            let buffer_ids = self
18306                .selections
18307                .disjoint_anchor_ranges()
18308                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18309                .collect::<HashSet<_>>();
18310            for buffer_id in buffer_ids {
18311                self.fold_buffer(buffer_id, cx);
18312            }
18313        }
18314    }
18315
18316    pub fn toggle_fold_all(
18317        &mut self,
18318        _: &actions::ToggleFoldAll,
18319        window: &mut Window,
18320        cx: &mut Context<Self>,
18321    ) {
18322        if self.buffer.read(cx).is_singleton() {
18323            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18324            let has_folds = display_map
18325                .folds_in_range(0..display_map.buffer_snapshot().len())
18326                .next()
18327                .is_some();
18328
18329            if has_folds {
18330                self.unfold_all(&actions::UnfoldAll, window, cx);
18331            } else {
18332                self.fold_all(&actions::FoldAll, window, cx);
18333            }
18334        } else {
18335            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18336            let should_unfold = buffer_ids
18337                .iter()
18338                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18339
18340            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18341                editor
18342                    .update_in(cx, |editor, _, cx| {
18343                        for buffer_id in buffer_ids {
18344                            if should_unfold {
18345                                editor.unfold_buffer(buffer_id, cx);
18346                            } else {
18347                                editor.fold_buffer(buffer_id, cx);
18348                            }
18349                        }
18350                    })
18351                    .ok();
18352            });
18353        }
18354    }
18355
18356    fn fold_at_level(
18357        &mut self,
18358        fold_at: &FoldAtLevel,
18359        window: &mut Window,
18360        cx: &mut Context<Self>,
18361    ) {
18362        if !self.buffer.read(cx).is_singleton() {
18363            return;
18364        }
18365
18366        let fold_at_level = fold_at.0;
18367        let snapshot = self.buffer.read(cx).snapshot(cx);
18368        let mut to_fold = Vec::new();
18369        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18370
18371        let row_ranges_to_keep: Vec<Range<u32>> = self
18372            .selections
18373            .all::<Point>(&self.display_snapshot(cx))
18374            .into_iter()
18375            .map(|sel| sel.start.row..sel.end.row)
18376            .collect();
18377
18378        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18379            while start_row < end_row {
18380                match self
18381                    .snapshot(window, cx)
18382                    .crease_for_buffer_row(MultiBufferRow(start_row))
18383                {
18384                    Some(crease) => {
18385                        let nested_start_row = crease.range().start.row + 1;
18386                        let nested_end_row = crease.range().end.row;
18387
18388                        if current_level < fold_at_level {
18389                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18390                        } else if current_level == fold_at_level {
18391                            // Fold iff there is no selection completely contained within the fold region
18392                            if !row_ranges_to_keep.iter().any(|selection| {
18393                                selection.end >= nested_start_row
18394                                    && selection.start <= nested_end_row
18395                            }) {
18396                                to_fold.push(crease);
18397                            }
18398                        }
18399
18400                        start_row = nested_end_row + 1;
18401                    }
18402                    None => start_row += 1,
18403                }
18404            }
18405        }
18406
18407        self.fold_creases(to_fold, true, window, cx);
18408    }
18409
18410    pub fn fold_at_level_1(
18411        &mut self,
18412        _: &actions::FoldAtLevel1,
18413        window: &mut Window,
18414        cx: &mut Context<Self>,
18415    ) {
18416        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18417    }
18418
18419    pub fn fold_at_level_2(
18420        &mut self,
18421        _: &actions::FoldAtLevel2,
18422        window: &mut Window,
18423        cx: &mut Context<Self>,
18424    ) {
18425        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18426    }
18427
18428    pub fn fold_at_level_3(
18429        &mut self,
18430        _: &actions::FoldAtLevel3,
18431        window: &mut Window,
18432        cx: &mut Context<Self>,
18433    ) {
18434        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18435    }
18436
18437    pub fn fold_at_level_4(
18438        &mut self,
18439        _: &actions::FoldAtLevel4,
18440        window: &mut Window,
18441        cx: &mut Context<Self>,
18442    ) {
18443        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18444    }
18445
18446    pub fn fold_at_level_5(
18447        &mut self,
18448        _: &actions::FoldAtLevel5,
18449        window: &mut Window,
18450        cx: &mut Context<Self>,
18451    ) {
18452        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18453    }
18454
18455    pub fn fold_at_level_6(
18456        &mut self,
18457        _: &actions::FoldAtLevel6,
18458        window: &mut Window,
18459        cx: &mut Context<Self>,
18460    ) {
18461        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18462    }
18463
18464    pub fn fold_at_level_7(
18465        &mut self,
18466        _: &actions::FoldAtLevel7,
18467        window: &mut Window,
18468        cx: &mut Context<Self>,
18469    ) {
18470        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18471    }
18472
18473    pub fn fold_at_level_8(
18474        &mut self,
18475        _: &actions::FoldAtLevel8,
18476        window: &mut Window,
18477        cx: &mut Context<Self>,
18478    ) {
18479        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18480    }
18481
18482    pub fn fold_at_level_9(
18483        &mut self,
18484        _: &actions::FoldAtLevel9,
18485        window: &mut Window,
18486        cx: &mut Context<Self>,
18487    ) {
18488        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18489    }
18490
18491    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18492        if self.buffer.read(cx).is_singleton() {
18493            let mut fold_ranges = Vec::new();
18494            let snapshot = self.buffer.read(cx).snapshot(cx);
18495
18496            for row in 0..snapshot.max_row().0 {
18497                if let Some(foldable_range) = self
18498                    .snapshot(window, cx)
18499                    .crease_for_buffer_row(MultiBufferRow(row))
18500                {
18501                    fold_ranges.push(foldable_range);
18502                }
18503            }
18504
18505            self.fold_creases(fold_ranges, true, window, cx);
18506        } else {
18507            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18508                editor
18509                    .update_in(cx, |editor, _, cx| {
18510                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18511                            editor.fold_buffer(buffer_id, cx);
18512                        }
18513                    })
18514                    .ok();
18515            });
18516        }
18517    }
18518
18519    pub fn fold_function_bodies(
18520        &mut self,
18521        _: &actions::FoldFunctionBodies,
18522        window: &mut Window,
18523        cx: &mut Context<Self>,
18524    ) {
18525        let snapshot = self.buffer.read(cx).snapshot(cx);
18526
18527        let ranges = snapshot
18528            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18529            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18530            .collect::<Vec<_>>();
18531
18532        let creases = ranges
18533            .into_iter()
18534            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18535            .collect();
18536
18537        self.fold_creases(creases, true, window, cx);
18538    }
18539
18540    pub fn fold_recursive(
18541        &mut self,
18542        _: &actions::FoldRecursive,
18543        window: &mut Window,
18544        cx: &mut Context<Self>,
18545    ) {
18546        let mut to_fold = Vec::new();
18547        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18548        let selections = self.selections.all_adjusted(&display_map);
18549
18550        for selection in selections {
18551            let range = selection.range().sorted();
18552            let buffer_start_row = range.start.row;
18553
18554            if range.start.row != range.end.row {
18555                let mut found = false;
18556                for row in range.start.row..=range.end.row {
18557                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18558                        found = true;
18559                        to_fold.push(crease);
18560                    }
18561                }
18562                if found {
18563                    continue;
18564                }
18565            }
18566
18567            for row in (0..=range.start.row).rev() {
18568                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18569                    if crease.range().end.row >= buffer_start_row {
18570                        to_fold.push(crease);
18571                    } else {
18572                        break;
18573                    }
18574                }
18575            }
18576        }
18577
18578        self.fold_creases(to_fold, true, window, cx);
18579    }
18580
18581    pub fn fold_at(
18582        &mut self,
18583        buffer_row: MultiBufferRow,
18584        window: &mut Window,
18585        cx: &mut Context<Self>,
18586    ) {
18587        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18588
18589        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18590            let autoscroll = self
18591                .selections
18592                .all::<Point>(&display_map)
18593                .iter()
18594                .any(|selection| crease.range().overlaps(&selection.range()));
18595
18596            self.fold_creases(vec![crease], autoscroll, window, cx);
18597        }
18598    }
18599
18600    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18601        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18602            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18603            let buffer = display_map.buffer_snapshot();
18604            let selections = self.selections.all::<Point>(&display_map);
18605            let ranges = selections
18606                .iter()
18607                .map(|s| {
18608                    let range = s.display_range(&display_map).sorted();
18609                    let mut start = range.start.to_point(&display_map);
18610                    let mut end = range.end.to_point(&display_map);
18611                    start.column = 0;
18612                    end.column = buffer.line_len(MultiBufferRow(end.row));
18613                    start..end
18614                })
18615                .collect::<Vec<_>>();
18616
18617            self.unfold_ranges(&ranges, true, true, cx);
18618        } else {
18619            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18620            let buffer_ids = self
18621                .selections
18622                .disjoint_anchor_ranges()
18623                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18624                .collect::<HashSet<_>>();
18625            for buffer_id in buffer_ids {
18626                self.unfold_buffer(buffer_id, cx);
18627            }
18628        }
18629    }
18630
18631    pub fn unfold_recursive(
18632        &mut self,
18633        _: &UnfoldRecursive,
18634        _window: &mut Window,
18635        cx: &mut Context<Self>,
18636    ) {
18637        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18638        let selections = self.selections.all::<Point>(&display_map);
18639        let ranges = selections
18640            .iter()
18641            .map(|s| {
18642                let mut range = s.display_range(&display_map).sorted();
18643                *range.start.column_mut() = 0;
18644                *range.end.column_mut() = display_map.line_len(range.end.row());
18645                let start = range.start.to_point(&display_map);
18646                let end = range.end.to_point(&display_map);
18647                start..end
18648            })
18649            .collect::<Vec<_>>();
18650
18651        self.unfold_ranges(&ranges, true, true, cx);
18652    }
18653
18654    pub fn unfold_at(
18655        &mut self,
18656        buffer_row: MultiBufferRow,
18657        _window: &mut Window,
18658        cx: &mut Context<Self>,
18659    ) {
18660        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18661
18662        let intersection_range = Point::new(buffer_row.0, 0)
18663            ..Point::new(
18664                buffer_row.0,
18665                display_map.buffer_snapshot().line_len(buffer_row),
18666            );
18667
18668        let autoscroll = self
18669            .selections
18670            .all::<Point>(&display_map)
18671            .iter()
18672            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18673
18674        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18675    }
18676
18677    pub fn unfold_all(
18678        &mut self,
18679        _: &actions::UnfoldAll,
18680        _window: &mut Window,
18681        cx: &mut Context<Self>,
18682    ) {
18683        if self.buffer.read(cx).is_singleton() {
18684            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18685            self.unfold_ranges(&[0..display_map.buffer_snapshot().len()], true, true, cx);
18686        } else {
18687            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18688                editor
18689                    .update(cx, |editor, cx| {
18690                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18691                            editor.unfold_buffer(buffer_id, cx);
18692                        }
18693                    })
18694                    .ok();
18695            });
18696        }
18697    }
18698
18699    pub fn fold_selected_ranges(
18700        &mut self,
18701        _: &FoldSelectedRanges,
18702        window: &mut Window,
18703        cx: &mut Context<Self>,
18704    ) {
18705        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18706        let selections = self.selections.all_adjusted(&display_map);
18707        let ranges = selections
18708            .into_iter()
18709            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18710            .collect::<Vec<_>>();
18711        self.fold_creases(ranges, true, window, cx);
18712    }
18713
18714    pub fn fold_ranges<T: ToOffset + Clone>(
18715        &mut self,
18716        ranges: Vec<Range<T>>,
18717        auto_scroll: bool,
18718        window: &mut Window,
18719        cx: &mut Context<Self>,
18720    ) {
18721        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18722        let ranges = ranges
18723            .into_iter()
18724            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18725            .collect::<Vec<_>>();
18726        self.fold_creases(ranges, auto_scroll, window, cx);
18727    }
18728
18729    pub fn fold_creases<T: ToOffset + Clone>(
18730        &mut self,
18731        creases: Vec<Crease<T>>,
18732        auto_scroll: bool,
18733        _window: &mut Window,
18734        cx: &mut Context<Self>,
18735    ) {
18736        if creases.is_empty() {
18737            return;
18738        }
18739
18740        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18741
18742        if auto_scroll {
18743            self.request_autoscroll(Autoscroll::fit(), cx);
18744        }
18745
18746        cx.notify();
18747
18748        self.scrollbar_marker_state.dirty = true;
18749        self.folds_did_change(cx);
18750    }
18751
18752    /// Removes any folds whose ranges intersect any of the given ranges.
18753    pub fn unfold_ranges<T: ToOffset + Clone>(
18754        &mut self,
18755        ranges: &[Range<T>],
18756        inclusive: bool,
18757        auto_scroll: bool,
18758        cx: &mut Context<Self>,
18759    ) {
18760        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18761            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18762        });
18763        self.folds_did_change(cx);
18764    }
18765
18766    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18767        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18768            return;
18769        }
18770        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18771        self.display_map.update(cx, |display_map, cx| {
18772            display_map.fold_buffers([buffer_id], cx)
18773        });
18774        cx.emit(EditorEvent::BufferFoldToggled {
18775            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18776            folded: true,
18777        });
18778        cx.notify();
18779    }
18780
18781    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18782        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18783            return;
18784        }
18785        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18786        self.display_map.update(cx, |display_map, cx| {
18787            display_map.unfold_buffers([buffer_id], cx);
18788        });
18789        cx.emit(EditorEvent::BufferFoldToggled {
18790            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18791            folded: false,
18792        });
18793        cx.notify();
18794    }
18795
18796    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18797        self.display_map.read(cx).is_buffer_folded(buffer)
18798    }
18799
18800    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18801        self.display_map.read(cx).folded_buffers()
18802    }
18803
18804    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18805        self.display_map.update(cx, |display_map, cx| {
18806            display_map.disable_header_for_buffer(buffer_id, cx);
18807        });
18808        cx.notify();
18809    }
18810
18811    /// Removes any folds with the given ranges.
18812    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18813        &mut self,
18814        ranges: &[Range<T>],
18815        type_id: TypeId,
18816        auto_scroll: bool,
18817        cx: &mut Context<Self>,
18818    ) {
18819        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18820            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18821        });
18822        self.folds_did_change(cx);
18823    }
18824
18825    fn remove_folds_with<T: ToOffset + Clone>(
18826        &mut self,
18827        ranges: &[Range<T>],
18828        auto_scroll: bool,
18829        cx: &mut Context<Self>,
18830        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18831    ) {
18832        if ranges.is_empty() {
18833            return;
18834        }
18835
18836        let mut buffers_affected = HashSet::default();
18837        let multi_buffer = self.buffer().read(cx);
18838        for range in ranges {
18839            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18840                buffers_affected.insert(buffer.read(cx).remote_id());
18841            };
18842        }
18843
18844        self.display_map.update(cx, update);
18845
18846        if auto_scroll {
18847            self.request_autoscroll(Autoscroll::fit(), cx);
18848        }
18849
18850        cx.notify();
18851        self.scrollbar_marker_state.dirty = true;
18852        self.active_indent_guides_state.dirty = true;
18853    }
18854
18855    pub fn update_renderer_widths(
18856        &mut self,
18857        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18858        cx: &mut Context<Self>,
18859    ) -> bool {
18860        self.display_map
18861            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18862    }
18863
18864    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18865        self.display_map.read(cx).fold_placeholder.clone()
18866    }
18867
18868    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18869        self.buffer.update(cx, |buffer, cx| {
18870            buffer.set_all_diff_hunks_expanded(cx);
18871        });
18872    }
18873
18874    pub fn expand_all_diff_hunks(
18875        &mut self,
18876        _: &ExpandAllDiffHunks,
18877        _window: &mut Window,
18878        cx: &mut Context<Self>,
18879    ) {
18880        self.buffer.update(cx, |buffer, cx| {
18881            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18882        });
18883    }
18884
18885    pub fn collapse_all_diff_hunks(
18886        &mut self,
18887        _: &CollapseAllDiffHunks,
18888        _window: &mut Window,
18889        cx: &mut Context<Self>,
18890    ) {
18891        self.buffer.update(cx, |buffer, cx| {
18892            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18893        });
18894    }
18895
18896    pub fn toggle_selected_diff_hunks(
18897        &mut self,
18898        _: &ToggleSelectedDiffHunks,
18899        _window: &mut Window,
18900        cx: &mut Context<Self>,
18901    ) {
18902        let ranges: Vec<_> = self
18903            .selections
18904            .disjoint_anchors()
18905            .iter()
18906            .map(|s| s.range())
18907            .collect();
18908        self.toggle_diff_hunks_in_ranges(ranges, cx);
18909    }
18910
18911    pub fn diff_hunks_in_ranges<'a>(
18912        &'a self,
18913        ranges: &'a [Range<Anchor>],
18914        buffer: &'a MultiBufferSnapshot,
18915    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18916        ranges.iter().flat_map(move |range| {
18917            let end_excerpt_id = range.end.excerpt_id;
18918            let range = range.to_point(buffer);
18919            let mut peek_end = range.end;
18920            if range.end.row < buffer.max_row().0 {
18921                peek_end = Point::new(range.end.row + 1, 0);
18922            }
18923            buffer
18924                .diff_hunks_in_range(range.start..peek_end)
18925                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18926        })
18927    }
18928
18929    pub fn has_stageable_diff_hunks_in_ranges(
18930        &self,
18931        ranges: &[Range<Anchor>],
18932        snapshot: &MultiBufferSnapshot,
18933    ) -> bool {
18934        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18935        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18936    }
18937
18938    pub fn toggle_staged_selected_diff_hunks(
18939        &mut self,
18940        _: &::git::ToggleStaged,
18941        _: &mut Window,
18942        cx: &mut Context<Self>,
18943    ) {
18944        let snapshot = self.buffer.read(cx).snapshot(cx);
18945        let ranges: Vec<_> = self
18946            .selections
18947            .disjoint_anchors()
18948            .iter()
18949            .map(|s| s.range())
18950            .collect();
18951        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18952        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18953    }
18954
18955    pub fn set_render_diff_hunk_controls(
18956        &mut self,
18957        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18958        cx: &mut Context<Self>,
18959    ) {
18960        self.render_diff_hunk_controls = render_diff_hunk_controls;
18961        cx.notify();
18962    }
18963
18964    pub fn stage_and_next(
18965        &mut self,
18966        _: &::git::StageAndNext,
18967        window: &mut Window,
18968        cx: &mut Context<Self>,
18969    ) {
18970        self.do_stage_or_unstage_and_next(true, window, cx);
18971    }
18972
18973    pub fn unstage_and_next(
18974        &mut self,
18975        _: &::git::UnstageAndNext,
18976        window: &mut Window,
18977        cx: &mut Context<Self>,
18978    ) {
18979        self.do_stage_or_unstage_and_next(false, window, cx);
18980    }
18981
18982    pub fn stage_or_unstage_diff_hunks(
18983        &mut self,
18984        stage: bool,
18985        ranges: Vec<Range<Anchor>>,
18986        cx: &mut Context<Self>,
18987    ) {
18988        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18989        cx.spawn(async move |this, cx| {
18990            task.await?;
18991            this.update(cx, |this, cx| {
18992                let snapshot = this.buffer.read(cx).snapshot(cx);
18993                let chunk_by = this
18994                    .diff_hunks_in_ranges(&ranges, &snapshot)
18995                    .chunk_by(|hunk| hunk.buffer_id);
18996                for (buffer_id, hunks) in &chunk_by {
18997                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18998                }
18999            })
19000        })
19001        .detach_and_log_err(cx);
19002    }
19003
19004    fn save_buffers_for_ranges_if_needed(
19005        &mut self,
19006        ranges: &[Range<Anchor>],
19007        cx: &mut Context<Editor>,
19008    ) -> Task<Result<()>> {
19009        let multibuffer = self.buffer.read(cx);
19010        let snapshot = multibuffer.read(cx);
19011        let buffer_ids: HashSet<_> = ranges
19012            .iter()
19013            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
19014            .collect();
19015        drop(snapshot);
19016
19017        let mut buffers = HashSet::default();
19018        for buffer_id in buffer_ids {
19019            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
19020                let buffer = buffer_entity.read(cx);
19021                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
19022                {
19023                    buffers.insert(buffer_entity);
19024                }
19025            }
19026        }
19027
19028        if let Some(project) = &self.project {
19029            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
19030        } else {
19031            Task::ready(Ok(()))
19032        }
19033    }
19034
19035    fn do_stage_or_unstage_and_next(
19036        &mut self,
19037        stage: bool,
19038        window: &mut Window,
19039        cx: &mut Context<Self>,
19040    ) {
19041        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
19042
19043        if ranges.iter().any(|range| range.start != range.end) {
19044            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19045            return;
19046        }
19047
19048        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19049        let snapshot = self.snapshot(window, cx);
19050        let position = self
19051            .selections
19052            .newest::<Point>(&snapshot.display_snapshot)
19053            .head();
19054        let mut row = snapshot
19055            .buffer_snapshot()
19056            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
19057            .find(|hunk| hunk.row_range.start.0 > position.row)
19058            .map(|hunk| hunk.row_range.start);
19059
19060        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
19061        // Outside of the project diff editor, wrap around to the beginning.
19062        if !all_diff_hunks_expanded {
19063            row = row.or_else(|| {
19064                snapshot
19065                    .buffer_snapshot()
19066                    .diff_hunks_in_range(Point::zero()..position)
19067                    .find(|hunk| hunk.row_range.end.0 < position.row)
19068                    .map(|hunk| hunk.row_range.start)
19069            });
19070        }
19071
19072        if let Some(row) = row {
19073            let destination = Point::new(row.0, 0);
19074            let autoscroll = Autoscroll::center();
19075
19076            self.unfold_ranges(&[destination..destination], false, false, cx);
19077            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
19078                s.select_ranges([destination..destination]);
19079            });
19080        }
19081    }
19082
19083    fn do_stage_or_unstage(
19084        &self,
19085        stage: bool,
19086        buffer_id: BufferId,
19087        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
19088        cx: &mut App,
19089    ) -> Option<()> {
19090        let project = self.project()?;
19091        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19092        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19093        let buffer_snapshot = buffer.read(cx).snapshot();
19094        let file_exists = buffer_snapshot
19095            .file()
19096            .is_some_and(|file| file.disk_state().exists());
19097        diff.update(cx, |diff, cx| {
19098            diff.stage_or_unstage_hunks(
19099                stage,
19100                &hunks
19101                    .map(|hunk| buffer_diff::DiffHunk {
19102                        buffer_range: hunk.buffer_range,
19103                        diff_base_byte_range: hunk.diff_base_byte_range,
19104                        secondary_status: hunk.secondary_status,
19105                        range: Point::zero()..Point::zero(), // unused
19106                    })
19107                    .collect::<Vec<_>>(),
19108                &buffer_snapshot,
19109                file_exists,
19110                cx,
19111            )
19112        });
19113        None
19114    }
19115
19116    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19117        let ranges: Vec<_> = self
19118            .selections
19119            .disjoint_anchors()
19120            .iter()
19121            .map(|s| s.range())
19122            .collect();
19123        self.buffer
19124            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19125    }
19126
19127    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19128        self.buffer.update(cx, |buffer, cx| {
19129            let ranges = vec![Anchor::min()..Anchor::max()];
19130            if !buffer.all_diff_hunks_expanded()
19131                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19132            {
19133                buffer.collapse_diff_hunks(ranges, cx);
19134                true
19135            } else {
19136                false
19137            }
19138        })
19139    }
19140
19141    fn toggle_diff_hunks_in_ranges(
19142        &mut self,
19143        ranges: Vec<Range<Anchor>>,
19144        cx: &mut Context<Editor>,
19145    ) {
19146        self.buffer.update(cx, |buffer, cx| {
19147            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
19148            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
19149        })
19150    }
19151
19152    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
19153        self.buffer.update(cx, |buffer, cx| {
19154            let snapshot = buffer.snapshot(cx);
19155            let excerpt_id = range.end.excerpt_id;
19156            let point_range = range.to_point(&snapshot);
19157            let expand = !buffer.single_hunk_is_expanded(range, cx);
19158            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
19159        })
19160    }
19161
19162    pub(crate) fn apply_all_diff_hunks(
19163        &mut self,
19164        _: &ApplyAllDiffHunks,
19165        window: &mut Window,
19166        cx: &mut Context<Self>,
19167    ) {
19168        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19169
19170        let buffers = self.buffer.read(cx).all_buffers();
19171        for branch_buffer in buffers {
19172            branch_buffer.update(cx, |branch_buffer, cx| {
19173                branch_buffer.merge_into_base(Vec::new(), cx);
19174            });
19175        }
19176
19177        if let Some(project) = self.project.clone() {
19178            self.save(
19179                SaveOptions {
19180                    format: true,
19181                    autosave: false,
19182                },
19183                project,
19184                window,
19185                cx,
19186            )
19187            .detach_and_log_err(cx);
19188        }
19189    }
19190
19191    pub(crate) fn apply_selected_diff_hunks(
19192        &mut self,
19193        _: &ApplyDiffHunk,
19194        window: &mut Window,
19195        cx: &mut Context<Self>,
19196    ) {
19197        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19198        let snapshot = self.snapshot(window, cx);
19199        let hunks = snapshot.hunks_for_ranges(
19200            self.selections
19201                .all(&snapshot.display_snapshot)
19202                .into_iter()
19203                .map(|selection| selection.range()),
19204        );
19205        let mut ranges_by_buffer = HashMap::default();
19206        self.transact(window, cx, |editor, _window, cx| {
19207            for hunk in hunks {
19208                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19209                    ranges_by_buffer
19210                        .entry(buffer.clone())
19211                        .or_insert_with(Vec::new)
19212                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19213                }
19214            }
19215
19216            for (buffer, ranges) in ranges_by_buffer {
19217                buffer.update(cx, |buffer, cx| {
19218                    buffer.merge_into_base(ranges, cx);
19219                });
19220            }
19221        });
19222
19223        if let Some(project) = self.project.clone() {
19224            self.save(
19225                SaveOptions {
19226                    format: true,
19227                    autosave: false,
19228                },
19229                project,
19230                window,
19231                cx,
19232            )
19233            .detach_and_log_err(cx);
19234        }
19235    }
19236
19237    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19238        if hovered != self.gutter_hovered {
19239            self.gutter_hovered = hovered;
19240            cx.notify();
19241        }
19242    }
19243
19244    pub fn insert_blocks(
19245        &mut self,
19246        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19247        autoscroll: Option<Autoscroll>,
19248        cx: &mut Context<Self>,
19249    ) -> Vec<CustomBlockId> {
19250        let blocks = self
19251            .display_map
19252            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19253        if let Some(autoscroll) = autoscroll {
19254            self.request_autoscroll(autoscroll, cx);
19255        }
19256        cx.notify();
19257        blocks
19258    }
19259
19260    pub fn resize_blocks(
19261        &mut self,
19262        heights: HashMap<CustomBlockId, u32>,
19263        autoscroll: Option<Autoscroll>,
19264        cx: &mut Context<Self>,
19265    ) {
19266        self.display_map
19267            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19268        if let Some(autoscroll) = autoscroll {
19269            self.request_autoscroll(autoscroll, cx);
19270        }
19271        cx.notify();
19272    }
19273
19274    pub fn replace_blocks(
19275        &mut self,
19276        renderers: HashMap<CustomBlockId, RenderBlock>,
19277        autoscroll: Option<Autoscroll>,
19278        cx: &mut Context<Self>,
19279    ) {
19280        self.display_map
19281            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19282        if let Some(autoscroll) = autoscroll {
19283            self.request_autoscroll(autoscroll, cx);
19284        }
19285        cx.notify();
19286    }
19287
19288    pub fn remove_blocks(
19289        &mut self,
19290        block_ids: HashSet<CustomBlockId>,
19291        autoscroll: Option<Autoscroll>,
19292        cx: &mut Context<Self>,
19293    ) {
19294        self.display_map.update(cx, |display_map, cx| {
19295            display_map.remove_blocks(block_ids, cx)
19296        });
19297        if let Some(autoscroll) = autoscroll {
19298            self.request_autoscroll(autoscroll, cx);
19299        }
19300        cx.notify();
19301    }
19302
19303    pub fn row_for_block(
19304        &self,
19305        block_id: CustomBlockId,
19306        cx: &mut Context<Self>,
19307    ) -> Option<DisplayRow> {
19308        self.display_map
19309            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19310    }
19311
19312    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19313        self.focused_block = Some(focused_block);
19314    }
19315
19316    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19317        self.focused_block.take()
19318    }
19319
19320    pub fn insert_creases(
19321        &mut self,
19322        creases: impl IntoIterator<Item = Crease<Anchor>>,
19323        cx: &mut Context<Self>,
19324    ) -> Vec<CreaseId> {
19325        self.display_map
19326            .update(cx, |map, cx| map.insert_creases(creases, cx))
19327    }
19328
19329    pub fn remove_creases(
19330        &mut self,
19331        ids: impl IntoIterator<Item = CreaseId>,
19332        cx: &mut Context<Self>,
19333    ) -> Vec<(CreaseId, Range<Anchor>)> {
19334        self.display_map
19335            .update(cx, |map, cx| map.remove_creases(ids, cx))
19336    }
19337
19338    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19339        self.display_map
19340            .update(cx, |map, cx| map.snapshot(cx))
19341            .longest_row()
19342    }
19343
19344    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19345        self.display_map
19346            .update(cx, |map, cx| map.snapshot(cx))
19347            .max_point()
19348    }
19349
19350    pub fn text(&self, cx: &App) -> String {
19351        self.buffer.read(cx).read(cx).text()
19352    }
19353
19354    pub fn is_empty(&self, cx: &App) -> bool {
19355        self.buffer.read(cx).read(cx).is_empty()
19356    }
19357
19358    pub fn text_option(&self, cx: &App) -> Option<String> {
19359        let text = self.text(cx);
19360        let text = text.trim();
19361
19362        if text.is_empty() {
19363            return None;
19364        }
19365
19366        Some(text.to_string())
19367    }
19368
19369    pub fn set_text(
19370        &mut self,
19371        text: impl Into<Arc<str>>,
19372        window: &mut Window,
19373        cx: &mut Context<Self>,
19374    ) {
19375        self.transact(window, cx, |this, _, cx| {
19376            this.buffer
19377                .read(cx)
19378                .as_singleton()
19379                .expect("you can only call set_text on editors for singleton buffers")
19380                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19381        });
19382    }
19383
19384    pub fn display_text(&self, cx: &mut App) -> String {
19385        self.display_map
19386            .update(cx, |map, cx| map.snapshot(cx))
19387            .text()
19388    }
19389
19390    fn create_minimap(
19391        &self,
19392        minimap_settings: MinimapSettings,
19393        window: &mut Window,
19394        cx: &mut Context<Self>,
19395    ) -> Option<Entity<Self>> {
19396        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19397            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19398    }
19399
19400    fn initialize_new_minimap(
19401        &self,
19402        minimap_settings: MinimapSettings,
19403        window: &mut Window,
19404        cx: &mut Context<Self>,
19405    ) -> Entity<Self> {
19406        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19407
19408        let mut minimap = Editor::new_internal(
19409            EditorMode::Minimap {
19410                parent: cx.weak_entity(),
19411            },
19412            self.buffer.clone(),
19413            None,
19414            Some(self.display_map.clone()),
19415            window,
19416            cx,
19417        );
19418        minimap.scroll_manager.clone_state(&self.scroll_manager);
19419        minimap.set_text_style_refinement(TextStyleRefinement {
19420            font_size: Some(MINIMAP_FONT_SIZE),
19421            font_weight: Some(MINIMAP_FONT_WEIGHT),
19422            ..Default::default()
19423        });
19424        minimap.update_minimap_configuration(minimap_settings, cx);
19425        cx.new(|_| minimap)
19426    }
19427
19428    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19429        let current_line_highlight = minimap_settings
19430            .current_line_highlight
19431            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19432        self.set_current_line_highlight(Some(current_line_highlight));
19433    }
19434
19435    pub fn minimap(&self) -> Option<&Entity<Self>> {
19436        self.minimap
19437            .as_ref()
19438            .filter(|_| self.minimap_visibility.visible())
19439    }
19440
19441    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19442        let mut wrap_guides = smallvec![];
19443
19444        if self.show_wrap_guides == Some(false) {
19445            return wrap_guides;
19446        }
19447
19448        let settings = self.buffer.read(cx).language_settings(cx);
19449        if settings.show_wrap_guides {
19450            match self.soft_wrap_mode(cx) {
19451                SoftWrap::Column(soft_wrap) => {
19452                    wrap_guides.push((soft_wrap as usize, true));
19453                }
19454                SoftWrap::Bounded(soft_wrap) => {
19455                    wrap_guides.push((soft_wrap as usize, true));
19456                }
19457                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19458            }
19459            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19460        }
19461
19462        wrap_guides
19463    }
19464
19465    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19466        let settings = self.buffer.read(cx).language_settings(cx);
19467        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19468        match mode {
19469            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19470                SoftWrap::None
19471            }
19472            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19473            language_settings::SoftWrap::PreferredLineLength => {
19474                SoftWrap::Column(settings.preferred_line_length)
19475            }
19476            language_settings::SoftWrap::Bounded => {
19477                SoftWrap::Bounded(settings.preferred_line_length)
19478            }
19479        }
19480    }
19481
19482    pub fn set_soft_wrap_mode(
19483        &mut self,
19484        mode: language_settings::SoftWrap,
19485
19486        cx: &mut Context<Self>,
19487    ) {
19488        self.soft_wrap_mode_override = Some(mode);
19489        cx.notify();
19490    }
19491
19492    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19493        self.hard_wrap = hard_wrap;
19494        cx.notify();
19495    }
19496
19497    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19498        self.text_style_refinement = Some(style);
19499    }
19500
19501    /// called by the Element so we know what style we were most recently rendered with.
19502    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19503        // We intentionally do not inform the display map about the minimap style
19504        // so that wrapping is not recalculated and stays consistent for the editor
19505        // and its linked minimap.
19506        if !self.mode.is_minimap() {
19507            let font = style.text.font();
19508            let font_size = style.text.font_size.to_pixels(window.rem_size());
19509            let display_map = self
19510                .placeholder_display_map
19511                .as_ref()
19512                .filter(|_| self.is_empty(cx))
19513                .unwrap_or(&self.display_map);
19514
19515            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19516        }
19517        self.style = Some(style);
19518    }
19519
19520    pub fn style(&self) -> Option<&EditorStyle> {
19521        self.style.as_ref()
19522    }
19523
19524    // Called by the element. This method is not designed to be called outside of the editor
19525    // element's layout code because it does not notify when rewrapping is computed synchronously.
19526    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19527        if self.is_empty(cx) {
19528            self.placeholder_display_map
19529                .as_ref()
19530                .map_or(false, |display_map| {
19531                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19532                })
19533        } else {
19534            self.display_map
19535                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19536        }
19537    }
19538
19539    pub fn set_soft_wrap(&mut self) {
19540        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19541    }
19542
19543    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19544        if self.soft_wrap_mode_override.is_some() {
19545            self.soft_wrap_mode_override.take();
19546        } else {
19547            let soft_wrap = match self.soft_wrap_mode(cx) {
19548                SoftWrap::GitDiff => return,
19549                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19550                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19551                    language_settings::SoftWrap::None
19552                }
19553            };
19554            self.soft_wrap_mode_override = Some(soft_wrap);
19555        }
19556        cx.notify();
19557    }
19558
19559    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19560        let Some(workspace) = self.workspace() else {
19561            return;
19562        };
19563        let fs = workspace.read(cx).app_state().fs.clone();
19564        let current_show = TabBarSettings::get_global(cx).show;
19565        update_settings_file(fs, cx, move |setting, _| {
19566            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19567        });
19568    }
19569
19570    pub fn toggle_indent_guides(
19571        &mut self,
19572        _: &ToggleIndentGuides,
19573        _: &mut Window,
19574        cx: &mut Context<Self>,
19575    ) {
19576        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19577            self.buffer
19578                .read(cx)
19579                .language_settings(cx)
19580                .indent_guides
19581                .enabled
19582        });
19583        self.show_indent_guides = Some(!currently_enabled);
19584        cx.notify();
19585    }
19586
19587    fn should_show_indent_guides(&self) -> Option<bool> {
19588        self.show_indent_guides
19589    }
19590
19591    pub fn toggle_line_numbers(
19592        &mut self,
19593        _: &ToggleLineNumbers,
19594        _: &mut Window,
19595        cx: &mut Context<Self>,
19596    ) {
19597        let mut editor_settings = EditorSettings::get_global(cx).clone();
19598        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19599        EditorSettings::override_global(editor_settings, cx);
19600    }
19601
19602    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19603        if let Some(show_line_numbers) = self.show_line_numbers {
19604            return show_line_numbers;
19605        }
19606        EditorSettings::get_global(cx).gutter.line_numbers
19607    }
19608
19609    pub fn relative_line_numbers(&self, cx: &mut App) -> RelativeLineNumbers {
19610        match (
19611            self.use_relative_line_numbers,
19612            EditorSettings::get_global(cx).relative_line_numbers,
19613        ) {
19614            (None, setting) => setting,
19615            (Some(false), _) => RelativeLineNumbers::Disabled,
19616            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
19617            (Some(true), _) => RelativeLineNumbers::Enabled,
19618        }
19619    }
19620
19621    pub fn toggle_relative_line_numbers(
19622        &mut self,
19623        _: &ToggleRelativeLineNumbers,
19624        _: &mut Window,
19625        cx: &mut Context<Self>,
19626    ) {
19627        let is_relative = self.relative_line_numbers(cx);
19628        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
19629    }
19630
19631    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19632        self.use_relative_line_numbers = is_relative;
19633        cx.notify();
19634    }
19635
19636    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19637        self.show_gutter = show_gutter;
19638        cx.notify();
19639    }
19640
19641    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19642        self.show_scrollbars = ScrollbarAxes {
19643            horizontal: show,
19644            vertical: show,
19645        };
19646        cx.notify();
19647    }
19648
19649    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19650        self.show_scrollbars.vertical = show;
19651        cx.notify();
19652    }
19653
19654    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19655        self.show_scrollbars.horizontal = show;
19656        cx.notify();
19657    }
19658
19659    pub fn set_minimap_visibility(
19660        &mut self,
19661        minimap_visibility: MinimapVisibility,
19662        window: &mut Window,
19663        cx: &mut Context<Self>,
19664    ) {
19665        if self.minimap_visibility != minimap_visibility {
19666            if minimap_visibility.visible() && self.minimap.is_none() {
19667                let minimap_settings = EditorSettings::get_global(cx).minimap;
19668                self.minimap =
19669                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19670            }
19671            self.minimap_visibility = minimap_visibility;
19672            cx.notify();
19673        }
19674    }
19675
19676    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19677        self.set_show_scrollbars(false, cx);
19678        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19679    }
19680
19681    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19682        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19683    }
19684
19685    /// Normally the text in full mode and auto height editors is padded on the
19686    /// left side by roughly half a character width for improved hit testing.
19687    ///
19688    /// Use this method to disable this for cases where this is not wanted (e.g.
19689    /// if you want to align the editor text with some other text above or below)
19690    /// or if you want to add this padding to single-line editors.
19691    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19692        self.offset_content = offset_content;
19693        cx.notify();
19694    }
19695
19696    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19697        self.show_line_numbers = Some(show_line_numbers);
19698        cx.notify();
19699    }
19700
19701    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19702        self.disable_expand_excerpt_buttons = true;
19703        cx.notify();
19704    }
19705
19706    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19707        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19708        cx.notify();
19709    }
19710
19711    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19712        self.show_code_actions = Some(show_code_actions);
19713        cx.notify();
19714    }
19715
19716    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19717        self.show_runnables = Some(show_runnables);
19718        cx.notify();
19719    }
19720
19721    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19722        self.show_breakpoints = Some(show_breakpoints);
19723        cx.notify();
19724    }
19725
19726    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19727        if self.display_map.read(cx).masked != masked {
19728            self.display_map.update(cx, |map, _| map.masked = masked);
19729        }
19730        cx.notify()
19731    }
19732
19733    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19734        self.show_wrap_guides = Some(show_wrap_guides);
19735        cx.notify();
19736    }
19737
19738    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19739        self.show_indent_guides = Some(show_indent_guides);
19740        cx.notify();
19741    }
19742
19743    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19744        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19745            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19746                && let Some(dir) = file.abs_path(cx).parent()
19747            {
19748                return Some(dir.to_owned());
19749            }
19750        }
19751
19752        None
19753    }
19754
19755    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19756        self.active_excerpt(cx)?
19757            .1
19758            .read(cx)
19759            .file()
19760            .and_then(|f| f.as_local())
19761    }
19762
19763    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19764        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19765            let buffer = buffer.read(cx);
19766            if let Some(project_path) = buffer.project_path(cx) {
19767                let project = self.project()?.read(cx);
19768                project.absolute_path(&project_path, cx)
19769            } else {
19770                buffer
19771                    .file()
19772                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19773            }
19774        })
19775    }
19776
19777    pub fn reveal_in_finder(
19778        &mut self,
19779        _: &RevealInFileManager,
19780        _window: &mut Window,
19781        cx: &mut Context<Self>,
19782    ) {
19783        if let Some(target) = self.target_file(cx) {
19784            cx.reveal_path(&target.abs_path(cx));
19785        }
19786    }
19787
19788    pub fn copy_path(
19789        &mut self,
19790        _: &zed_actions::workspace::CopyPath,
19791        _window: &mut Window,
19792        cx: &mut Context<Self>,
19793    ) {
19794        if let Some(path) = self.target_file_abs_path(cx)
19795            && let Some(path) = path.to_str()
19796        {
19797            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19798        } else {
19799            cx.propagate();
19800        }
19801    }
19802
19803    pub fn copy_relative_path(
19804        &mut self,
19805        _: &zed_actions::workspace::CopyRelativePath,
19806        _window: &mut Window,
19807        cx: &mut Context<Self>,
19808    ) {
19809        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19810            let project = self.project()?.read(cx);
19811            let path = buffer.read(cx).file()?.path();
19812            let path = path.display(project.path_style(cx));
19813            Some(path)
19814        }) {
19815            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19816        } else {
19817            cx.propagate();
19818        }
19819    }
19820
19821    /// Returns the project path for the editor's buffer, if any buffer is
19822    /// opened in the editor.
19823    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19824        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19825            buffer.read(cx).project_path(cx)
19826        } else {
19827            None
19828        }
19829    }
19830
19831    // Returns true if the editor handled a go-to-line request
19832    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19833        maybe!({
19834            let breakpoint_store = self.breakpoint_store.as_ref()?;
19835
19836            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19837            else {
19838                self.clear_row_highlights::<ActiveDebugLine>();
19839                return None;
19840            };
19841
19842            let position = active_stack_frame.position;
19843            let buffer_id = position.buffer_id?;
19844            let snapshot = self
19845                .project
19846                .as_ref()?
19847                .read(cx)
19848                .buffer_for_id(buffer_id, cx)?
19849                .read(cx)
19850                .snapshot();
19851
19852            let mut handled = false;
19853            for (id, ExcerptRange { context, .. }) in
19854                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19855            {
19856                if context.start.cmp(&position, &snapshot).is_ge()
19857                    || context.end.cmp(&position, &snapshot).is_lt()
19858                {
19859                    continue;
19860                }
19861                let snapshot = self.buffer.read(cx).snapshot(cx);
19862                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19863
19864                handled = true;
19865                self.clear_row_highlights::<ActiveDebugLine>();
19866
19867                self.go_to_line::<ActiveDebugLine>(
19868                    multibuffer_anchor,
19869                    Some(cx.theme().colors().editor_debugger_active_line_background),
19870                    window,
19871                    cx,
19872                );
19873
19874                cx.notify();
19875            }
19876
19877            handled.then_some(())
19878        })
19879        .is_some()
19880    }
19881
19882    pub fn copy_file_name_without_extension(
19883        &mut self,
19884        _: &CopyFileNameWithoutExtension,
19885        _: &mut Window,
19886        cx: &mut Context<Self>,
19887    ) {
19888        if let Some(file) = self.target_file(cx)
19889            && let Some(file_stem) = file.path().file_stem()
19890        {
19891            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
19892        }
19893    }
19894
19895    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19896        if let Some(file) = self.target_file(cx)
19897            && let Some(name) = file.path().file_name()
19898        {
19899            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19900        }
19901    }
19902
19903    pub fn toggle_git_blame(
19904        &mut self,
19905        _: &::git::Blame,
19906        window: &mut Window,
19907        cx: &mut Context<Self>,
19908    ) {
19909        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19910
19911        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19912            self.start_git_blame(true, window, cx);
19913        }
19914
19915        cx.notify();
19916    }
19917
19918    pub fn toggle_git_blame_inline(
19919        &mut self,
19920        _: &ToggleGitBlameInline,
19921        window: &mut Window,
19922        cx: &mut Context<Self>,
19923    ) {
19924        self.toggle_git_blame_inline_internal(true, window, cx);
19925        cx.notify();
19926    }
19927
19928    pub fn open_git_blame_commit(
19929        &mut self,
19930        _: &OpenGitBlameCommit,
19931        window: &mut Window,
19932        cx: &mut Context<Self>,
19933    ) {
19934        self.open_git_blame_commit_internal(window, cx);
19935    }
19936
19937    fn open_git_blame_commit_internal(
19938        &mut self,
19939        window: &mut Window,
19940        cx: &mut Context<Self>,
19941    ) -> Option<()> {
19942        let blame = self.blame.as_ref()?;
19943        let snapshot = self.snapshot(window, cx);
19944        let cursor = self
19945            .selections
19946            .newest::<Point>(&snapshot.display_snapshot)
19947            .head();
19948        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
19949        let (_, blame_entry) = blame
19950            .update(cx, |blame, cx| {
19951                blame
19952                    .blame_for_rows(
19953                        &[RowInfo {
19954                            buffer_id: Some(buffer.remote_id()),
19955                            buffer_row: Some(point.row),
19956                            ..Default::default()
19957                        }],
19958                        cx,
19959                    )
19960                    .next()
19961            })
19962            .flatten()?;
19963        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19964        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19965        let workspace = self.workspace()?.downgrade();
19966        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19967        None
19968    }
19969
19970    pub fn git_blame_inline_enabled(&self) -> bool {
19971        self.git_blame_inline_enabled
19972    }
19973
19974    pub fn toggle_selection_menu(
19975        &mut self,
19976        _: &ToggleSelectionMenu,
19977        _: &mut Window,
19978        cx: &mut Context<Self>,
19979    ) {
19980        self.show_selection_menu = self
19981            .show_selection_menu
19982            .map(|show_selections_menu| !show_selections_menu)
19983            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19984
19985        cx.notify();
19986    }
19987
19988    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19989        self.show_selection_menu
19990            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19991    }
19992
19993    fn start_git_blame(
19994        &mut self,
19995        user_triggered: bool,
19996        window: &mut Window,
19997        cx: &mut Context<Self>,
19998    ) {
19999        if let Some(project) = self.project() {
20000            if let Some(buffer) = self.buffer().read(cx).as_singleton()
20001                && buffer.read(cx).file().is_none()
20002            {
20003                return;
20004            }
20005
20006            let focused = self.focus_handle(cx).contains_focused(window, cx);
20007
20008            let project = project.clone();
20009            let blame = cx
20010                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
20011            self.blame_subscription =
20012                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
20013            self.blame = Some(blame);
20014        }
20015    }
20016
20017    fn toggle_git_blame_inline_internal(
20018        &mut self,
20019        user_triggered: bool,
20020        window: &mut Window,
20021        cx: &mut Context<Self>,
20022    ) {
20023        if self.git_blame_inline_enabled {
20024            self.git_blame_inline_enabled = false;
20025            self.show_git_blame_inline = false;
20026            self.show_git_blame_inline_delay_task.take();
20027        } else {
20028            self.git_blame_inline_enabled = true;
20029            self.start_git_blame_inline(user_triggered, window, cx);
20030        }
20031
20032        cx.notify();
20033    }
20034
20035    fn start_git_blame_inline(
20036        &mut self,
20037        user_triggered: bool,
20038        window: &mut Window,
20039        cx: &mut Context<Self>,
20040    ) {
20041        self.start_git_blame(user_triggered, window, cx);
20042
20043        if ProjectSettings::get_global(cx)
20044            .git
20045            .inline_blame_delay()
20046            .is_some()
20047        {
20048            self.start_inline_blame_timer(window, cx);
20049        } else {
20050            self.show_git_blame_inline = true
20051        }
20052    }
20053
20054    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
20055        self.blame.as_ref()
20056    }
20057
20058    pub fn show_git_blame_gutter(&self) -> bool {
20059        self.show_git_blame_gutter
20060    }
20061
20062    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
20063        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
20064    }
20065
20066    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
20067        self.show_git_blame_inline
20068            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
20069            && !self.newest_selection_head_on_empty_line(cx)
20070            && self.has_blame_entries(cx)
20071    }
20072
20073    fn has_blame_entries(&self, cx: &App) -> bool {
20074        self.blame()
20075            .is_some_and(|blame| blame.read(cx).has_generated_entries())
20076    }
20077
20078    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
20079        let cursor_anchor = self.selections.newest_anchor().head();
20080
20081        let snapshot = self.buffer.read(cx).snapshot(cx);
20082        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
20083
20084        snapshot.line_len(buffer_row) == 0
20085    }
20086
20087    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
20088        let buffer_and_selection = maybe!({
20089            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20090            let selection_range = selection.range();
20091
20092            let multi_buffer = self.buffer().read(cx);
20093            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20094            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
20095
20096            let (buffer, range, _) = if selection.reversed {
20097                buffer_ranges.first()
20098            } else {
20099                buffer_ranges.last()
20100            }?;
20101
20102            let selection = text::ToPoint::to_point(&range.start, buffer).row
20103                ..text::ToPoint::to_point(&range.end, buffer).row;
20104            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
20105        });
20106
20107        let Some((buffer, selection)) = buffer_and_selection else {
20108            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
20109        };
20110
20111        let Some(project) = self.project() else {
20112            return Task::ready(Err(anyhow!("editor does not have project")));
20113        };
20114
20115        project.update(cx, |project, cx| {
20116            project.get_permalink_to_line(&buffer, selection, cx)
20117        })
20118    }
20119
20120    pub fn copy_permalink_to_line(
20121        &mut self,
20122        _: &CopyPermalinkToLine,
20123        window: &mut Window,
20124        cx: &mut Context<Self>,
20125    ) {
20126        let permalink_task = self.get_permalink_to_line(cx);
20127        let workspace = self.workspace();
20128
20129        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20130            Ok(permalink) => {
20131                cx.update(|_, cx| {
20132                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
20133                })
20134                .ok();
20135            }
20136            Err(err) => {
20137                let message = format!("Failed to copy permalink: {err}");
20138
20139                anyhow::Result::<()>::Err(err).log_err();
20140
20141                if let Some(workspace) = workspace {
20142                    workspace
20143                        .update_in(cx, |workspace, _, cx| {
20144                            struct CopyPermalinkToLine;
20145
20146                            workspace.show_toast(
20147                                Toast::new(
20148                                    NotificationId::unique::<CopyPermalinkToLine>(),
20149                                    message,
20150                                ),
20151                                cx,
20152                            )
20153                        })
20154                        .ok();
20155                }
20156            }
20157        })
20158        .detach();
20159    }
20160
20161    pub fn copy_file_location(
20162        &mut self,
20163        _: &CopyFileLocation,
20164        _: &mut Window,
20165        cx: &mut Context<Self>,
20166    ) {
20167        let selection = self
20168            .selections
20169            .newest::<Point>(&self.display_snapshot(cx))
20170            .start
20171            .row
20172            + 1;
20173        if let Some(file) = self.target_file(cx) {
20174            let path = file.path().display(file.path_style(cx));
20175            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
20176        }
20177    }
20178
20179    pub fn open_permalink_to_line(
20180        &mut self,
20181        _: &OpenPermalinkToLine,
20182        window: &mut Window,
20183        cx: &mut Context<Self>,
20184    ) {
20185        let permalink_task = self.get_permalink_to_line(cx);
20186        let workspace = self.workspace();
20187
20188        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20189            Ok(permalink) => {
20190                cx.update(|_, cx| {
20191                    cx.open_url(permalink.as_ref());
20192                })
20193                .ok();
20194            }
20195            Err(err) => {
20196                let message = format!("Failed to open permalink: {err}");
20197
20198                anyhow::Result::<()>::Err(err).log_err();
20199
20200                if let Some(workspace) = workspace {
20201                    workspace
20202                        .update(cx, |workspace, cx| {
20203                            struct OpenPermalinkToLine;
20204
20205                            workspace.show_toast(
20206                                Toast::new(
20207                                    NotificationId::unique::<OpenPermalinkToLine>(),
20208                                    message,
20209                                ),
20210                                cx,
20211                            )
20212                        })
20213                        .ok();
20214                }
20215            }
20216        })
20217        .detach();
20218    }
20219
20220    pub fn insert_uuid_v4(
20221        &mut self,
20222        _: &InsertUuidV4,
20223        window: &mut Window,
20224        cx: &mut Context<Self>,
20225    ) {
20226        self.insert_uuid(UuidVersion::V4, window, cx);
20227    }
20228
20229    pub fn insert_uuid_v7(
20230        &mut self,
20231        _: &InsertUuidV7,
20232        window: &mut Window,
20233        cx: &mut Context<Self>,
20234    ) {
20235        self.insert_uuid(UuidVersion::V7, window, cx);
20236    }
20237
20238    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20239        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20240        self.transact(window, cx, |this, window, cx| {
20241            let edits = this
20242                .selections
20243                .all::<Point>(&this.display_snapshot(cx))
20244                .into_iter()
20245                .map(|selection| {
20246                    let uuid = match version {
20247                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20248                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20249                    };
20250
20251                    (selection.range(), uuid.to_string())
20252                });
20253            this.edit(edits, cx);
20254            this.refresh_edit_prediction(true, false, window, cx);
20255        });
20256    }
20257
20258    pub fn open_selections_in_multibuffer(
20259        &mut self,
20260        _: &OpenSelectionsInMultibuffer,
20261        window: &mut Window,
20262        cx: &mut Context<Self>,
20263    ) {
20264        let multibuffer = self.buffer.read(cx);
20265
20266        let Some(buffer) = multibuffer.as_singleton() else {
20267            return;
20268        };
20269
20270        let Some(workspace) = self.workspace() else {
20271            return;
20272        };
20273
20274        let title = multibuffer.title(cx).to_string();
20275
20276        let locations = self
20277            .selections
20278            .all_anchors(cx)
20279            .iter()
20280            .map(|selection| {
20281                (
20282                    buffer.clone(),
20283                    (selection.start.text_anchor..selection.end.text_anchor)
20284                        .to_point(buffer.read(cx)),
20285                )
20286            })
20287            .into_group_map();
20288
20289        cx.spawn_in(window, async move |_, cx| {
20290            workspace.update_in(cx, |workspace, window, cx| {
20291                Self::open_locations_in_multibuffer(
20292                    workspace,
20293                    locations,
20294                    format!("Selections for '{title}'"),
20295                    false,
20296                    MultibufferSelectionMode::All,
20297                    window,
20298                    cx,
20299                );
20300            })
20301        })
20302        .detach();
20303    }
20304
20305    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20306    /// last highlight added will be used.
20307    ///
20308    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20309    pub fn highlight_rows<T: 'static>(
20310        &mut self,
20311        range: Range<Anchor>,
20312        color: Hsla,
20313        options: RowHighlightOptions,
20314        cx: &mut Context<Self>,
20315    ) {
20316        let snapshot = self.buffer().read(cx).snapshot(cx);
20317        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20318        let ix = row_highlights.binary_search_by(|highlight| {
20319            Ordering::Equal
20320                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20321                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20322        });
20323
20324        if let Err(mut ix) = ix {
20325            let index = post_inc(&mut self.highlight_order);
20326
20327            // If this range intersects with the preceding highlight, then merge it with
20328            // the preceding highlight. Otherwise insert a new highlight.
20329            let mut merged = false;
20330            if ix > 0 {
20331                let prev_highlight = &mut row_highlights[ix - 1];
20332                if prev_highlight
20333                    .range
20334                    .end
20335                    .cmp(&range.start, &snapshot)
20336                    .is_ge()
20337                {
20338                    ix -= 1;
20339                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20340                        prev_highlight.range.end = range.end;
20341                    }
20342                    merged = true;
20343                    prev_highlight.index = index;
20344                    prev_highlight.color = color;
20345                    prev_highlight.options = options;
20346                }
20347            }
20348
20349            if !merged {
20350                row_highlights.insert(
20351                    ix,
20352                    RowHighlight {
20353                        range,
20354                        index,
20355                        color,
20356                        options,
20357                        type_id: TypeId::of::<T>(),
20358                    },
20359                );
20360            }
20361
20362            // If any of the following highlights intersect with this one, merge them.
20363            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20364                let highlight = &row_highlights[ix];
20365                if next_highlight
20366                    .range
20367                    .start
20368                    .cmp(&highlight.range.end, &snapshot)
20369                    .is_le()
20370                {
20371                    if next_highlight
20372                        .range
20373                        .end
20374                        .cmp(&highlight.range.end, &snapshot)
20375                        .is_gt()
20376                    {
20377                        row_highlights[ix].range.end = next_highlight.range.end;
20378                    }
20379                    row_highlights.remove(ix + 1);
20380                } else {
20381                    break;
20382                }
20383            }
20384        }
20385    }
20386
20387    /// Remove any highlighted row ranges of the given type that intersect the
20388    /// given ranges.
20389    pub fn remove_highlighted_rows<T: 'static>(
20390        &mut self,
20391        ranges_to_remove: Vec<Range<Anchor>>,
20392        cx: &mut Context<Self>,
20393    ) {
20394        let snapshot = self.buffer().read(cx).snapshot(cx);
20395        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20396        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20397        row_highlights.retain(|highlight| {
20398            while let Some(range_to_remove) = ranges_to_remove.peek() {
20399                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20400                    Ordering::Less | Ordering::Equal => {
20401                        ranges_to_remove.next();
20402                    }
20403                    Ordering::Greater => {
20404                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20405                            Ordering::Less | Ordering::Equal => {
20406                                return false;
20407                            }
20408                            Ordering::Greater => break,
20409                        }
20410                    }
20411                }
20412            }
20413
20414            true
20415        })
20416    }
20417
20418    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20419    pub fn clear_row_highlights<T: 'static>(&mut self) {
20420        self.highlighted_rows.remove(&TypeId::of::<T>());
20421    }
20422
20423    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20424    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20425        self.highlighted_rows
20426            .get(&TypeId::of::<T>())
20427            .map_or(&[] as &[_], |vec| vec.as_slice())
20428            .iter()
20429            .map(|highlight| (highlight.range.clone(), highlight.color))
20430    }
20431
20432    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20433    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20434    /// Allows to ignore certain kinds of highlights.
20435    pub fn highlighted_display_rows(
20436        &self,
20437        window: &mut Window,
20438        cx: &mut App,
20439    ) -> BTreeMap<DisplayRow, LineHighlight> {
20440        let snapshot = self.snapshot(window, cx);
20441        let mut used_highlight_orders = HashMap::default();
20442        self.highlighted_rows
20443            .iter()
20444            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20445            .fold(
20446                BTreeMap::<DisplayRow, LineHighlight>::new(),
20447                |mut unique_rows, highlight| {
20448                    let start = highlight.range.start.to_display_point(&snapshot);
20449                    let end = highlight.range.end.to_display_point(&snapshot);
20450                    let start_row = start.row().0;
20451                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20452                        && end.column() == 0
20453                    {
20454                        end.row().0.saturating_sub(1)
20455                    } else {
20456                        end.row().0
20457                    };
20458                    for row in start_row..=end_row {
20459                        let used_index =
20460                            used_highlight_orders.entry(row).or_insert(highlight.index);
20461                        if highlight.index >= *used_index {
20462                            *used_index = highlight.index;
20463                            unique_rows.insert(
20464                                DisplayRow(row),
20465                                LineHighlight {
20466                                    include_gutter: highlight.options.include_gutter,
20467                                    border: None,
20468                                    background: highlight.color.into(),
20469                                    type_id: Some(highlight.type_id),
20470                                },
20471                            );
20472                        }
20473                    }
20474                    unique_rows
20475                },
20476            )
20477    }
20478
20479    pub fn highlighted_display_row_for_autoscroll(
20480        &self,
20481        snapshot: &DisplaySnapshot,
20482    ) -> Option<DisplayRow> {
20483        self.highlighted_rows
20484            .values()
20485            .flat_map(|highlighted_rows| highlighted_rows.iter())
20486            .filter_map(|highlight| {
20487                if highlight.options.autoscroll {
20488                    Some(highlight.range.start.to_display_point(snapshot).row())
20489                } else {
20490                    None
20491                }
20492            })
20493            .min()
20494    }
20495
20496    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20497        self.highlight_background::<SearchWithinRange>(
20498            ranges,
20499            |colors| colors.colors().editor_document_highlight_read_background,
20500            cx,
20501        )
20502    }
20503
20504    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20505        self.breadcrumb_header = Some(new_header);
20506    }
20507
20508    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20509        self.clear_background_highlights::<SearchWithinRange>(cx);
20510    }
20511
20512    pub fn highlight_background<T: 'static>(
20513        &mut self,
20514        ranges: &[Range<Anchor>],
20515        color_fetcher: fn(&Theme) -> Hsla,
20516        cx: &mut Context<Self>,
20517    ) {
20518        self.background_highlights.insert(
20519            HighlightKey::Type(TypeId::of::<T>()),
20520            (color_fetcher, Arc::from(ranges)),
20521        );
20522        self.scrollbar_marker_state.dirty = true;
20523        cx.notify();
20524    }
20525
20526    pub fn highlight_background_key<T: 'static>(
20527        &mut self,
20528        key: usize,
20529        ranges: &[Range<Anchor>],
20530        color_fetcher: fn(&Theme) -> Hsla,
20531        cx: &mut Context<Self>,
20532    ) {
20533        self.background_highlights.insert(
20534            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20535            (color_fetcher, Arc::from(ranges)),
20536        );
20537        self.scrollbar_marker_state.dirty = true;
20538        cx.notify();
20539    }
20540
20541    pub fn clear_background_highlights<T: 'static>(
20542        &mut self,
20543        cx: &mut Context<Self>,
20544    ) -> Option<BackgroundHighlight> {
20545        let text_highlights = self
20546            .background_highlights
20547            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20548        if !text_highlights.1.is_empty() {
20549            self.scrollbar_marker_state.dirty = true;
20550            cx.notify();
20551        }
20552        Some(text_highlights)
20553    }
20554
20555    pub fn highlight_gutter<T: 'static>(
20556        &mut self,
20557        ranges: impl Into<Vec<Range<Anchor>>>,
20558        color_fetcher: fn(&App) -> Hsla,
20559        cx: &mut Context<Self>,
20560    ) {
20561        self.gutter_highlights
20562            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20563        cx.notify();
20564    }
20565
20566    pub fn clear_gutter_highlights<T: 'static>(
20567        &mut self,
20568        cx: &mut Context<Self>,
20569    ) -> Option<GutterHighlight> {
20570        cx.notify();
20571        self.gutter_highlights.remove(&TypeId::of::<T>())
20572    }
20573
20574    pub fn insert_gutter_highlight<T: 'static>(
20575        &mut self,
20576        range: Range<Anchor>,
20577        color_fetcher: fn(&App) -> Hsla,
20578        cx: &mut Context<Self>,
20579    ) {
20580        let snapshot = self.buffer().read(cx).snapshot(cx);
20581        let mut highlights = self
20582            .gutter_highlights
20583            .remove(&TypeId::of::<T>())
20584            .map(|(_, highlights)| highlights)
20585            .unwrap_or_default();
20586        let ix = highlights.binary_search_by(|highlight| {
20587            Ordering::Equal
20588                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20589                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20590        });
20591        if let Err(ix) = ix {
20592            highlights.insert(ix, range);
20593        }
20594        self.gutter_highlights
20595            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20596    }
20597
20598    pub fn remove_gutter_highlights<T: 'static>(
20599        &mut self,
20600        ranges_to_remove: Vec<Range<Anchor>>,
20601        cx: &mut Context<Self>,
20602    ) {
20603        let snapshot = self.buffer().read(cx).snapshot(cx);
20604        let Some((color_fetcher, mut gutter_highlights)) =
20605            self.gutter_highlights.remove(&TypeId::of::<T>())
20606        else {
20607            return;
20608        };
20609        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20610        gutter_highlights.retain(|highlight| {
20611            while let Some(range_to_remove) = ranges_to_remove.peek() {
20612                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20613                    Ordering::Less | Ordering::Equal => {
20614                        ranges_to_remove.next();
20615                    }
20616                    Ordering::Greater => {
20617                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20618                            Ordering::Less | Ordering::Equal => {
20619                                return false;
20620                            }
20621                            Ordering::Greater => break,
20622                        }
20623                    }
20624                }
20625            }
20626
20627            true
20628        });
20629        self.gutter_highlights
20630            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20631    }
20632
20633    #[cfg(feature = "test-support")]
20634    pub fn all_text_highlights(
20635        &self,
20636        window: &mut Window,
20637        cx: &mut Context<Self>,
20638    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20639        let snapshot = self.snapshot(window, cx);
20640        self.display_map.update(cx, |display_map, _| {
20641            display_map
20642                .all_text_highlights()
20643                .map(|highlight| {
20644                    let (style, ranges) = highlight.as_ref();
20645                    (
20646                        *style,
20647                        ranges
20648                            .iter()
20649                            .map(|range| range.clone().to_display_points(&snapshot))
20650                            .collect(),
20651                    )
20652                })
20653                .collect()
20654        })
20655    }
20656
20657    #[cfg(feature = "test-support")]
20658    pub fn all_text_background_highlights(
20659        &self,
20660        window: &mut Window,
20661        cx: &mut Context<Self>,
20662    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20663        let snapshot = self.snapshot(window, cx);
20664        let buffer = &snapshot.buffer_snapshot();
20665        let start = buffer.anchor_before(0);
20666        let end = buffer.anchor_after(buffer.len());
20667        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20668    }
20669
20670    #[cfg(any(test, feature = "test-support"))]
20671    pub fn sorted_background_highlights_in_range(
20672        &self,
20673        search_range: Range<Anchor>,
20674        display_snapshot: &DisplaySnapshot,
20675        theme: &Theme,
20676    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20677        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20678        res.sort_by(|a, b| {
20679            a.0.start
20680                .cmp(&b.0.start)
20681                .then_with(|| a.0.end.cmp(&b.0.end))
20682                .then_with(|| a.1.cmp(&b.1))
20683        });
20684        res
20685    }
20686
20687    #[cfg(feature = "test-support")]
20688    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20689        let snapshot = self.buffer().read(cx).snapshot(cx);
20690
20691        let highlights = self
20692            .background_highlights
20693            .get(&HighlightKey::Type(TypeId::of::<
20694                items::BufferSearchHighlights,
20695            >()));
20696
20697        if let Some((_color, ranges)) = highlights {
20698            ranges
20699                .iter()
20700                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20701                .collect_vec()
20702        } else {
20703            vec![]
20704        }
20705    }
20706
20707    fn document_highlights_for_position<'a>(
20708        &'a self,
20709        position: Anchor,
20710        buffer: &'a MultiBufferSnapshot,
20711    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20712        let read_highlights = self
20713            .background_highlights
20714            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20715            .map(|h| &h.1);
20716        let write_highlights = self
20717            .background_highlights
20718            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20719            .map(|h| &h.1);
20720        let left_position = position.bias_left(buffer);
20721        let right_position = position.bias_right(buffer);
20722        read_highlights
20723            .into_iter()
20724            .chain(write_highlights)
20725            .flat_map(move |ranges| {
20726                let start_ix = match ranges.binary_search_by(|probe| {
20727                    let cmp = probe.end.cmp(&left_position, buffer);
20728                    if cmp.is_ge() {
20729                        Ordering::Greater
20730                    } else {
20731                        Ordering::Less
20732                    }
20733                }) {
20734                    Ok(i) | Err(i) => i,
20735                };
20736
20737                ranges[start_ix..]
20738                    .iter()
20739                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20740            })
20741    }
20742
20743    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20744        self.background_highlights
20745            .get(&HighlightKey::Type(TypeId::of::<T>()))
20746            .is_some_and(|(_, highlights)| !highlights.is_empty())
20747    }
20748
20749    /// Returns all background highlights for a given range.
20750    ///
20751    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20752    pub fn background_highlights_in_range(
20753        &self,
20754        search_range: Range<Anchor>,
20755        display_snapshot: &DisplaySnapshot,
20756        theme: &Theme,
20757    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20758        let mut results = Vec::new();
20759        for (color_fetcher, ranges) in self.background_highlights.values() {
20760            let color = color_fetcher(theme);
20761            let start_ix = match ranges.binary_search_by(|probe| {
20762                let cmp = probe
20763                    .end
20764                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20765                if cmp.is_gt() {
20766                    Ordering::Greater
20767                } else {
20768                    Ordering::Less
20769                }
20770            }) {
20771                Ok(i) | Err(i) => i,
20772            };
20773            for range in &ranges[start_ix..] {
20774                if range
20775                    .start
20776                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20777                    .is_ge()
20778                {
20779                    break;
20780                }
20781
20782                let start = range.start.to_display_point(display_snapshot);
20783                let end = range.end.to_display_point(display_snapshot);
20784                results.push((start..end, color))
20785            }
20786        }
20787        results
20788    }
20789
20790    pub fn gutter_highlights_in_range(
20791        &self,
20792        search_range: Range<Anchor>,
20793        display_snapshot: &DisplaySnapshot,
20794        cx: &App,
20795    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20796        let mut results = Vec::new();
20797        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20798            let color = color_fetcher(cx);
20799            let start_ix = match ranges.binary_search_by(|probe| {
20800                let cmp = probe
20801                    .end
20802                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20803                if cmp.is_gt() {
20804                    Ordering::Greater
20805                } else {
20806                    Ordering::Less
20807                }
20808            }) {
20809                Ok(i) | Err(i) => i,
20810            };
20811            for range in &ranges[start_ix..] {
20812                if range
20813                    .start
20814                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20815                    .is_ge()
20816                {
20817                    break;
20818                }
20819
20820                let start = range.start.to_display_point(display_snapshot);
20821                let end = range.end.to_display_point(display_snapshot);
20822                results.push((start..end, color))
20823            }
20824        }
20825        results
20826    }
20827
20828    /// Get the text ranges corresponding to the redaction query
20829    pub fn redacted_ranges(
20830        &self,
20831        search_range: Range<Anchor>,
20832        display_snapshot: &DisplaySnapshot,
20833        cx: &App,
20834    ) -> Vec<Range<DisplayPoint>> {
20835        display_snapshot
20836            .buffer_snapshot()
20837            .redacted_ranges(search_range, |file| {
20838                if let Some(file) = file {
20839                    file.is_private()
20840                        && EditorSettings::get(
20841                            Some(SettingsLocation {
20842                                worktree_id: file.worktree_id(cx),
20843                                path: file.path().as_ref(),
20844                            }),
20845                            cx,
20846                        )
20847                        .redact_private_values
20848                } else {
20849                    false
20850                }
20851            })
20852            .map(|range| {
20853                range.start.to_display_point(display_snapshot)
20854                    ..range.end.to_display_point(display_snapshot)
20855            })
20856            .collect()
20857    }
20858
20859    pub fn highlight_text_key<T: 'static>(
20860        &mut self,
20861        key: usize,
20862        ranges: Vec<Range<Anchor>>,
20863        style: HighlightStyle,
20864        cx: &mut Context<Self>,
20865    ) {
20866        self.display_map.update(cx, |map, _| {
20867            map.highlight_text(
20868                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20869                ranges,
20870                style,
20871            );
20872        });
20873        cx.notify();
20874    }
20875
20876    pub fn highlight_text<T: 'static>(
20877        &mut self,
20878        ranges: Vec<Range<Anchor>>,
20879        style: HighlightStyle,
20880        cx: &mut Context<Self>,
20881    ) {
20882        self.display_map.update(cx, |map, _| {
20883            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20884        });
20885        cx.notify();
20886    }
20887
20888    pub fn text_highlights<'a, T: 'static>(
20889        &'a self,
20890        cx: &'a App,
20891    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20892        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20893    }
20894
20895    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20896        let cleared = self
20897            .display_map
20898            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20899        if cleared {
20900            cx.notify();
20901        }
20902    }
20903
20904    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20905        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20906            && self.focus_handle.is_focused(window)
20907    }
20908
20909    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20910        self.show_cursor_when_unfocused = is_enabled;
20911        cx.notify();
20912    }
20913
20914    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20915        cx.notify();
20916    }
20917
20918    fn on_debug_session_event(
20919        &mut self,
20920        _session: Entity<Session>,
20921        event: &SessionEvent,
20922        cx: &mut Context<Self>,
20923    ) {
20924        if let SessionEvent::InvalidateInlineValue = event {
20925            self.refresh_inline_values(cx);
20926        }
20927    }
20928
20929    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20930        let Some(project) = self.project.clone() else {
20931            return;
20932        };
20933
20934        if !self.inline_value_cache.enabled {
20935            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20936            self.splice_inlays(&inlays, Vec::new(), cx);
20937            return;
20938        }
20939
20940        let current_execution_position = self
20941            .highlighted_rows
20942            .get(&TypeId::of::<ActiveDebugLine>())
20943            .and_then(|lines| lines.last().map(|line| line.range.end));
20944
20945        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20946            let inline_values = editor
20947                .update(cx, |editor, cx| {
20948                    let Some(current_execution_position) = current_execution_position else {
20949                        return Some(Task::ready(Ok(Vec::new())));
20950                    };
20951
20952                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20953                        let snapshot = buffer.snapshot(cx);
20954
20955                        let excerpt = snapshot.excerpt_containing(
20956                            current_execution_position..current_execution_position,
20957                        )?;
20958
20959                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20960                    })?;
20961
20962                    let range =
20963                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20964
20965                    project.inline_values(buffer, range, cx)
20966                })
20967                .ok()
20968                .flatten()?
20969                .await
20970                .context("refreshing debugger inlays")
20971                .log_err()?;
20972
20973            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20974
20975            for (buffer_id, inline_value) in inline_values
20976                .into_iter()
20977                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20978            {
20979                buffer_inline_values
20980                    .entry(buffer_id)
20981                    .or_default()
20982                    .push(inline_value);
20983            }
20984
20985            editor
20986                .update(cx, |editor, cx| {
20987                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20988                    let mut new_inlays = Vec::default();
20989
20990                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20991                        let buffer_id = buffer_snapshot.remote_id();
20992                        buffer_inline_values
20993                            .get(&buffer_id)
20994                            .into_iter()
20995                            .flatten()
20996                            .for_each(|hint| {
20997                                let inlay = Inlay::debugger(
20998                                    post_inc(&mut editor.next_inlay_id),
20999                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
21000                                    hint.text(),
21001                                );
21002                                if !inlay.text().chars().contains(&'\n') {
21003                                    new_inlays.push(inlay);
21004                                }
21005                            });
21006                    }
21007
21008                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
21009                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
21010
21011                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
21012                })
21013                .ok()?;
21014            Some(())
21015        });
21016    }
21017
21018    fn on_buffer_event(
21019        &mut self,
21020        multibuffer: &Entity<MultiBuffer>,
21021        event: &multi_buffer::Event,
21022        window: &mut Window,
21023        cx: &mut Context<Self>,
21024    ) {
21025        match event {
21026            multi_buffer::Event::Edited { edited_buffer } => {
21027                self.scrollbar_marker_state.dirty = true;
21028                self.active_indent_guides_state.dirty = true;
21029                self.refresh_active_diagnostics(cx);
21030                self.refresh_code_actions(window, cx);
21031                self.refresh_selected_text_highlights(true, window, cx);
21032                self.refresh_single_line_folds(window, cx);
21033                self.colorize_brackets(cx);
21034                self.refresh_matching_bracket_highlights(window, cx);
21035                if self.has_active_edit_prediction() {
21036                    self.update_visible_edit_prediction(window, cx);
21037                }
21038
21039                if let Some(buffer) = edited_buffer {
21040                    if buffer.read(cx).file().is_none() {
21041                        cx.emit(EditorEvent::TitleChanged);
21042                    }
21043
21044                    if self.project.is_some() {
21045                        let buffer_id = buffer.read(cx).remote_id();
21046                        self.register_buffer(buffer_id, cx);
21047                        self.update_lsp_data(Some(buffer_id), window, cx);
21048                        self.refresh_inlay_hints(
21049                            InlayHintRefreshReason::BufferEdited(buffer_id),
21050                            cx,
21051                        );
21052                    }
21053                }
21054
21055                cx.emit(EditorEvent::BufferEdited);
21056                cx.emit(SearchEvent::MatchesInvalidated);
21057
21058                let Some(project) = &self.project else { return };
21059                let (telemetry, is_via_ssh) = {
21060                    let project = project.read(cx);
21061                    let telemetry = project.client().telemetry().clone();
21062                    let is_via_ssh = project.is_via_remote_server();
21063                    (telemetry, is_via_ssh)
21064                };
21065                telemetry.log_edit_event("editor", is_via_ssh);
21066            }
21067            multi_buffer::Event::ExcerptsAdded {
21068                buffer,
21069                predecessor,
21070                excerpts,
21071            } => {
21072                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21073                let buffer_id = buffer.read(cx).remote_id();
21074                if self.buffer.read(cx).diff_for(buffer_id).is_none()
21075                    && let Some(project) = &self.project
21076                {
21077                    update_uncommitted_diff_for_buffer(
21078                        cx.entity(),
21079                        project,
21080                        [buffer.clone()],
21081                        self.buffer.clone(),
21082                        cx,
21083                    )
21084                    .detach();
21085                }
21086                self.update_lsp_data(Some(buffer_id), window, cx);
21087                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21088                self.colorize_brackets(cx);
21089                cx.emit(EditorEvent::ExcerptsAdded {
21090                    buffer: buffer.clone(),
21091                    predecessor: *predecessor,
21092                    excerpts: excerpts.clone(),
21093                });
21094            }
21095            multi_buffer::Event::ExcerptsRemoved {
21096                ids,
21097                removed_buffer_ids,
21098            } => {
21099                if let Some(inlay_hints) = &mut self.inlay_hints {
21100                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
21101                }
21102                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
21103                for buffer_id in removed_buffer_ids {
21104                    self.registered_buffers.remove(buffer_id);
21105                }
21106                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21107                cx.emit(EditorEvent::ExcerptsRemoved {
21108                    ids: ids.clone(),
21109                    removed_buffer_ids: removed_buffer_ids.clone(),
21110                });
21111            }
21112            multi_buffer::Event::ExcerptsEdited {
21113                excerpt_ids,
21114                buffer_ids,
21115            } => {
21116                self.display_map.update(cx, |map, cx| {
21117                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
21118                });
21119                cx.emit(EditorEvent::ExcerptsEdited {
21120                    ids: excerpt_ids.clone(),
21121                });
21122            }
21123            multi_buffer::Event::ExcerptsExpanded { ids } => {
21124                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21125                self.refresh_document_highlights(cx);
21126                self.colorize_brackets(cx);
21127                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
21128            }
21129            multi_buffer::Event::Reparsed(buffer_id) => {
21130                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21131                self.colorize_brackets(cx);
21132                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21133
21134                cx.emit(EditorEvent::Reparsed(*buffer_id));
21135            }
21136            multi_buffer::Event::DiffHunksToggled => {
21137                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21138            }
21139            multi_buffer::Event::LanguageChanged(buffer_id) => {
21140                self.registered_buffers.remove(&buffer_id);
21141                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21142                cx.emit(EditorEvent::Reparsed(*buffer_id));
21143                cx.notify();
21144            }
21145            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
21146            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21147            multi_buffer::Event::FileHandleChanged
21148            | multi_buffer::Event::Reloaded
21149            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21150            multi_buffer::Event::DiagnosticsUpdated => {
21151                self.update_diagnostics_state(window, cx);
21152            }
21153            _ => {}
21154        };
21155    }
21156
21157    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21158        if !self.diagnostics_enabled() {
21159            return;
21160        }
21161        self.refresh_active_diagnostics(cx);
21162        self.refresh_inline_diagnostics(true, window, cx);
21163        self.scrollbar_marker_state.dirty = true;
21164        cx.notify();
21165    }
21166
21167    pub fn start_temporary_diff_override(&mut self) {
21168        self.load_diff_task.take();
21169        self.temporary_diff_override = true;
21170    }
21171
21172    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21173        self.temporary_diff_override = false;
21174        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21175        self.buffer.update(cx, |buffer, cx| {
21176            buffer.set_all_diff_hunks_collapsed(cx);
21177        });
21178
21179        if let Some(project) = self.project.clone() {
21180            self.load_diff_task = Some(
21181                update_uncommitted_diff_for_buffer(
21182                    cx.entity(),
21183                    &project,
21184                    self.buffer.read(cx).all_buffers(),
21185                    self.buffer.clone(),
21186                    cx,
21187                )
21188                .shared(),
21189            );
21190        }
21191    }
21192
21193    fn on_display_map_changed(
21194        &mut self,
21195        _: Entity<DisplayMap>,
21196        _: &mut Window,
21197        cx: &mut Context<Self>,
21198    ) {
21199        cx.notify();
21200    }
21201
21202    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21203        if self.diagnostics_enabled() {
21204            let new_severity = EditorSettings::get_global(cx)
21205                .diagnostics_max_severity
21206                .unwrap_or(DiagnosticSeverity::Hint);
21207            self.set_max_diagnostics_severity(new_severity, cx);
21208        }
21209        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21210        self.update_edit_prediction_settings(cx);
21211        self.refresh_edit_prediction(true, false, window, cx);
21212        self.refresh_inline_values(cx);
21213        self.refresh_inlay_hints(
21214            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21215                self.selections.newest_anchor().head(),
21216                &self.buffer.read(cx).snapshot(cx),
21217                cx,
21218            )),
21219            cx,
21220        );
21221
21222        let old_cursor_shape = self.cursor_shape;
21223        let old_show_breadcrumbs = self.show_breadcrumbs;
21224
21225        {
21226            let editor_settings = EditorSettings::get_global(cx);
21227            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21228            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21229            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21230            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21231        }
21232
21233        if old_cursor_shape != self.cursor_shape {
21234            cx.emit(EditorEvent::CursorShapeChanged);
21235        }
21236
21237        if old_show_breadcrumbs != self.show_breadcrumbs {
21238            cx.emit(EditorEvent::BreadcrumbsChanged);
21239        }
21240
21241        let project_settings = ProjectSettings::get_global(cx);
21242        self.buffer_serialization = self
21243            .should_serialize_buffer()
21244            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
21245
21246        if self.mode.is_full() {
21247            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21248            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21249            if self.show_inline_diagnostics != show_inline_diagnostics {
21250                self.show_inline_diagnostics = show_inline_diagnostics;
21251                self.refresh_inline_diagnostics(false, window, cx);
21252            }
21253
21254            if self.git_blame_inline_enabled != inline_blame_enabled {
21255                self.toggle_git_blame_inline_internal(false, window, cx);
21256            }
21257
21258            let minimap_settings = EditorSettings::get_global(cx).minimap;
21259            if self.minimap_visibility != MinimapVisibility::Disabled {
21260                if self.minimap_visibility.settings_visibility()
21261                    != minimap_settings.minimap_enabled()
21262                {
21263                    self.set_minimap_visibility(
21264                        MinimapVisibility::for_mode(self.mode(), cx),
21265                        window,
21266                        cx,
21267                    );
21268                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21269                    minimap_entity.update(cx, |minimap_editor, cx| {
21270                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21271                    })
21272                }
21273            }
21274
21275            self.colorize_brackets(cx);
21276
21277            if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21278                colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21279            }) {
21280                if !inlay_splice.is_empty() {
21281                    self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21282                }
21283                self.refresh_colors_for_visible_range(None, window, cx);
21284            }
21285        }
21286
21287        cx.notify();
21288    }
21289
21290    pub fn set_searchable(&mut self, searchable: bool) {
21291        self.searchable = searchable;
21292    }
21293
21294    pub fn searchable(&self) -> bool {
21295        self.searchable
21296    }
21297
21298    pub fn open_excerpts_in_split(
21299        &mut self,
21300        _: &OpenExcerptsSplit,
21301        window: &mut Window,
21302        cx: &mut Context<Self>,
21303    ) {
21304        self.open_excerpts_common(None, true, window, cx)
21305    }
21306
21307    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21308        self.open_excerpts_common(None, false, window, cx)
21309    }
21310
21311    fn open_excerpts_common(
21312        &mut self,
21313        jump_data: Option<JumpData>,
21314        split: bool,
21315        window: &mut Window,
21316        cx: &mut Context<Self>,
21317    ) {
21318        let Some(workspace) = self.workspace() else {
21319            cx.propagate();
21320            return;
21321        };
21322
21323        if self.buffer.read(cx).is_singleton() {
21324            cx.propagate();
21325            return;
21326        }
21327
21328        let mut new_selections_by_buffer = HashMap::default();
21329        match &jump_data {
21330            Some(JumpData::MultiBufferPoint {
21331                excerpt_id,
21332                position,
21333                anchor,
21334                line_offset_from_top,
21335            }) => {
21336                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21337                if let Some(buffer) = multi_buffer_snapshot
21338                    .buffer_id_for_excerpt(*excerpt_id)
21339                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21340                {
21341                    let buffer_snapshot = buffer.read(cx).snapshot();
21342                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21343                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21344                    } else {
21345                        buffer_snapshot.clip_point(*position, Bias::Left)
21346                    };
21347                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21348                    new_selections_by_buffer.insert(
21349                        buffer,
21350                        (
21351                            vec![jump_to_offset..jump_to_offset],
21352                            Some(*line_offset_from_top),
21353                        ),
21354                    );
21355                }
21356            }
21357            Some(JumpData::MultiBufferRow {
21358                row,
21359                line_offset_from_top,
21360            }) => {
21361                let point = MultiBufferPoint::new(row.0, 0);
21362                if let Some((buffer, buffer_point, _)) =
21363                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21364                {
21365                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21366                    new_selections_by_buffer
21367                        .entry(buffer)
21368                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21369                        .0
21370                        .push(buffer_offset..buffer_offset)
21371                }
21372            }
21373            None => {
21374                let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
21375                let multi_buffer = self.buffer.read(cx);
21376                for selection in selections {
21377                    for (snapshot, range, _, anchor) in multi_buffer
21378                        .snapshot(cx)
21379                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21380                    {
21381                        if let Some(anchor) = anchor {
21382                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21383                            else {
21384                                continue;
21385                            };
21386                            let offset = text::ToOffset::to_offset(
21387                                &anchor.text_anchor,
21388                                &buffer_handle.read(cx).snapshot(),
21389                            );
21390                            let range = offset..offset;
21391                            new_selections_by_buffer
21392                                .entry(buffer_handle)
21393                                .or_insert((Vec::new(), None))
21394                                .0
21395                                .push(range)
21396                        } else {
21397                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21398                            else {
21399                                continue;
21400                            };
21401                            new_selections_by_buffer
21402                                .entry(buffer_handle)
21403                                .or_insert((Vec::new(), None))
21404                                .0
21405                                .push(range)
21406                        }
21407                    }
21408                }
21409            }
21410        }
21411
21412        new_selections_by_buffer
21413            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21414
21415        if new_selections_by_buffer.is_empty() {
21416            return;
21417        }
21418
21419        // We defer the pane interaction because we ourselves are a workspace item
21420        // and activating a new item causes the pane to call a method on us reentrantly,
21421        // which panics if we're on the stack.
21422        window.defer(cx, move |window, cx| {
21423            workspace.update(cx, |workspace, cx| {
21424                let pane = if split {
21425                    workspace.adjacent_pane(window, cx)
21426                } else {
21427                    workspace.active_pane().clone()
21428                };
21429
21430                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21431                    let editor = buffer
21432                        .read(cx)
21433                        .file()
21434                        .is_none()
21435                        .then(|| {
21436                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21437                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21438                            // Instead, we try to activate the existing editor in the pane first.
21439                            let (editor, pane_item_index) =
21440                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21441                                    let editor = item.downcast::<Editor>()?;
21442                                    let singleton_buffer =
21443                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21444                                    if singleton_buffer == buffer {
21445                                        Some((editor, i))
21446                                    } else {
21447                                        None
21448                                    }
21449                                })?;
21450                            pane.update(cx, |pane, cx| {
21451                                pane.activate_item(pane_item_index, true, true, window, cx)
21452                            });
21453                            Some(editor)
21454                        })
21455                        .flatten()
21456                        .unwrap_or_else(|| {
21457                            workspace.open_project_item::<Self>(
21458                                pane.clone(),
21459                                buffer,
21460                                true,
21461                                true,
21462                                window,
21463                                cx,
21464                            )
21465                        });
21466
21467                    editor.update(cx, |editor, cx| {
21468                        let autoscroll = match scroll_offset {
21469                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21470                            None => Autoscroll::newest(),
21471                        };
21472                        let nav_history = editor.nav_history.take();
21473                        editor.change_selections(
21474                            SelectionEffects::scroll(autoscroll),
21475                            window,
21476                            cx,
21477                            |s| {
21478                                s.select_ranges(ranges);
21479                            },
21480                        );
21481                        editor.nav_history = nav_history;
21482                    });
21483                }
21484            })
21485        });
21486    }
21487
21488    // For now, don't allow opening excerpts in buffers that aren't backed by
21489    // regular project files.
21490    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21491        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21492    }
21493
21494    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21495        let snapshot = self.buffer.read(cx).read(cx);
21496        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21497        Some(
21498            ranges
21499                .iter()
21500                .map(move |range| {
21501                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21502                })
21503                .collect(),
21504        )
21505    }
21506
21507    fn selection_replacement_ranges(
21508        &self,
21509        range: Range<OffsetUtf16>,
21510        cx: &mut App,
21511    ) -> Vec<Range<OffsetUtf16>> {
21512        let selections = self
21513            .selections
21514            .all::<OffsetUtf16>(&self.display_snapshot(cx));
21515        let newest_selection = selections
21516            .iter()
21517            .max_by_key(|selection| selection.id)
21518            .unwrap();
21519        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21520        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21521        let snapshot = self.buffer.read(cx).read(cx);
21522        selections
21523            .into_iter()
21524            .map(|mut selection| {
21525                selection.start.0 =
21526                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21527                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21528                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21529                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21530            })
21531            .collect()
21532    }
21533
21534    fn report_editor_event(
21535        &self,
21536        reported_event: ReportEditorEvent,
21537        file_extension: Option<String>,
21538        cx: &App,
21539    ) {
21540        if cfg!(any(test, feature = "test-support")) {
21541            return;
21542        }
21543
21544        let Some(project) = &self.project else { return };
21545
21546        // If None, we are in a file without an extension
21547        let file = self
21548            .buffer
21549            .read(cx)
21550            .as_singleton()
21551            .and_then(|b| b.read(cx).file());
21552        let file_extension = file_extension.or(file
21553            .as_ref()
21554            .and_then(|file| Path::new(file.file_name(cx)).extension())
21555            .and_then(|e| e.to_str())
21556            .map(|a| a.to_string()));
21557
21558        let vim_mode = vim_flavor(cx).is_some();
21559
21560        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21561        let copilot_enabled = edit_predictions_provider
21562            == language::language_settings::EditPredictionProvider::Copilot;
21563        let copilot_enabled_for_language = self
21564            .buffer
21565            .read(cx)
21566            .language_settings(cx)
21567            .show_edit_predictions;
21568
21569        let project = project.read(cx);
21570        let event_type = reported_event.event_type();
21571
21572        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21573            telemetry::event!(
21574                event_type,
21575                type = if auto_saved {"autosave"} else {"manual"},
21576                file_extension,
21577                vim_mode,
21578                copilot_enabled,
21579                copilot_enabled_for_language,
21580                edit_predictions_provider,
21581                is_via_ssh = project.is_via_remote_server(),
21582            );
21583        } else {
21584            telemetry::event!(
21585                event_type,
21586                file_extension,
21587                vim_mode,
21588                copilot_enabled,
21589                copilot_enabled_for_language,
21590                edit_predictions_provider,
21591                is_via_ssh = project.is_via_remote_server(),
21592            );
21593        };
21594    }
21595
21596    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21597    /// with each line being an array of {text, highlight} objects.
21598    fn copy_highlight_json(
21599        &mut self,
21600        _: &CopyHighlightJson,
21601        window: &mut Window,
21602        cx: &mut Context<Self>,
21603    ) {
21604        #[derive(Serialize)]
21605        struct Chunk<'a> {
21606            text: String,
21607            highlight: Option<&'a str>,
21608        }
21609
21610        let snapshot = self.buffer.read(cx).snapshot(cx);
21611        let range = self
21612            .selected_text_range(false, window, cx)
21613            .and_then(|selection| {
21614                if selection.range.is_empty() {
21615                    None
21616                } else {
21617                    Some(
21618                        snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.start))
21619                            ..snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.end)),
21620                    )
21621                }
21622            })
21623            .unwrap_or_else(|| 0..snapshot.len());
21624
21625        let chunks = snapshot.chunks(range, true);
21626        let mut lines = Vec::new();
21627        let mut line: VecDeque<Chunk> = VecDeque::new();
21628
21629        let Some(style) = self.style.as_ref() else {
21630            return;
21631        };
21632
21633        for chunk in chunks {
21634            let highlight = chunk
21635                .syntax_highlight_id
21636                .and_then(|id| id.name(&style.syntax));
21637            let mut chunk_lines = chunk.text.split('\n').peekable();
21638            while let Some(text) = chunk_lines.next() {
21639                let mut merged_with_last_token = false;
21640                if let Some(last_token) = line.back_mut()
21641                    && last_token.highlight == highlight
21642                {
21643                    last_token.text.push_str(text);
21644                    merged_with_last_token = true;
21645                }
21646
21647                if !merged_with_last_token {
21648                    line.push_back(Chunk {
21649                        text: text.into(),
21650                        highlight,
21651                    });
21652                }
21653
21654                if chunk_lines.peek().is_some() {
21655                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21656                        line.pop_front();
21657                    }
21658                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21659                        line.pop_back();
21660                    }
21661
21662                    lines.push(mem::take(&mut line));
21663                }
21664            }
21665        }
21666
21667        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21668            return;
21669        };
21670        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21671    }
21672
21673    pub fn open_context_menu(
21674        &mut self,
21675        _: &OpenContextMenu,
21676        window: &mut Window,
21677        cx: &mut Context<Self>,
21678    ) {
21679        self.request_autoscroll(Autoscroll::newest(), cx);
21680        let position = self
21681            .selections
21682            .newest_display(&self.display_snapshot(cx))
21683            .start;
21684        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21685    }
21686
21687    pub fn replay_insert_event(
21688        &mut self,
21689        text: &str,
21690        relative_utf16_range: Option<Range<isize>>,
21691        window: &mut Window,
21692        cx: &mut Context<Self>,
21693    ) {
21694        if !self.input_enabled {
21695            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21696            return;
21697        }
21698        if let Some(relative_utf16_range) = relative_utf16_range {
21699            let selections = self
21700                .selections
21701                .all::<OffsetUtf16>(&self.display_snapshot(cx));
21702            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21703                let new_ranges = selections.into_iter().map(|range| {
21704                    let start = OffsetUtf16(
21705                        range
21706                            .head()
21707                            .0
21708                            .saturating_add_signed(relative_utf16_range.start),
21709                    );
21710                    let end = OffsetUtf16(
21711                        range
21712                            .head()
21713                            .0
21714                            .saturating_add_signed(relative_utf16_range.end),
21715                    );
21716                    start..end
21717                });
21718                s.select_ranges(new_ranges);
21719            });
21720        }
21721
21722        self.handle_input(text, window, cx);
21723    }
21724
21725    pub fn is_focused(&self, window: &Window) -> bool {
21726        self.focus_handle.is_focused(window)
21727    }
21728
21729    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21730        cx.emit(EditorEvent::Focused);
21731
21732        if let Some(descendant) = self
21733            .last_focused_descendant
21734            .take()
21735            .and_then(|descendant| descendant.upgrade())
21736        {
21737            window.focus(&descendant);
21738        } else {
21739            if let Some(blame) = self.blame.as_ref() {
21740                blame.update(cx, GitBlame::focus)
21741            }
21742
21743            self.blink_manager.update(cx, BlinkManager::enable);
21744            self.show_cursor_names(window, cx);
21745            self.buffer.update(cx, |buffer, cx| {
21746                buffer.finalize_last_transaction(cx);
21747                if self.leader_id.is_none() {
21748                    buffer.set_active_selections(
21749                        &self.selections.disjoint_anchors_arc(),
21750                        self.selections.line_mode(),
21751                        self.cursor_shape,
21752                        cx,
21753                    );
21754                }
21755            });
21756        }
21757    }
21758
21759    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21760        cx.emit(EditorEvent::FocusedIn)
21761    }
21762
21763    fn handle_focus_out(
21764        &mut self,
21765        event: FocusOutEvent,
21766        _window: &mut Window,
21767        cx: &mut Context<Self>,
21768    ) {
21769        if event.blurred != self.focus_handle {
21770            self.last_focused_descendant = Some(event.blurred);
21771        }
21772        self.selection_drag_state = SelectionDragState::None;
21773        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21774    }
21775
21776    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21777        self.blink_manager.update(cx, BlinkManager::disable);
21778        self.buffer
21779            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21780
21781        if let Some(blame) = self.blame.as_ref() {
21782            blame.update(cx, GitBlame::blur)
21783        }
21784        if !self.hover_state.focused(window, cx) {
21785            hide_hover(self, cx);
21786        }
21787        if !self
21788            .context_menu
21789            .borrow()
21790            .as_ref()
21791            .is_some_and(|context_menu| context_menu.focused(window, cx))
21792        {
21793            self.hide_context_menu(window, cx);
21794        }
21795        self.take_active_edit_prediction(cx);
21796        cx.emit(EditorEvent::Blurred);
21797        cx.notify();
21798    }
21799
21800    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21801        let mut pending: String = window
21802            .pending_input_keystrokes()
21803            .into_iter()
21804            .flatten()
21805            .filter_map(|keystroke| {
21806                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21807                    keystroke.key_char.clone()
21808                } else {
21809                    None
21810                }
21811            })
21812            .collect();
21813
21814        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21815            pending = "".to_string();
21816        }
21817
21818        let existing_pending = self
21819            .text_highlights::<PendingInput>(cx)
21820            .map(|(_, ranges)| ranges.to_vec());
21821        if existing_pending.is_none() && pending.is_empty() {
21822            return;
21823        }
21824        let transaction =
21825            self.transact(window, cx, |this, window, cx| {
21826                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
21827                let edits = selections
21828                    .iter()
21829                    .map(|selection| (selection.end..selection.end, pending.clone()));
21830                this.edit(edits, cx);
21831                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21832                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21833                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21834                    }));
21835                });
21836                if let Some(existing_ranges) = existing_pending {
21837                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21838                    this.edit(edits, cx);
21839                }
21840            });
21841
21842        let snapshot = self.snapshot(window, cx);
21843        let ranges = self
21844            .selections
21845            .all::<usize>(&snapshot.display_snapshot)
21846            .into_iter()
21847            .map(|selection| {
21848                snapshot.buffer_snapshot().anchor_after(selection.end)
21849                    ..snapshot
21850                        .buffer_snapshot()
21851                        .anchor_before(selection.end + pending.len())
21852            })
21853            .collect();
21854
21855        if pending.is_empty() {
21856            self.clear_highlights::<PendingInput>(cx);
21857        } else {
21858            self.highlight_text::<PendingInput>(
21859                ranges,
21860                HighlightStyle {
21861                    underline: Some(UnderlineStyle {
21862                        thickness: px(1.),
21863                        color: None,
21864                        wavy: false,
21865                    }),
21866                    ..Default::default()
21867                },
21868                cx,
21869            );
21870        }
21871
21872        self.ime_transaction = self.ime_transaction.or(transaction);
21873        if let Some(transaction) = self.ime_transaction {
21874            self.buffer.update(cx, |buffer, cx| {
21875                buffer.group_until_transaction(transaction, cx);
21876            });
21877        }
21878
21879        if self.text_highlights::<PendingInput>(cx).is_none() {
21880            self.ime_transaction.take();
21881        }
21882    }
21883
21884    pub fn register_action_renderer(
21885        &mut self,
21886        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21887    ) -> Subscription {
21888        let id = self.next_editor_action_id.post_inc();
21889        self.editor_actions
21890            .borrow_mut()
21891            .insert(id, Box::new(listener));
21892
21893        let editor_actions = self.editor_actions.clone();
21894        Subscription::new(move || {
21895            editor_actions.borrow_mut().remove(&id);
21896        })
21897    }
21898
21899    pub fn register_action<A: Action>(
21900        &mut self,
21901        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21902    ) -> Subscription {
21903        let id = self.next_editor_action_id.post_inc();
21904        let listener = Arc::new(listener);
21905        self.editor_actions.borrow_mut().insert(
21906            id,
21907            Box::new(move |_, window, _| {
21908                let listener = listener.clone();
21909                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21910                    let action = action.downcast_ref().unwrap();
21911                    if phase == DispatchPhase::Bubble {
21912                        listener(action, window, cx)
21913                    }
21914                })
21915            }),
21916        );
21917
21918        let editor_actions = self.editor_actions.clone();
21919        Subscription::new(move || {
21920            editor_actions.borrow_mut().remove(&id);
21921        })
21922    }
21923
21924    pub fn file_header_size(&self) -> u32 {
21925        FILE_HEADER_HEIGHT
21926    }
21927
21928    pub fn restore(
21929        &mut self,
21930        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21931        window: &mut Window,
21932        cx: &mut Context<Self>,
21933    ) {
21934        let workspace = self.workspace();
21935        let project = self.project();
21936        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21937            let mut tasks = Vec::new();
21938            for (buffer_id, changes) in revert_changes {
21939                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21940                    buffer.update(cx, |buffer, cx| {
21941                        buffer.edit(
21942                            changes
21943                                .into_iter()
21944                                .map(|(range, text)| (range, text.to_string())),
21945                            None,
21946                            cx,
21947                        );
21948                    });
21949
21950                    if let Some(project) =
21951                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21952                    {
21953                        project.update(cx, |project, cx| {
21954                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21955                        })
21956                    }
21957                }
21958            }
21959            tasks
21960        });
21961        cx.spawn_in(window, async move |_, cx| {
21962            for (buffer, task) in save_tasks {
21963                let result = task.await;
21964                if result.is_err() {
21965                    let Some(path) = buffer
21966                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21967                        .ok()
21968                    else {
21969                        continue;
21970                    };
21971                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21972                        let Some(task) = cx
21973                            .update_window_entity(workspace, |workspace, window, cx| {
21974                                workspace
21975                                    .open_path_preview(path, None, false, false, false, window, cx)
21976                            })
21977                            .ok()
21978                        else {
21979                            continue;
21980                        };
21981                        task.await.log_err();
21982                    }
21983                }
21984            }
21985        })
21986        .detach();
21987        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21988            selections.refresh()
21989        });
21990    }
21991
21992    pub fn to_pixel_point(
21993        &self,
21994        source: multi_buffer::Anchor,
21995        editor_snapshot: &EditorSnapshot,
21996        window: &mut Window,
21997    ) -> Option<gpui::Point<Pixels>> {
21998        let source_point = source.to_display_point(editor_snapshot);
21999        self.display_to_pixel_point(source_point, editor_snapshot, window)
22000    }
22001
22002    pub fn display_to_pixel_point(
22003        &self,
22004        source: DisplayPoint,
22005        editor_snapshot: &EditorSnapshot,
22006        window: &mut Window,
22007    ) -> Option<gpui::Point<Pixels>> {
22008        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
22009        let text_layout_details = self.text_layout_details(window);
22010        let scroll_top = text_layout_details
22011            .scroll_anchor
22012            .scroll_position(editor_snapshot)
22013            .y;
22014
22015        if source.row().as_f64() < scroll_top.floor() {
22016            return None;
22017        }
22018        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
22019        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
22020        Some(gpui::Point::new(source_x, source_y))
22021    }
22022
22023    pub fn has_visible_completions_menu(&self) -> bool {
22024        !self.edit_prediction_preview_is_active()
22025            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
22026                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
22027            })
22028    }
22029
22030    pub fn register_addon<T: Addon>(&mut self, instance: T) {
22031        if self.mode.is_minimap() {
22032            return;
22033        }
22034        self.addons
22035            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
22036    }
22037
22038    pub fn unregister_addon<T: Addon>(&mut self) {
22039        self.addons.remove(&std::any::TypeId::of::<T>());
22040    }
22041
22042    pub fn addon<T: Addon>(&self) -> Option<&T> {
22043        let type_id = std::any::TypeId::of::<T>();
22044        self.addons
22045            .get(&type_id)
22046            .and_then(|item| item.to_any().downcast_ref::<T>())
22047    }
22048
22049    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
22050        let type_id = std::any::TypeId::of::<T>();
22051        self.addons
22052            .get_mut(&type_id)
22053            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
22054    }
22055
22056    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
22057        let text_layout_details = self.text_layout_details(window);
22058        let style = &text_layout_details.editor_style;
22059        let font_id = window.text_system().resolve_font(&style.text.font());
22060        let font_size = style.text.font_size.to_pixels(window.rem_size());
22061        let line_height = style.text.line_height_in_pixels(window.rem_size());
22062        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
22063        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
22064
22065        CharacterDimensions {
22066            em_width,
22067            em_advance,
22068            line_height,
22069        }
22070    }
22071
22072    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
22073        self.load_diff_task.clone()
22074    }
22075
22076    fn read_metadata_from_db(
22077        &mut self,
22078        item_id: u64,
22079        workspace_id: WorkspaceId,
22080        window: &mut Window,
22081        cx: &mut Context<Editor>,
22082    ) {
22083        if self.buffer_kind(cx) == ItemBufferKind::Singleton
22084            && !self.mode.is_minimap()
22085            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
22086        {
22087            let buffer_snapshot = OnceCell::new();
22088
22089            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
22090                && !folds.is_empty()
22091            {
22092                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22093                self.fold_ranges(
22094                    folds
22095                        .into_iter()
22096                        .map(|(start, end)| {
22097                            snapshot.clip_offset(start, Bias::Left)
22098                                ..snapshot.clip_offset(end, Bias::Right)
22099                        })
22100                        .collect(),
22101                    false,
22102                    window,
22103                    cx,
22104                );
22105            }
22106
22107            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
22108                && !selections.is_empty()
22109            {
22110                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22111                // skip adding the initial selection to selection history
22112                self.selection_history.mode = SelectionHistoryMode::Skipping;
22113                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22114                    s.select_ranges(selections.into_iter().map(|(start, end)| {
22115                        snapshot.clip_offset(start, Bias::Left)
22116                            ..snapshot.clip_offset(end, Bias::Right)
22117                    }));
22118                });
22119                self.selection_history.mode = SelectionHistoryMode::Normal;
22120            };
22121        }
22122
22123        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22124    }
22125
22126    fn update_lsp_data(
22127        &mut self,
22128        for_buffer: Option<BufferId>,
22129        window: &mut Window,
22130        cx: &mut Context<'_, Self>,
22131    ) {
22132        self.pull_diagnostics(for_buffer, window, cx);
22133        self.refresh_colors_for_visible_range(for_buffer, window, cx);
22134    }
22135
22136    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
22137        if self.ignore_lsp_data() {
22138            return;
22139        }
22140        for (_, (visible_buffer, _, _)) in self.visible_excerpts(cx) {
22141            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
22142        }
22143    }
22144
22145    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
22146        if !self.registered_buffers.contains_key(&buffer_id)
22147            && let Some(project) = self.project.as_ref()
22148        {
22149            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
22150                project.update(cx, |project, cx| {
22151                    self.registered_buffers.insert(
22152                        buffer_id,
22153                        project.register_buffer_with_language_servers(&buffer, cx),
22154                    );
22155                });
22156            } else {
22157                self.registered_buffers.remove(&buffer_id);
22158            }
22159        }
22160    }
22161
22162    fn ignore_lsp_data(&self) -> bool {
22163        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
22164        // skip any LSP updates for it.
22165        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
22166    }
22167}
22168
22169fn edit_for_markdown_paste<'a>(
22170    buffer: &MultiBufferSnapshot,
22171    range: Range<usize>,
22172    to_insert: &'a str,
22173    url: Option<url::Url>,
22174) -> (Range<usize>, Cow<'a, str>) {
22175    if url.is_none() {
22176        return (range, Cow::Borrowed(to_insert));
22177    };
22178
22179    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22180
22181    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22182        Cow::Borrowed(to_insert)
22183    } else {
22184        Cow::Owned(format!("[{old_text}]({to_insert})"))
22185    };
22186    (range, new_text)
22187}
22188
22189#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
22190pub enum VimFlavor {
22191    Vim,
22192    Helix,
22193}
22194
22195pub fn vim_flavor(cx: &App) -> Option<VimFlavor> {
22196    if vim_mode_setting::HelixModeSetting::try_get(cx)
22197        .map(|helix_mode| helix_mode.0)
22198        .unwrap_or(false)
22199    {
22200        Some(VimFlavor::Helix)
22201    } else if vim_mode_setting::VimModeSetting::try_get(cx)
22202        .map(|vim_mode| vim_mode.0)
22203        .unwrap_or(false)
22204    {
22205        Some(VimFlavor::Vim)
22206    } else {
22207        None // neither vim nor helix mode
22208    }
22209}
22210
22211fn process_completion_for_edit(
22212    completion: &Completion,
22213    intent: CompletionIntent,
22214    buffer: &Entity<Buffer>,
22215    cursor_position: &text::Anchor,
22216    cx: &mut Context<Editor>,
22217) -> CompletionEdit {
22218    let buffer = buffer.read(cx);
22219    let buffer_snapshot = buffer.snapshot();
22220    let (snippet, new_text) = if completion.is_snippet() {
22221        let mut snippet_source = completion.new_text.clone();
22222        // Workaround for typescript language server issues so that methods don't expand within
22223        // strings and functions with type expressions. The previous point is used because the query
22224        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22225        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22226        let previous_point = if previous_point.column > 0 {
22227            cursor_position.to_previous_offset(&buffer_snapshot)
22228        } else {
22229            cursor_position.to_offset(&buffer_snapshot)
22230        };
22231        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22232            && scope.prefers_label_for_snippet_in_completion()
22233            && let Some(label) = completion.label()
22234            && matches!(
22235                completion.kind(),
22236                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22237            )
22238        {
22239            snippet_source = label;
22240        }
22241        match Snippet::parse(&snippet_source).log_err() {
22242            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22243            None => (None, completion.new_text.clone()),
22244        }
22245    } else {
22246        (None, completion.new_text.clone())
22247    };
22248
22249    let mut range_to_replace = {
22250        let replace_range = &completion.replace_range;
22251        if let CompletionSource::Lsp {
22252            insert_range: Some(insert_range),
22253            ..
22254        } = &completion.source
22255        {
22256            debug_assert_eq!(
22257                insert_range.start, replace_range.start,
22258                "insert_range and replace_range should start at the same position"
22259            );
22260            debug_assert!(
22261                insert_range
22262                    .start
22263                    .cmp(cursor_position, &buffer_snapshot)
22264                    .is_le(),
22265                "insert_range should start before or at cursor position"
22266            );
22267            debug_assert!(
22268                replace_range
22269                    .start
22270                    .cmp(cursor_position, &buffer_snapshot)
22271                    .is_le(),
22272                "replace_range should start before or at cursor position"
22273            );
22274
22275            let should_replace = match intent {
22276                CompletionIntent::CompleteWithInsert => false,
22277                CompletionIntent::CompleteWithReplace => true,
22278                CompletionIntent::Complete | CompletionIntent::Compose => {
22279                    let insert_mode =
22280                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22281                            .completions
22282                            .lsp_insert_mode;
22283                    match insert_mode {
22284                        LspInsertMode::Insert => false,
22285                        LspInsertMode::Replace => true,
22286                        LspInsertMode::ReplaceSubsequence => {
22287                            let mut text_to_replace = buffer.chars_for_range(
22288                                buffer.anchor_before(replace_range.start)
22289                                    ..buffer.anchor_after(replace_range.end),
22290                            );
22291                            let mut current_needle = text_to_replace.next();
22292                            for haystack_ch in completion.label.text.chars() {
22293                                if let Some(needle_ch) = current_needle
22294                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22295                                {
22296                                    current_needle = text_to_replace.next();
22297                                }
22298                            }
22299                            current_needle.is_none()
22300                        }
22301                        LspInsertMode::ReplaceSuffix => {
22302                            if replace_range
22303                                .end
22304                                .cmp(cursor_position, &buffer_snapshot)
22305                                .is_gt()
22306                            {
22307                                let range_after_cursor = *cursor_position..replace_range.end;
22308                                let text_after_cursor = buffer
22309                                    .text_for_range(
22310                                        buffer.anchor_before(range_after_cursor.start)
22311                                            ..buffer.anchor_after(range_after_cursor.end),
22312                                    )
22313                                    .collect::<String>()
22314                                    .to_ascii_lowercase();
22315                                completion
22316                                    .label
22317                                    .text
22318                                    .to_ascii_lowercase()
22319                                    .ends_with(&text_after_cursor)
22320                            } else {
22321                                true
22322                            }
22323                        }
22324                    }
22325                }
22326            };
22327
22328            if should_replace {
22329                replace_range.clone()
22330            } else {
22331                insert_range.clone()
22332            }
22333        } else {
22334            replace_range.clone()
22335        }
22336    };
22337
22338    if range_to_replace
22339        .end
22340        .cmp(cursor_position, &buffer_snapshot)
22341        .is_lt()
22342    {
22343        range_to_replace.end = *cursor_position;
22344    }
22345
22346    CompletionEdit {
22347        new_text,
22348        replace_range: range_to_replace.to_offset(buffer),
22349        snippet,
22350    }
22351}
22352
22353struct CompletionEdit {
22354    new_text: String,
22355    replace_range: Range<usize>,
22356    snippet: Option<Snippet>,
22357}
22358
22359fn insert_extra_newline_brackets(
22360    buffer: &MultiBufferSnapshot,
22361    range: Range<usize>,
22362    language: &language::LanguageScope,
22363) -> bool {
22364    let leading_whitespace_len = buffer
22365        .reversed_chars_at(range.start)
22366        .take_while(|c| c.is_whitespace() && *c != '\n')
22367        .map(|c| c.len_utf8())
22368        .sum::<usize>();
22369    let trailing_whitespace_len = buffer
22370        .chars_at(range.end)
22371        .take_while(|c| c.is_whitespace() && *c != '\n')
22372        .map(|c| c.len_utf8())
22373        .sum::<usize>();
22374    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22375
22376    language.brackets().any(|(pair, enabled)| {
22377        let pair_start = pair.start.trim_end();
22378        let pair_end = pair.end.trim_start();
22379
22380        enabled
22381            && pair.newline
22382            && buffer.contains_str_at(range.end, pair_end)
22383            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22384    })
22385}
22386
22387fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22388    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22389        [(buffer, range, _)] => (*buffer, range.clone()),
22390        _ => return false,
22391    };
22392    let pair = {
22393        let mut result: Option<BracketMatch> = None;
22394
22395        for pair in buffer
22396            .all_bracket_ranges(range.clone())
22397            .into_iter()
22398            .filter(move |pair| {
22399                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22400            })
22401        {
22402            let len = pair.close_range.end - pair.open_range.start;
22403
22404            if let Some(existing) = &result {
22405                let existing_len = existing.close_range.end - existing.open_range.start;
22406                if len > existing_len {
22407                    continue;
22408                }
22409            }
22410
22411            result = Some(pair);
22412        }
22413
22414        result
22415    };
22416    let Some(pair) = pair else {
22417        return false;
22418    };
22419    pair.newline_only
22420        && buffer
22421            .chars_for_range(pair.open_range.end..range.start)
22422            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22423            .all(|c| c.is_whitespace() && c != '\n')
22424}
22425
22426fn update_uncommitted_diff_for_buffer(
22427    editor: Entity<Editor>,
22428    project: &Entity<Project>,
22429    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22430    buffer: Entity<MultiBuffer>,
22431    cx: &mut App,
22432) -> Task<()> {
22433    let mut tasks = Vec::new();
22434    project.update(cx, |project, cx| {
22435        for buffer in buffers {
22436            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22437                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22438            }
22439        }
22440    });
22441    cx.spawn(async move |cx| {
22442        let diffs = future::join_all(tasks).await;
22443        if editor
22444            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22445            .unwrap_or(false)
22446        {
22447            return;
22448        }
22449
22450        buffer
22451            .update(cx, |buffer, cx| {
22452                for diff in diffs.into_iter().flatten() {
22453                    buffer.add_diff(diff, cx);
22454                }
22455            })
22456            .ok();
22457    })
22458}
22459
22460fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22461    let tab_size = tab_size.get() as usize;
22462    let mut width = offset;
22463
22464    for ch in text.chars() {
22465        width += if ch == '\t' {
22466            tab_size - (width % tab_size)
22467        } else {
22468            1
22469        };
22470    }
22471
22472    width - offset
22473}
22474
22475#[cfg(test)]
22476mod tests {
22477    use super::*;
22478
22479    #[test]
22480    fn test_string_size_with_expanded_tabs() {
22481        let nz = |val| NonZeroU32::new(val).unwrap();
22482        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22483        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22484        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22485        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22486        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22487        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22488        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22489        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22490    }
22491}
22492
22493/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22494struct WordBreakingTokenizer<'a> {
22495    input: &'a str,
22496}
22497
22498impl<'a> WordBreakingTokenizer<'a> {
22499    fn new(input: &'a str) -> Self {
22500        Self { input }
22501    }
22502}
22503
22504fn is_char_ideographic(ch: char) -> bool {
22505    use unicode_script::Script::*;
22506    use unicode_script::UnicodeScript;
22507    matches!(ch.script(), Han | Tangut | Yi)
22508}
22509
22510fn is_grapheme_ideographic(text: &str) -> bool {
22511    text.chars().any(is_char_ideographic)
22512}
22513
22514fn is_grapheme_whitespace(text: &str) -> bool {
22515    text.chars().any(|x| x.is_whitespace())
22516}
22517
22518fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22519    text.chars()
22520        .next()
22521        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22522}
22523
22524#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22525enum WordBreakToken<'a> {
22526    Word { token: &'a str, grapheme_len: usize },
22527    InlineWhitespace { token: &'a str, grapheme_len: usize },
22528    Newline,
22529}
22530
22531impl<'a> Iterator for WordBreakingTokenizer<'a> {
22532    /// Yields a span, the count of graphemes in the token, and whether it was
22533    /// whitespace. Note that it also breaks at word boundaries.
22534    type Item = WordBreakToken<'a>;
22535
22536    fn next(&mut self) -> Option<Self::Item> {
22537        use unicode_segmentation::UnicodeSegmentation;
22538        if self.input.is_empty() {
22539            return None;
22540        }
22541
22542        let mut iter = self.input.graphemes(true).peekable();
22543        let mut offset = 0;
22544        let mut grapheme_len = 0;
22545        if let Some(first_grapheme) = iter.next() {
22546            let is_newline = first_grapheme == "\n";
22547            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22548            offset += first_grapheme.len();
22549            grapheme_len += 1;
22550            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22551                if let Some(grapheme) = iter.peek().copied()
22552                    && should_stay_with_preceding_ideograph(grapheme)
22553                {
22554                    offset += grapheme.len();
22555                    grapheme_len += 1;
22556                }
22557            } else {
22558                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22559                let mut next_word_bound = words.peek().copied();
22560                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22561                    next_word_bound = words.next();
22562                }
22563                while let Some(grapheme) = iter.peek().copied() {
22564                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22565                        break;
22566                    };
22567                    if is_grapheme_whitespace(grapheme) != is_whitespace
22568                        || (grapheme == "\n") != is_newline
22569                    {
22570                        break;
22571                    };
22572                    offset += grapheme.len();
22573                    grapheme_len += 1;
22574                    iter.next();
22575                }
22576            }
22577            let token = &self.input[..offset];
22578            self.input = &self.input[offset..];
22579            if token == "\n" {
22580                Some(WordBreakToken::Newline)
22581            } else if is_whitespace {
22582                Some(WordBreakToken::InlineWhitespace {
22583                    token,
22584                    grapheme_len,
22585                })
22586            } else {
22587                Some(WordBreakToken::Word {
22588                    token,
22589                    grapheme_len,
22590                })
22591            }
22592        } else {
22593            None
22594        }
22595    }
22596}
22597
22598#[test]
22599fn test_word_breaking_tokenizer() {
22600    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22601        ("", &[]),
22602        ("  ", &[whitespace("  ", 2)]),
22603        ("Ʒ", &[word("Ʒ", 1)]),
22604        ("Ǽ", &[word("Ǽ", 1)]),
22605        ("", &[word("", 1)]),
22606        ("⋑⋑", &[word("⋑⋑", 2)]),
22607        (
22608            "原理,进而",
22609            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22610        ),
22611        (
22612            "hello world",
22613            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22614        ),
22615        (
22616            "hello, world",
22617            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22618        ),
22619        (
22620            "  hello world",
22621            &[
22622                whitespace("  ", 2),
22623                word("hello", 5),
22624                whitespace(" ", 1),
22625                word("world", 5),
22626            ],
22627        ),
22628        (
22629            "这是什么 \n 钢笔",
22630            &[
22631                word("", 1),
22632                word("", 1),
22633                word("", 1),
22634                word("", 1),
22635                whitespace(" ", 1),
22636                newline(),
22637                whitespace(" ", 1),
22638                word("", 1),
22639                word("", 1),
22640            ],
22641        ),
22642        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22643    ];
22644
22645    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22646        WordBreakToken::Word {
22647            token,
22648            grapheme_len,
22649        }
22650    }
22651
22652    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22653        WordBreakToken::InlineWhitespace {
22654            token,
22655            grapheme_len,
22656        }
22657    }
22658
22659    fn newline() -> WordBreakToken<'static> {
22660        WordBreakToken::Newline
22661    }
22662
22663    for (input, result) in tests {
22664        assert_eq!(
22665            WordBreakingTokenizer::new(input)
22666                .collect::<Vec<_>>()
22667                .as_slice(),
22668            *result,
22669        );
22670    }
22671}
22672
22673fn wrap_with_prefix(
22674    first_line_prefix: String,
22675    subsequent_lines_prefix: String,
22676    unwrapped_text: String,
22677    wrap_column: usize,
22678    tab_size: NonZeroU32,
22679    preserve_existing_whitespace: bool,
22680) -> String {
22681    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22682    let subsequent_lines_prefix_len =
22683        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22684    let mut wrapped_text = String::new();
22685    let mut current_line = first_line_prefix;
22686    let mut is_first_line = true;
22687
22688    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22689    let mut current_line_len = first_line_prefix_len;
22690    let mut in_whitespace = false;
22691    for token in tokenizer {
22692        let have_preceding_whitespace = in_whitespace;
22693        match token {
22694            WordBreakToken::Word {
22695                token,
22696                grapheme_len,
22697            } => {
22698                in_whitespace = false;
22699                let current_prefix_len = if is_first_line {
22700                    first_line_prefix_len
22701                } else {
22702                    subsequent_lines_prefix_len
22703                };
22704                if current_line_len + grapheme_len > wrap_column
22705                    && current_line_len != current_prefix_len
22706                {
22707                    wrapped_text.push_str(current_line.trim_end());
22708                    wrapped_text.push('\n');
22709                    is_first_line = false;
22710                    current_line = subsequent_lines_prefix.clone();
22711                    current_line_len = subsequent_lines_prefix_len;
22712                }
22713                current_line.push_str(token);
22714                current_line_len += grapheme_len;
22715            }
22716            WordBreakToken::InlineWhitespace {
22717                mut token,
22718                mut grapheme_len,
22719            } => {
22720                in_whitespace = true;
22721                if have_preceding_whitespace && !preserve_existing_whitespace {
22722                    continue;
22723                }
22724                if !preserve_existing_whitespace {
22725                    // Keep a single whitespace grapheme as-is
22726                    if let Some(first) =
22727                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
22728                    {
22729                        token = first;
22730                    } else {
22731                        token = " ";
22732                    }
22733                    grapheme_len = 1;
22734                }
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                    wrapped_text.push_str(current_line.trim_end());
22742                    wrapped_text.push('\n');
22743                    is_first_line = false;
22744                    current_line = subsequent_lines_prefix.clone();
22745                    current_line_len = subsequent_lines_prefix_len;
22746                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22747                    current_line.push_str(token);
22748                    current_line_len += grapheme_len;
22749                }
22750            }
22751            WordBreakToken::Newline => {
22752                in_whitespace = true;
22753                let current_prefix_len = if is_first_line {
22754                    first_line_prefix_len
22755                } else {
22756                    subsequent_lines_prefix_len
22757                };
22758                if preserve_existing_whitespace {
22759                    wrapped_text.push_str(current_line.trim_end());
22760                    wrapped_text.push('\n');
22761                    is_first_line = false;
22762                    current_line = subsequent_lines_prefix.clone();
22763                    current_line_len = subsequent_lines_prefix_len;
22764                } else if have_preceding_whitespace {
22765                    continue;
22766                } else if current_line_len + 1 > wrap_column
22767                    && current_line_len != current_prefix_len
22768                {
22769                    wrapped_text.push_str(current_line.trim_end());
22770                    wrapped_text.push('\n');
22771                    is_first_line = false;
22772                    current_line = subsequent_lines_prefix.clone();
22773                    current_line_len = subsequent_lines_prefix_len;
22774                } else if current_line_len != current_prefix_len {
22775                    current_line.push(' ');
22776                    current_line_len += 1;
22777                }
22778            }
22779        }
22780    }
22781
22782    if !current_line.is_empty() {
22783        wrapped_text.push_str(&current_line);
22784    }
22785    wrapped_text
22786}
22787
22788#[test]
22789fn test_wrap_with_prefix() {
22790    assert_eq!(
22791        wrap_with_prefix(
22792            "# ".to_string(),
22793            "# ".to_string(),
22794            "abcdefg".to_string(),
22795            4,
22796            NonZeroU32::new(4).unwrap(),
22797            false,
22798        ),
22799        "# abcdefg"
22800    );
22801    assert_eq!(
22802        wrap_with_prefix(
22803            "".to_string(),
22804            "".to_string(),
22805            "\thello world".to_string(),
22806            8,
22807            NonZeroU32::new(4).unwrap(),
22808            false,
22809        ),
22810        "hello\nworld"
22811    );
22812    assert_eq!(
22813        wrap_with_prefix(
22814            "// ".to_string(),
22815            "// ".to_string(),
22816            "xx \nyy zz aa bb cc".to_string(),
22817            12,
22818            NonZeroU32::new(4).unwrap(),
22819            false,
22820        ),
22821        "// xx yy zz\n// aa bb cc"
22822    );
22823    assert_eq!(
22824        wrap_with_prefix(
22825            String::new(),
22826            String::new(),
22827            "这是什么 \n 钢笔".to_string(),
22828            3,
22829            NonZeroU32::new(4).unwrap(),
22830            false,
22831        ),
22832        "这是什\n么 钢\n"
22833    );
22834    assert_eq!(
22835        wrap_with_prefix(
22836            String::new(),
22837            String::new(),
22838            format!("foo{}bar", '\u{2009}'), // thin space
22839            80,
22840            NonZeroU32::new(4).unwrap(),
22841            false,
22842        ),
22843        format!("foo{}bar", '\u{2009}')
22844    );
22845}
22846
22847pub trait CollaborationHub {
22848    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22849    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22850    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22851}
22852
22853impl CollaborationHub for Entity<Project> {
22854    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22855        self.read(cx).collaborators()
22856    }
22857
22858    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22859        self.read(cx).user_store().read(cx).participant_indices()
22860    }
22861
22862    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22863        let this = self.read(cx);
22864        let user_ids = this.collaborators().values().map(|c| c.user_id);
22865        this.user_store().read(cx).participant_names(user_ids, cx)
22866    }
22867}
22868
22869pub trait SemanticsProvider {
22870    fn hover(
22871        &self,
22872        buffer: &Entity<Buffer>,
22873        position: text::Anchor,
22874        cx: &mut App,
22875    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22876
22877    fn inline_values(
22878        &self,
22879        buffer_handle: Entity<Buffer>,
22880        range: Range<text::Anchor>,
22881        cx: &mut App,
22882    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22883
22884    fn applicable_inlay_chunks(
22885        &self,
22886        buffer: &Entity<Buffer>,
22887        ranges: &[Range<text::Anchor>],
22888        cx: &mut App,
22889    ) -> Vec<Range<BufferRow>>;
22890
22891    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
22892
22893    fn inlay_hints(
22894        &self,
22895        invalidate: InvalidationStrategy,
22896        buffer: Entity<Buffer>,
22897        ranges: Vec<Range<text::Anchor>>,
22898        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
22899        cx: &mut App,
22900    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
22901
22902    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22903
22904    fn document_highlights(
22905        &self,
22906        buffer: &Entity<Buffer>,
22907        position: text::Anchor,
22908        cx: &mut App,
22909    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22910
22911    fn definitions(
22912        &self,
22913        buffer: &Entity<Buffer>,
22914        position: text::Anchor,
22915        kind: GotoDefinitionKind,
22916        cx: &mut App,
22917    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22918
22919    fn range_for_rename(
22920        &self,
22921        buffer: &Entity<Buffer>,
22922        position: text::Anchor,
22923        cx: &mut App,
22924    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22925
22926    fn perform_rename(
22927        &self,
22928        buffer: &Entity<Buffer>,
22929        position: text::Anchor,
22930        new_name: String,
22931        cx: &mut App,
22932    ) -> Option<Task<Result<ProjectTransaction>>>;
22933}
22934
22935pub trait CompletionProvider {
22936    fn completions(
22937        &self,
22938        excerpt_id: ExcerptId,
22939        buffer: &Entity<Buffer>,
22940        buffer_position: text::Anchor,
22941        trigger: CompletionContext,
22942        window: &mut Window,
22943        cx: &mut Context<Editor>,
22944    ) -> Task<Result<Vec<CompletionResponse>>>;
22945
22946    fn resolve_completions(
22947        &self,
22948        _buffer: Entity<Buffer>,
22949        _completion_indices: Vec<usize>,
22950        _completions: Rc<RefCell<Box<[Completion]>>>,
22951        _cx: &mut Context<Editor>,
22952    ) -> Task<Result<bool>> {
22953        Task::ready(Ok(false))
22954    }
22955
22956    fn apply_additional_edits_for_completion(
22957        &self,
22958        _buffer: Entity<Buffer>,
22959        _completions: Rc<RefCell<Box<[Completion]>>>,
22960        _completion_index: usize,
22961        _push_to_history: bool,
22962        _cx: &mut Context<Editor>,
22963    ) -> Task<Result<Option<language::Transaction>>> {
22964        Task::ready(Ok(None))
22965    }
22966
22967    fn is_completion_trigger(
22968        &self,
22969        buffer: &Entity<Buffer>,
22970        position: language::Anchor,
22971        text: &str,
22972        trigger_in_words: bool,
22973        menu_is_open: bool,
22974        cx: &mut Context<Editor>,
22975    ) -> bool;
22976
22977    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22978
22979    fn sort_completions(&self) -> bool {
22980        true
22981    }
22982
22983    fn filter_completions(&self) -> bool {
22984        true
22985    }
22986}
22987
22988pub trait CodeActionProvider {
22989    fn id(&self) -> Arc<str>;
22990
22991    fn code_actions(
22992        &self,
22993        buffer: &Entity<Buffer>,
22994        range: Range<text::Anchor>,
22995        window: &mut Window,
22996        cx: &mut App,
22997    ) -> Task<Result<Vec<CodeAction>>>;
22998
22999    fn apply_code_action(
23000        &self,
23001        buffer_handle: Entity<Buffer>,
23002        action: CodeAction,
23003        excerpt_id: ExcerptId,
23004        push_to_history: bool,
23005        window: &mut Window,
23006        cx: &mut App,
23007    ) -> Task<Result<ProjectTransaction>>;
23008}
23009
23010impl CodeActionProvider for Entity<Project> {
23011    fn id(&self) -> Arc<str> {
23012        "project".into()
23013    }
23014
23015    fn code_actions(
23016        &self,
23017        buffer: &Entity<Buffer>,
23018        range: Range<text::Anchor>,
23019        _window: &mut Window,
23020        cx: &mut App,
23021    ) -> Task<Result<Vec<CodeAction>>> {
23022        self.update(cx, |project, cx| {
23023            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
23024            let code_actions = project.code_actions(buffer, range, None, cx);
23025            cx.background_spawn(async move {
23026                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
23027                Ok(code_lens_actions
23028                    .context("code lens fetch")?
23029                    .into_iter()
23030                    .flatten()
23031                    .chain(
23032                        code_actions
23033                            .context("code action fetch")?
23034                            .into_iter()
23035                            .flatten(),
23036                    )
23037                    .collect())
23038            })
23039        })
23040    }
23041
23042    fn apply_code_action(
23043        &self,
23044        buffer_handle: Entity<Buffer>,
23045        action: CodeAction,
23046        _excerpt_id: ExcerptId,
23047        push_to_history: bool,
23048        _window: &mut Window,
23049        cx: &mut App,
23050    ) -> Task<Result<ProjectTransaction>> {
23051        self.update(cx, |project, cx| {
23052            project.apply_code_action(buffer_handle, action, push_to_history, cx)
23053        })
23054    }
23055}
23056
23057fn snippet_completions(
23058    project: &Project,
23059    buffer: &Entity<Buffer>,
23060    buffer_position: text::Anchor,
23061    cx: &mut App,
23062) -> Task<Result<CompletionResponse>> {
23063    let languages = buffer.read(cx).languages_at(buffer_position);
23064    let snippet_store = project.snippets().read(cx);
23065
23066    let scopes: Vec<_> = languages
23067        .iter()
23068        .filter_map(|language| {
23069            let language_name = language.lsp_id();
23070            let snippets = snippet_store.snippets_for(Some(language_name), cx);
23071
23072            if snippets.is_empty() {
23073                None
23074            } else {
23075                Some((language.default_scope(), snippets))
23076            }
23077        })
23078        .collect();
23079
23080    if scopes.is_empty() {
23081        return Task::ready(Ok(CompletionResponse {
23082            completions: vec![],
23083            display_options: CompletionDisplayOptions::default(),
23084            is_incomplete: false,
23085        }));
23086    }
23087
23088    let snapshot = buffer.read(cx).text_snapshot();
23089    let executor = cx.background_executor().clone();
23090
23091    cx.background_spawn(async move {
23092        let mut is_incomplete = false;
23093        let mut completions: Vec<Completion> = Vec::new();
23094        for (scope, snippets) in scopes.into_iter() {
23095            let classifier =
23096                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
23097
23098            const MAX_WORD_PREFIX_LEN: usize = 128;
23099            let last_word: String = snapshot
23100                .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
23101                .take(MAX_WORD_PREFIX_LEN)
23102                .take_while(|c| classifier.is_word(*c))
23103                .collect::<String>()
23104                .chars()
23105                .rev()
23106                .collect();
23107
23108            if last_word.is_empty() {
23109                return Ok(CompletionResponse {
23110                    completions: vec![],
23111                    display_options: CompletionDisplayOptions::default(),
23112                    is_incomplete: true,
23113                });
23114            }
23115
23116            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
23117            let to_lsp = |point: &text::Anchor| {
23118                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
23119                point_to_lsp(end)
23120            };
23121            let lsp_end = to_lsp(&buffer_position);
23122
23123            let candidates = snippets
23124                .iter()
23125                .enumerate()
23126                .flat_map(|(ix, snippet)| {
23127                    snippet
23128                        .prefix
23129                        .iter()
23130                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
23131                })
23132                .collect::<Vec<StringMatchCandidate>>();
23133
23134            const MAX_RESULTS: usize = 100;
23135            let mut matches = fuzzy::match_strings(
23136                &candidates,
23137                &last_word,
23138                last_word.chars().any(|c| c.is_uppercase()),
23139                true,
23140                MAX_RESULTS,
23141                &Default::default(),
23142                executor.clone(),
23143            )
23144            .await;
23145
23146            if matches.len() >= MAX_RESULTS {
23147                is_incomplete = true;
23148            }
23149
23150            // Remove all candidates where the query's start does not match the start of any word in the candidate
23151            if let Some(query_start) = last_word.chars().next() {
23152                matches.retain(|string_match| {
23153                    split_words(&string_match.string).any(|word| {
23154                        // Check that the first codepoint of the word as lowercase matches the first
23155                        // codepoint of the query as lowercase
23156                        word.chars()
23157                            .flat_map(|codepoint| codepoint.to_lowercase())
23158                            .zip(query_start.to_lowercase())
23159                            .all(|(word_cp, query_cp)| word_cp == query_cp)
23160                    })
23161                });
23162            }
23163
23164            let matched_strings = matches
23165                .into_iter()
23166                .map(|m| m.string)
23167                .collect::<HashSet<_>>();
23168
23169            completions.extend(snippets.iter().filter_map(|snippet| {
23170                let matching_prefix = snippet
23171                    .prefix
23172                    .iter()
23173                    .find(|prefix| matched_strings.contains(*prefix))?;
23174                let start = as_offset - last_word.len();
23175                let start = snapshot.anchor_before(start);
23176                let range = start..buffer_position;
23177                let lsp_start = to_lsp(&start);
23178                let lsp_range = lsp::Range {
23179                    start: lsp_start,
23180                    end: lsp_end,
23181                };
23182                Some(Completion {
23183                    replace_range: range,
23184                    new_text: snippet.body.clone(),
23185                    source: CompletionSource::Lsp {
23186                        insert_range: None,
23187                        server_id: LanguageServerId(usize::MAX),
23188                        resolved: true,
23189                        lsp_completion: Box::new(lsp::CompletionItem {
23190                            label: snippet.prefix.first().unwrap().clone(),
23191                            kind: Some(CompletionItemKind::SNIPPET),
23192                            label_details: snippet.description.as_ref().map(|description| {
23193                                lsp::CompletionItemLabelDetails {
23194                                    detail: Some(description.clone()),
23195                                    description: None,
23196                                }
23197                            }),
23198                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23199                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23200                                lsp::InsertReplaceEdit {
23201                                    new_text: snippet.body.clone(),
23202                                    insert: lsp_range,
23203                                    replace: lsp_range,
23204                                },
23205                            )),
23206                            filter_text: Some(snippet.body.clone()),
23207                            sort_text: Some(char::MAX.to_string()),
23208                            ..lsp::CompletionItem::default()
23209                        }),
23210                        lsp_defaults: None,
23211                    },
23212                    label: CodeLabel::plain(matching_prefix.clone(), None),
23213                    icon_path: None,
23214                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23215                        single_line: snippet.name.clone().into(),
23216                        plain_text: snippet
23217                            .description
23218                            .clone()
23219                            .map(|description| description.into()),
23220                    }),
23221                    insert_text_mode: None,
23222                    confirm: None,
23223                })
23224            }))
23225        }
23226
23227        Ok(CompletionResponse {
23228            completions,
23229            display_options: CompletionDisplayOptions::default(),
23230            is_incomplete,
23231        })
23232    })
23233}
23234
23235impl CompletionProvider for Entity<Project> {
23236    fn completions(
23237        &self,
23238        _excerpt_id: ExcerptId,
23239        buffer: &Entity<Buffer>,
23240        buffer_position: text::Anchor,
23241        options: CompletionContext,
23242        _window: &mut Window,
23243        cx: &mut Context<Editor>,
23244    ) -> Task<Result<Vec<CompletionResponse>>> {
23245        self.update(cx, |project, cx| {
23246            let snippets = snippet_completions(project, buffer, buffer_position, cx);
23247            let project_completions = project.completions(buffer, buffer_position, options, cx);
23248            cx.background_spawn(async move {
23249                let mut responses = project_completions.await?;
23250                let snippets = snippets.await?;
23251                if !snippets.completions.is_empty() {
23252                    responses.push(snippets);
23253                }
23254                Ok(responses)
23255            })
23256        })
23257    }
23258
23259    fn resolve_completions(
23260        &self,
23261        buffer: Entity<Buffer>,
23262        completion_indices: Vec<usize>,
23263        completions: Rc<RefCell<Box<[Completion]>>>,
23264        cx: &mut Context<Editor>,
23265    ) -> Task<Result<bool>> {
23266        self.update(cx, |project, cx| {
23267            project.lsp_store().update(cx, |lsp_store, cx| {
23268                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23269            })
23270        })
23271    }
23272
23273    fn apply_additional_edits_for_completion(
23274        &self,
23275        buffer: Entity<Buffer>,
23276        completions: Rc<RefCell<Box<[Completion]>>>,
23277        completion_index: usize,
23278        push_to_history: bool,
23279        cx: &mut Context<Editor>,
23280    ) -> Task<Result<Option<language::Transaction>>> {
23281        self.update(cx, |project, cx| {
23282            project.lsp_store().update(cx, |lsp_store, cx| {
23283                lsp_store.apply_additional_edits_for_completion(
23284                    buffer,
23285                    completions,
23286                    completion_index,
23287                    push_to_history,
23288                    cx,
23289                )
23290            })
23291        })
23292    }
23293
23294    fn is_completion_trigger(
23295        &self,
23296        buffer: &Entity<Buffer>,
23297        position: language::Anchor,
23298        text: &str,
23299        trigger_in_words: bool,
23300        menu_is_open: bool,
23301        cx: &mut Context<Editor>,
23302    ) -> bool {
23303        let mut chars = text.chars();
23304        let char = if let Some(char) = chars.next() {
23305            char
23306        } else {
23307            return false;
23308        };
23309        if chars.next().is_some() {
23310            return false;
23311        }
23312
23313        let buffer = buffer.read(cx);
23314        let snapshot = buffer.snapshot();
23315        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23316            return false;
23317        }
23318        let classifier = snapshot
23319            .char_classifier_at(position)
23320            .scope_context(Some(CharScopeContext::Completion));
23321        if trigger_in_words && classifier.is_word(char) {
23322            return true;
23323        }
23324
23325        buffer.completion_triggers().contains(text)
23326    }
23327}
23328
23329impl SemanticsProvider for Entity<Project> {
23330    fn hover(
23331        &self,
23332        buffer: &Entity<Buffer>,
23333        position: text::Anchor,
23334        cx: &mut App,
23335    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23336        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23337    }
23338
23339    fn document_highlights(
23340        &self,
23341        buffer: &Entity<Buffer>,
23342        position: text::Anchor,
23343        cx: &mut App,
23344    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23345        Some(self.update(cx, |project, cx| {
23346            project.document_highlights(buffer, position, cx)
23347        }))
23348    }
23349
23350    fn definitions(
23351        &self,
23352        buffer: &Entity<Buffer>,
23353        position: text::Anchor,
23354        kind: GotoDefinitionKind,
23355        cx: &mut App,
23356    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23357        Some(self.update(cx, |project, cx| match kind {
23358            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23359            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23360            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23361            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23362        }))
23363    }
23364
23365    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23366        self.update(cx, |project, cx| {
23367            if project
23368                .active_debug_session(cx)
23369                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23370            {
23371                return true;
23372            }
23373
23374            buffer.update(cx, |buffer, cx| {
23375                project.any_language_server_supports_inlay_hints(buffer, cx)
23376            })
23377        })
23378    }
23379
23380    fn inline_values(
23381        &self,
23382        buffer_handle: Entity<Buffer>,
23383        range: Range<text::Anchor>,
23384        cx: &mut App,
23385    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23386        self.update(cx, |project, cx| {
23387            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23388
23389            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23390        })
23391    }
23392
23393    fn applicable_inlay_chunks(
23394        &self,
23395        buffer: &Entity<Buffer>,
23396        ranges: &[Range<text::Anchor>],
23397        cx: &mut App,
23398    ) -> Vec<Range<BufferRow>> {
23399        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23400            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
23401        })
23402    }
23403
23404    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
23405        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
23406            lsp_store.invalidate_inlay_hints(for_buffers)
23407        });
23408    }
23409
23410    fn inlay_hints(
23411        &self,
23412        invalidate: InvalidationStrategy,
23413        buffer: Entity<Buffer>,
23414        ranges: Vec<Range<text::Anchor>>,
23415        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23416        cx: &mut App,
23417    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
23418        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23419            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
23420        }))
23421    }
23422
23423    fn range_for_rename(
23424        &self,
23425        buffer: &Entity<Buffer>,
23426        position: text::Anchor,
23427        cx: &mut App,
23428    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23429        Some(self.update(cx, |project, cx| {
23430            let buffer = buffer.clone();
23431            let task = project.prepare_rename(buffer.clone(), position, cx);
23432            cx.spawn(async move |_, cx| {
23433                Ok(match task.await? {
23434                    PrepareRenameResponse::Success(range) => Some(range),
23435                    PrepareRenameResponse::InvalidPosition => None,
23436                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23437                        // Fallback on using TreeSitter info to determine identifier range
23438                        buffer.read_with(cx, |buffer, _| {
23439                            let snapshot = buffer.snapshot();
23440                            let (range, kind) = snapshot.surrounding_word(position, None);
23441                            if kind != Some(CharKind::Word) {
23442                                return None;
23443                            }
23444                            Some(
23445                                snapshot.anchor_before(range.start)
23446                                    ..snapshot.anchor_after(range.end),
23447                            )
23448                        })?
23449                    }
23450                })
23451            })
23452        }))
23453    }
23454
23455    fn perform_rename(
23456        &self,
23457        buffer: &Entity<Buffer>,
23458        position: text::Anchor,
23459        new_name: String,
23460        cx: &mut App,
23461    ) -> Option<Task<Result<ProjectTransaction>>> {
23462        Some(self.update(cx, |project, cx| {
23463            project.perform_rename(buffer.clone(), position, new_name, cx)
23464        }))
23465    }
23466}
23467
23468fn consume_contiguous_rows(
23469    contiguous_row_selections: &mut Vec<Selection<Point>>,
23470    selection: &Selection<Point>,
23471    display_map: &DisplaySnapshot,
23472    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23473) -> (MultiBufferRow, MultiBufferRow) {
23474    contiguous_row_selections.push(selection.clone());
23475    let start_row = starting_row(selection, display_map);
23476    let mut end_row = ending_row(selection, display_map);
23477
23478    while let Some(next_selection) = selections.peek() {
23479        if next_selection.start.row <= end_row.0 {
23480            end_row = ending_row(next_selection, display_map);
23481            contiguous_row_selections.push(selections.next().unwrap().clone());
23482        } else {
23483            break;
23484        }
23485    }
23486    (start_row, end_row)
23487}
23488
23489fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23490    if selection.start.column > 0 {
23491        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23492    } else {
23493        MultiBufferRow(selection.start.row)
23494    }
23495}
23496
23497fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23498    if next_selection.end.column > 0 || next_selection.is_empty() {
23499        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23500    } else {
23501        MultiBufferRow(next_selection.end.row)
23502    }
23503}
23504
23505impl EditorSnapshot {
23506    pub fn remote_selections_in_range<'a>(
23507        &'a self,
23508        range: &'a Range<Anchor>,
23509        collaboration_hub: &dyn CollaborationHub,
23510        cx: &'a App,
23511    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23512        let participant_names = collaboration_hub.user_names(cx);
23513        let participant_indices = collaboration_hub.user_participant_indices(cx);
23514        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23515        let collaborators_by_replica_id = collaborators_by_peer_id
23516            .values()
23517            .map(|collaborator| (collaborator.replica_id, collaborator))
23518            .collect::<HashMap<_, _>>();
23519        self.buffer_snapshot()
23520            .selections_in_range(range, false)
23521            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23522                if replica_id == ReplicaId::AGENT {
23523                    Some(RemoteSelection {
23524                        replica_id,
23525                        selection,
23526                        cursor_shape,
23527                        line_mode,
23528                        collaborator_id: CollaboratorId::Agent,
23529                        user_name: Some("Agent".into()),
23530                        color: cx.theme().players().agent(),
23531                    })
23532                } else {
23533                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23534                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23535                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23536                    Some(RemoteSelection {
23537                        replica_id,
23538                        selection,
23539                        cursor_shape,
23540                        line_mode,
23541                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23542                        user_name,
23543                        color: if let Some(index) = participant_index {
23544                            cx.theme().players().color_for_participant(index.0)
23545                        } else {
23546                            cx.theme().players().absent()
23547                        },
23548                    })
23549                }
23550            })
23551    }
23552
23553    pub fn hunks_for_ranges(
23554        &self,
23555        ranges: impl IntoIterator<Item = Range<Point>>,
23556    ) -> Vec<MultiBufferDiffHunk> {
23557        let mut hunks = Vec::new();
23558        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23559            HashMap::default();
23560        for query_range in ranges {
23561            let query_rows =
23562                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23563            for hunk in self.buffer_snapshot().diff_hunks_in_range(
23564                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23565            ) {
23566                // Include deleted hunks that are adjacent to the query range, because
23567                // otherwise they would be missed.
23568                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23569                if hunk.status().is_deleted() {
23570                    intersects_range |= hunk.row_range.start == query_rows.end;
23571                    intersects_range |= hunk.row_range.end == query_rows.start;
23572                }
23573                if intersects_range {
23574                    if !processed_buffer_rows
23575                        .entry(hunk.buffer_id)
23576                        .or_default()
23577                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23578                    {
23579                        continue;
23580                    }
23581                    hunks.push(hunk);
23582                }
23583            }
23584        }
23585
23586        hunks
23587    }
23588
23589    fn display_diff_hunks_for_rows<'a>(
23590        &'a self,
23591        display_rows: Range<DisplayRow>,
23592        folded_buffers: &'a HashSet<BufferId>,
23593    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23594        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23595        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23596
23597        self.buffer_snapshot()
23598            .diff_hunks_in_range(buffer_start..buffer_end)
23599            .filter_map(|hunk| {
23600                if folded_buffers.contains(&hunk.buffer_id) {
23601                    return None;
23602                }
23603
23604                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23605                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23606
23607                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23608                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23609
23610                let display_hunk = if hunk_display_start.column() != 0 {
23611                    DisplayDiffHunk::Folded {
23612                        display_row: hunk_display_start.row(),
23613                    }
23614                } else {
23615                    let mut end_row = hunk_display_end.row();
23616                    if hunk_display_end.column() > 0 {
23617                        end_row.0 += 1;
23618                    }
23619                    let is_created_file = hunk.is_created_file();
23620                    DisplayDiffHunk::Unfolded {
23621                        status: hunk.status(),
23622                        diff_base_byte_range: hunk.diff_base_byte_range,
23623                        display_row_range: hunk_display_start.row()..end_row,
23624                        multi_buffer_range: Anchor::range_in_buffer(
23625                            hunk.excerpt_id,
23626                            hunk.buffer_id,
23627                            hunk.buffer_range,
23628                        ),
23629                        is_created_file,
23630                    }
23631                };
23632
23633                Some(display_hunk)
23634            })
23635    }
23636
23637    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23638        self.display_snapshot
23639            .buffer_snapshot()
23640            .language_at(position)
23641    }
23642
23643    pub fn is_focused(&self) -> bool {
23644        self.is_focused
23645    }
23646
23647    pub fn placeholder_text(&self) -> Option<String> {
23648        self.placeholder_display_snapshot
23649            .as_ref()
23650            .map(|display_map| display_map.text())
23651    }
23652
23653    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
23654        self.scroll_anchor.scroll_position(&self.display_snapshot)
23655    }
23656
23657    fn gutter_dimensions(
23658        &self,
23659        font_id: FontId,
23660        font_size: Pixels,
23661        max_line_number_width: Pixels,
23662        cx: &App,
23663    ) -> Option<GutterDimensions> {
23664        if !self.show_gutter {
23665            return None;
23666        }
23667
23668        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23669        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23670
23671        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23672            matches!(
23673                ProjectSettings::get_global(cx).git.git_gutter,
23674                GitGutterSetting::TrackedFiles
23675            )
23676        });
23677        let gutter_settings = EditorSettings::get_global(cx).gutter;
23678        let show_line_numbers = self
23679            .show_line_numbers
23680            .unwrap_or(gutter_settings.line_numbers);
23681        let line_gutter_width = if show_line_numbers {
23682            // Avoid flicker-like gutter resizes when the line number gains another digit by
23683            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23684            let min_width_for_number_on_gutter =
23685                ch_advance * gutter_settings.min_line_number_digits as f32;
23686            max_line_number_width.max(min_width_for_number_on_gutter)
23687        } else {
23688            0.0.into()
23689        };
23690
23691        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23692        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23693
23694        let git_blame_entries_width =
23695            self.git_blame_gutter_max_author_length
23696                .map(|max_author_length| {
23697                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23698                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23699
23700                    /// The number of characters to dedicate to gaps and margins.
23701                    const SPACING_WIDTH: usize = 4;
23702
23703                    let max_char_count = max_author_length.min(renderer.max_author_length())
23704                        + ::git::SHORT_SHA_LENGTH
23705                        + MAX_RELATIVE_TIMESTAMP.len()
23706                        + SPACING_WIDTH;
23707
23708                    ch_advance * max_char_count
23709                });
23710
23711        let is_singleton = self.buffer_snapshot().is_singleton();
23712
23713        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23714        left_padding += if !is_singleton {
23715            ch_width * 4.0
23716        } else if show_runnables || show_breakpoints {
23717            ch_width * 3.0
23718        } else if show_git_gutter && show_line_numbers {
23719            ch_width * 2.0
23720        } else if show_git_gutter || show_line_numbers {
23721            ch_width
23722        } else {
23723            px(0.)
23724        };
23725
23726        let shows_folds = is_singleton && gutter_settings.folds;
23727
23728        let right_padding = if shows_folds && show_line_numbers {
23729            ch_width * 4.0
23730        } else if shows_folds || (!is_singleton && show_line_numbers) {
23731            ch_width * 3.0
23732        } else if show_line_numbers {
23733            ch_width
23734        } else {
23735            px(0.)
23736        };
23737
23738        Some(GutterDimensions {
23739            left_padding,
23740            right_padding,
23741            width: line_gutter_width + left_padding + right_padding,
23742            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23743            git_blame_entries_width,
23744        })
23745    }
23746
23747    pub fn render_crease_toggle(
23748        &self,
23749        buffer_row: MultiBufferRow,
23750        row_contains_cursor: bool,
23751        editor: Entity<Editor>,
23752        window: &mut Window,
23753        cx: &mut App,
23754    ) -> Option<AnyElement> {
23755        let folded = self.is_line_folded(buffer_row);
23756        let mut is_foldable = false;
23757
23758        if let Some(crease) = self
23759            .crease_snapshot
23760            .query_row(buffer_row, self.buffer_snapshot())
23761        {
23762            is_foldable = true;
23763            match crease {
23764                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23765                    if let Some(render_toggle) = render_toggle {
23766                        let toggle_callback =
23767                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23768                                if folded {
23769                                    editor.update(cx, |editor, cx| {
23770                                        editor.fold_at(buffer_row, window, cx)
23771                                    });
23772                                } else {
23773                                    editor.update(cx, |editor, cx| {
23774                                        editor.unfold_at(buffer_row, window, cx)
23775                                    });
23776                                }
23777                            });
23778                        return Some((render_toggle)(
23779                            buffer_row,
23780                            folded,
23781                            toggle_callback,
23782                            window,
23783                            cx,
23784                        ));
23785                    }
23786                }
23787            }
23788        }
23789
23790        is_foldable |= self.starts_indent(buffer_row);
23791
23792        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23793            Some(
23794                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23795                    .toggle_state(folded)
23796                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23797                        if folded {
23798                            this.unfold_at(buffer_row, window, cx);
23799                        } else {
23800                            this.fold_at(buffer_row, window, cx);
23801                        }
23802                    }))
23803                    .into_any_element(),
23804            )
23805        } else {
23806            None
23807        }
23808    }
23809
23810    pub fn render_crease_trailer(
23811        &self,
23812        buffer_row: MultiBufferRow,
23813        window: &mut Window,
23814        cx: &mut App,
23815    ) -> Option<AnyElement> {
23816        let folded = self.is_line_folded(buffer_row);
23817        if let Crease::Inline { render_trailer, .. } = self
23818            .crease_snapshot
23819            .query_row(buffer_row, self.buffer_snapshot())?
23820        {
23821            let render_trailer = render_trailer.as_ref()?;
23822            Some(render_trailer(buffer_row, folded, window, cx))
23823        } else {
23824            None
23825        }
23826    }
23827}
23828
23829impl Deref for EditorSnapshot {
23830    type Target = DisplaySnapshot;
23831
23832    fn deref(&self) -> &Self::Target {
23833        &self.display_snapshot
23834    }
23835}
23836
23837#[derive(Clone, Debug, PartialEq, Eq)]
23838pub enum EditorEvent {
23839    InputIgnored {
23840        text: Arc<str>,
23841    },
23842    InputHandled {
23843        utf16_range_to_replace: Option<Range<isize>>,
23844        text: Arc<str>,
23845    },
23846    ExcerptsAdded {
23847        buffer: Entity<Buffer>,
23848        predecessor: ExcerptId,
23849        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23850    },
23851    ExcerptsRemoved {
23852        ids: Vec<ExcerptId>,
23853        removed_buffer_ids: Vec<BufferId>,
23854    },
23855    BufferFoldToggled {
23856        ids: Vec<ExcerptId>,
23857        folded: bool,
23858    },
23859    ExcerptsEdited {
23860        ids: Vec<ExcerptId>,
23861    },
23862    ExcerptsExpanded {
23863        ids: Vec<ExcerptId>,
23864    },
23865    BufferEdited,
23866    Edited {
23867        transaction_id: clock::Lamport,
23868    },
23869    Reparsed(BufferId),
23870    Focused,
23871    FocusedIn,
23872    Blurred,
23873    DirtyChanged,
23874    Saved,
23875    TitleChanged,
23876    SelectionsChanged {
23877        local: bool,
23878    },
23879    ScrollPositionChanged {
23880        local: bool,
23881        autoscroll: bool,
23882    },
23883    TransactionUndone {
23884        transaction_id: clock::Lamport,
23885    },
23886    TransactionBegun {
23887        transaction_id: clock::Lamport,
23888    },
23889    CursorShapeChanged,
23890    BreadcrumbsChanged,
23891    PushedToNavHistory {
23892        anchor: Anchor,
23893        is_deactivate: bool,
23894    },
23895}
23896
23897impl EventEmitter<EditorEvent> for Editor {}
23898
23899impl Focusable for Editor {
23900    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23901        self.focus_handle.clone()
23902    }
23903}
23904
23905impl Render for Editor {
23906    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23907        let settings = ThemeSettings::get_global(cx);
23908
23909        let mut text_style = match self.mode {
23910            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23911                color: cx.theme().colors().editor_foreground,
23912                font_family: settings.ui_font.family.clone(),
23913                font_features: settings.ui_font.features.clone(),
23914                font_fallbacks: settings.ui_font.fallbacks.clone(),
23915                font_size: rems(0.875).into(),
23916                font_weight: settings.ui_font.weight,
23917                line_height: relative(settings.buffer_line_height.value()),
23918                ..Default::default()
23919            },
23920            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23921                color: cx.theme().colors().editor_foreground,
23922                font_family: settings.buffer_font.family.clone(),
23923                font_features: settings.buffer_font.features.clone(),
23924                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23925                font_size: settings.buffer_font_size(cx).into(),
23926                font_weight: settings.buffer_font.weight,
23927                line_height: relative(settings.buffer_line_height.value()),
23928                ..Default::default()
23929            },
23930        };
23931        if let Some(text_style_refinement) = &self.text_style_refinement {
23932            text_style.refine(text_style_refinement)
23933        }
23934
23935        let background = match self.mode {
23936            EditorMode::SingleLine => cx.theme().system().transparent,
23937            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23938            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23939            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23940        };
23941
23942        EditorElement::new(
23943            &cx.entity(),
23944            EditorStyle {
23945                background,
23946                border: cx.theme().colors().border,
23947                local_player: cx.theme().players().local(),
23948                text: text_style,
23949                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23950                syntax: cx.theme().syntax().clone(),
23951                status: cx.theme().status().clone(),
23952                inlay_hints_style: make_inlay_hints_style(cx),
23953                edit_prediction_styles: make_suggestion_styles(cx),
23954                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23955                show_underlines: self.diagnostics_enabled(),
23956            },
23957        )
23958    }
23959}
23960
23961impl EntityInputHandler for Editor {
23962    fn text_for_range(
23963        &mut self,
23964        range_utf16: Range<usize>,
23965        adjusted_range: &mut Option<Range<usize>>,
23966        _: &mut Window,
23967        cx: &mut Context<Self>,
23968    ) -> Option<String> {
23969        let snapshot = self.buffer.read(cx).read(cx);
23970        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23971        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23972        if (start.0..end.0) != range_utf16 {
23973            adjusted_range.replace(start.0..end.0);
23974        }
23975        Some(snapshot.text_for_range(start..end).collect())
23976    }
23977
23978    fn selected_text_range(
23979        &mut self,
23980        ignore_disabled_input: bool,
23981        _: &mut Window,
23982        cx: &mut Context<Self>,
23983    ) -> Option<UTF16Selection> {
23984        // Prevent the IME menu from appearing when holding down an alphabetic key
23985        // while input is disabled.
23986        if !ignore_disabled_input && !self.input_enabled {
23987            return None;
23988        }
23989
23990        let selection = self
23991            .selections
23992            .newest::<OffsetUtf16>(&self.display_snapshot(cx));
23993        let range = selection.range();
23994
23995        Some(UTF16Selection {
23996            range: range.start.0..range.end.0,
23997            reversed: selection.reversed,
23998        })
23999    }
24000
24001    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
24002        let snapshot = self.buffer.read(cx).read(cx);
24003        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
24004        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
24005    }
24006
24007    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
24008        self.clear_highlights::<InputComposition>(cx);
24009        self.ime_transaction.take();
24010    }
24011
24012    fn replace_text_in_range(
24013        &mut self,
24014        range_utf16: Option<Range<usize>>,
24015        text: &str,
24016        window: &mut Window,
24017        cx: &mut Context<Self>,
24018    ) {
24019        if !self.input_enabled {
24020            cx.emit(EditorEvent::InputIgnored { text: text.into() });
24021            return;
24022        }
24023
24024        self.transact(window, cx, |this, window, cx| {
24025            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
24026                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
24027                Some(this.selection_replacement_ranges(range_utf16, cx))
24028            } else {
24029                this.marked_text_ranges(cx)
24030            };
24031
24032            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
24033                let newest_selection_id = this.selections.newest_anchor().id;
24034                this.selections
24035                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
24036                    .iter()
24037                    .zip(ranges_to_replace.iter())
24038                    .find_map(|(selection, range)| {
24039                        if selection.id == newest_selection_id {
24040                            Some(
24041                                (range.start.0 as isize - selection.head().0 as isize)
24042                                    ..(range.end.0 as isize - selection.head().0 as isize),
24043                            )
24044                        } else {
24045                            None
24046                        }
24047                    })
24048            });
24049
24050            cx.emit(EditorEvent::InputHandled {
24051                utf16_range_to_replace: range_to_replace,
24052                text: text.into(),
24053            });
24054
24055            if let Some(new_selected_ranges) = new_selected_ranges {
24056                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24057                    selections.select_ranges(new_selected_ranges)
24058                });
24059                this.backspace(&Default::default(), window, cx);
24060            }
24061
24062            this.handle_input(text, window, cx);
24063        });
24064
24065        if let Some(transaction) = self.ime_transaction {
24066            self.buffer.update(cx, |buffer, cx| {
24067                buffer.group_until_transaction(transaction, cx);
24068            });
24069        }
24070
24071        self.unmark_text(window, cx);
24072    }
24073
24074    fn replace_and_mark_text_in_range(
24075        &mut self,
24076        range_utf16: Option<Range<usize>>,
24077        text: &str,
24078        new_selected_range_utf16: Option<Range<usize>>,
24079        window: &mut Window,
24080        cx: &mut Context<Self>,
24081    ) {
24082        if !self.input_enabled {
24083            return;
24084        }
24085
24086        let transaction = self.transact(window, cx, |this, window, cx| {
24087            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
24088                let snapshot = this.buffer.read(cx).read(cx);
24089                if let Some(relative_range_utf16) = range_utf16.as_ref() {
24090                    for marked_range in &mut marked_ranges {
24091                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
24092                        marked_range.start.0 += relative_range_utf16.start;
24093                        marked_range.start =
24094                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
24095                        marked_range.end =
24096                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
24097                    }
24098                }
24099                Some(marked_ranges)
24100            } else if let Some(range_utf16) = range_utf16 {
24101                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
24102                Some(this.selection_replacement_ranges(range_utf16, cx))
24103            } else {
24104                None
24105            };
24106
24107            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
24108                let newest_selection_id = this.selections.newest_anchor().id;
24109                this.selections
24110                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
24111                    .iter()
24112                    .zip(ranges_to_replace.iter())
24113                    .find_map(|(selection, range)| {
24114                        if selection.id == newest_selection_id {
24115                            Some(
24116                                (range.start.0 as isize - selection.head().0 as isize)
24117                                    ..(range.end.0 as isize - selection.head().0 as isize),
24118                            )
24119                        } else {
24120                            None
24121                        }
24122                    })
24123            });
24124
24125            cx.emit(EditorEvent::InputHandled {
24126                utf16_range_to_replace: range_to_replace,
24127                text: text.into(),
24128            });
24129
24130            if let Some(ranges) = ranges_to_replace {
24131                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24132                    s.select_ranges(ranges)
24133                });
24134            }
24135
24136            let marked_ranges = {
24137                let snapshot = this.buffer.read(cx).read(cx);
24138                this.selections
24139                    .disjoint_anchors_arc()
24140                    .iter()
24141                    .map(|selection| {
24142                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
24143                    })
24144                    .collect::<Vec<_>>()
24145            };
24146
24147            if text.is_empty() {
24148                this.unmark_text(window, cx);
24149            } else {
24150                this.highlight_text::<InputComposition>(
24151                    marked_ranges.clone(),
24152                    HighlightStyle {
24153                        underline: Some(UnderlineStyle {
24154                            thickness: px(1.),
24155                            color: None,
24156                            wavy: false,
24157                        }),
24158                        ..Default::default()
24159                    },
24160                    cx,
24161                );
24162            }
24163
24164            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
24165            let use_autoclose = this.use_autoclose;
24166            let use_auto_surround = this.use_auto_surround;
24167            this.set_use_autoclose(false);
24168            this.set_use_auto_surround(false);
24169            this.handle_input(text, window, cx);
24170            this.set_use_autoclose(use_autoclose);
24171            this.set_use_auto_surround(use_auto_surround);
24172
24173            if let Some(new_selected_range) = new_selected_range_utf16 {
24174                let snapshot = this.buffer.read(cx).read(cx);
24175                let new_selected_ranges = marked_ranges
24176                    .into_iter()
24177                    .map(|marked_range| {
24178                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24179                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
24180                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
24181                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24182                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24183                    })
24184                    .collect::<Vec<_>>();
24185
24186                drop(snapshot);
24187                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24188                    selections.select_ranges(new_selected_ranges)
24189                });
24190            }
24191        });
24192
24193        self.ime_transaction = self.ime_transaction.or(transaction);
24194        if let Some(transaction) = self.ime_transaction {
24195            self.buffer.update(cx, |buffer, cx| {
24196                buffer.group_until_transaction(transaction, cx);
24197            });
24198        }
24199
24200        if self.text_highlights::<InputComposition>(cx).is_none() {
24201            self.ime_transaction.take();
24202        }
24203    }
24204
24205    fn bounds_for_range(
24206        &mut self,
24207        range_utf16: Range<usize>,
24208        element_bounds: gpui::Bounds<Pixels>,
24209        window: &mut Window,
24210        cx: &mut Context<Self>,
24211    ) -> Option<gpui::Bounds<Pixels>> {
24212        let text_layout_details = self.text_layout_details(window);
24213        let CharacterDimensions {
24214            em_width,
24215            em_advance,
24216            line_height,
24217        } = self.character_dimensions(window);
24218
24219        let snapshot = self.snapshot(window, cx);
24220        let scroll_position = snapshot.scroll_position();
24221        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24222
24223        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
24224        let x = Pixels::from(
24225            ScrollOffset::from(
24226                snapshot.x_for_display_point(start, &text_layout_details)
24227                    + self.gutter_dimensions.full_width(),
24228            ) - scroll_left,
24229        );
24230        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24231
24232        Some(Bounds {
24233            origin: element_bounds.origin + point(x, y),
24234            size: size(em_width, line_height),
24235        })
24236    }
24237
24238    fn character_index_for_point(
24239        &mut self,
24240        point: gpui::Point<Pixels>,
24241        _window: &mut Window,
24242        _cx: &mut Context<Self>,
24243    ) -> Option<usize> {
24244        let position_map = self.last_position_map.as_ref()?;
24245        if !position_map.text_hitbox.contains(&point) {
24246            return None;
24247        }
24248        let display_point = position_map.point_for_position(point).previous_valid;
24249        let anchor = position_map
24250            .snapshot
24251            .display_point_to_anchor(display_point, Bias::Left);
24252        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24253        Some(utf16_offset.0)
24254    }
24255
24256    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
24257        self.input_enabled
24258    }
24259}
24260
24261trait SelectionExt {
24262    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24263    fn spanned_rows(
24264        &self,
24265        include_end_if_at_line_start: bool,
24266        map: &DisplaySnapshot,
24267    ) -> Range<MultiBufferRow>;
24268}
24269
24270impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24271    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24272        let start = self
24273            .start
24274            .to_point(map.buffer_snapshot())
24275            .to_display_point(map);
24276        let end = self
24277            .end
24278            .to_point(map.buffer_snapshot())
24279            .to_display_point(map);
24280        if self.reversed {
24281            end..start
24282        } else {
24283            start..end
24284        }
24285    }
24286
24287    fn spanned_rows(
24288        &self,
24289        include_end_if_at_line_start: bool,
24290        map: &DisplaySnapshot,
24291    ) -> Range<MultiBufferRow> {
24292        let start = self.start.to_point(map.buffer_snapshot());
24293        let mut end = self.end.to_point(map.buffer_snapshot());
24294        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24295            end.row -= 1;
24296        }
24297
24298        let buffer_start = map.prev_line_boundary(start).0;
24299        let buffer_end = map.next_line_boundary(end).0;
24300        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24301    }
24302}
24303
24304impl<T: InvalidationRegion> InvalidationStack<T> {
24305    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24306    where
24307        S: Clone + ToOffset,
24308    {
24309        while let Some(region) = self.last() {
24310            let all_selections_inside_invalidation_ranges =
24311                if selections.len() == region.ranges().len() {
24312                    selections
24313                        .iter()
24314                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24315                        .all(|(selection, invalidation_range)| {
24316                            let head = selection.head().to_offset(buffer);
24317                            invalidation_range.start <= head && invalidation_range.end >= head
24318                        })
24319                } else {
24320                    false
24321                };
24322
24323            if all_selections_inside_invalidation_ranges {
24324                break;
24325            } else {
24326                self.pop();
24327            }
24328        }
24329    }
24330}
24331
24332impl<T> Default for InvalidationStack<T> {
24333    fn default() -> Self {
24334        Self(Default::default())
24335    }
24336}
24337
24338impl<T> Deref for InvalidationStack<T> {
24339    type Target = Vec<T>;
24340
24341    fn deref(&self) -> &Self::Target {
24342        &self.0
24343    }
24344}
24345
24346impl<T> DerefMut for InvalidationStack<T> {
24347    fn deref_mut(&mut self) -> &mut Self::Target {
24348        &mut self.0
24349    }
24350}
24351
24352impl InvalidationRegion for SnippetState {
24353    fn ranges(&self) -> &[Range<Anchor>] {
24354        &self.ranges[self.active_index]
24355    }
24356}
24357
24358fn edit_prediction_edit_text(
24359    current_snapshot: &BufferSnapshot,
24360    edits: &[(Range<Anchor>, String)],
24361    edit_preview: &EditPreview,
24362    include_deletions: bool,
24363    cx: &App,
24364) -> HighlightedText {
24365    let edits = edits
24366        .iter()
24367        .map(|(anchor, text)| {
24368            (
24369                anchor.start.text_anchor..anchor.end.text_anchor,
24370                text.clone(),
24371            )
24372        })
24373        .collect::<Vec<_>>();
24374
24375    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24376}
24377
24378fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
24379    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24380    // Just show the raw edit text with basic styling
24381    let mut text = String::new();
24382    let mut highlights = Vec::new();
24383
24384    let insertion_highlight_style = HighlightStyle {
24385        color: Some(cx.theme().colors().text),
24386        ..Default::default()
24387    };
24388
24389    for (_, edit_text) in edits {
24390        let start_offset = text.len();
24391        text.push_str(edit_text);
24392        let end_offset = text.len();
24393
24394        if start_offset < end_offset {
24395            highlights.push((start_offset..end_offset, insertion_highlight_style));
24396        }
24397    }
24398
24399    HighlightedText {
24400        text: text.into(),
24401        highlights,
24402    }
24403}
24404
24405pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24406    match severity {
24407        lsp::DiagnosticSeverity::ERROR => colors.error,
24408        lsp::DiagnosticSeverity::WARNING => colors.warning,
24409        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24410        lsp::DiagnosticSeverity::HINT => colors.info,
24411        _ => colors.ignored,
24412    }
24413}
24414
24415pub fn styled_runs_for_code_label<'a>(
24416    label: &'a CodeLabel,
24417    syntax_theme: &'a theme::SyntaxTheme,
24418) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24419    let fade_out = HighlightStyle {
24420        fade_out: Some(0.35),
24421        ..Default::default()
24422    };
24423
24424    let mut prev_end = label.filter_range.end;
24425    label
24426        .runs
24427        .iter()
24428        .enumerate()
24429        .flat_map(move |(ix, (range, highlight_id))| {
24430            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24431                style
24432            } else {
24433                return Default::default();
24434            };
24435            let muted_style = style.highlight(fade_out);
24436
24437            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24438            if range.start >= label.filter_range.end {
24439                if range.start > prev_end {
24440                    runs.push((prev_end..range.start, fade_out));
24441                }
24442                runs.push((range.clone(), muted_style));
24443            } else if range.end <= label.filter_range.end {
24444                runs.push((range.clone(), style));
24445            } else {
24446                runs.push((range.start..label.filter_range.end, style));
24447                runs.push((label.filter_range.end..range.end, muted_style));
24448            }
24449            prev_end = cmp::max(prev_end, range.end);
24450
24451            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24452                runs.push((prev_end..label.text.len(), fade_out));
24453            }
24454
24455            runs
24456        })
24457}
24458
24459pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24460    let mut prev_index = 0;
24461    let mut prev_codepoint: Option<char> = None;
24462    text.char_indices()
24463        .chain([(text.len(), '\0')])
24464        .filter_map(move |(index, codepoint)| {
24465            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24466            let is_boundary = index == text.len()
24467                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24468                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24469            if is_boundary {
24470                let chunk = &text[prev_index..index];
24471                prev_index = index;
24472                Some(chunk)
24473            } else {
24474                None
24475            }
24476        })
24477}
24478
24479pub trait RangeToAnchorExt: Sized {
24480    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24481
24482    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24483        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
24484        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24485    }
24486}
24487
24488impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24489    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24490        let start_offset = self.start.to_offset(snapshot);
24491        let end_offset = self.end.to_offset(snapshot);
24492        if start_offset == end_offset {
24493            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24494        } else {
24495            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24496        }
24497    }
24498}
24499
24500pub trait RowExt {
24501    fn as_f64(&self) -> f64;
24502
24503    fn next_row(&self) -> Self;
24504
24505    fn previous_row(&self) -> Self;
24506
24507    fn minus(&self, other: Self) -> u32;
24508}
24509
24510impl RowExt for DisplayRow {
24511    fn as_f64(&self) -> f64 {
24512        self.0 as _
24513    }
24514
24515    fn next_row(&self) -> Self {
24516        Self(self.0 + 1)
24517    }
24518
24519    fn previous_row(&self) -> Self {
24520        Self(self.0.saturating_sub(1))
24521    }
24522
24523    fn minus(&self, other: Self) -> u32 {
24524        self.0 - other.0
24525    }
24526}
24527
24528impl RowExt for MultiBufferRow {
24529    fn as_f64(&self) -> f64 {
24530        self.0 as _
24531    }
24532
24533    fn next_row(&self) -> Self {
24534        Self(self.0 + 1)
24535    }
24536
24537    fn previous_row(&self) -> Self {
24538        Self(self.0.saturating_sub(1))
24539    }
24540
24541    fn minus(&self, other: Self) -> u32 {
24542        self.0 - other.0
24543    }
24544}
24545
24546trait RowRangeExt {
24547    type Row;
24548
24549    fn len(&self) -> usize;
24550
24551    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24552}
24553
24554impl RowRangeExt for Range<MultiBufferRow> {
24555    type Row = MultiBufferRow;
24556
24557    fn len(&self) -> usize {
24558        (self.end.0 - self.start.0) as usize
24559    }
24560
24561    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24562        (self.start.0..self.end.0).map(MultiBufferRow)
24563    }
24564}
24565
24566impl RowRangeExt for Range<DisplayRow> {
24567    type Row = DisplayRow;
24568
24569    fn len(&self) -> usize {
24570        (self.end.0 - self.start.0) as usize
24571    }
24572
24573    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24574        (self.start.0..self.end.0).map(DisplayRow)
24575    }
24576}
24577
24578/// If select range has more than one line, we
24579/// just point the cursor to range.start.
24580fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24581    if range.start.row == range.end.row {
24582        range
24583    } else {
24584        range.start..range.start
24585    }
24586}
24587pub struct KillRing(ClipboardItem);
24588impl Global for KillRing {}
24589
24590const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24591
24592enum BreakpointPromptEditAction {
24593    Log,
24594    Condition,
24595    HitCondition,
24596}
24597
24598struct BreakpointPromptEditor {
24599    pub(crate) prompt: Entity<Editor>,
24600    editor: WeakEntity<Editor>,
24601    breakpoint_anchor: Anchor,
24602    breakpoint: Breakpoint,
24603    edit_action: BreakpointPromptEditAction,
24604    block_ids: HashSet<CustomBlockId>,
24605    editor_margins: Arc<Mutex<EditorMargins>>,
24606    _subscriptions: Vec<Subscription>,
24607}
24608
24609impl BreakpointPromptEditor {
24610    const MAX_LINES: u8 = 4;
24611
24612    fn new(
24613        editor: WeakEntity<Editor>,
24614        breakpoint_anchor: Anchor,
24615        breakpoint: Breakpoint,
24616        edit_action: BreakpointPromptEditAction,
24617        window: &mut Window,
24618        cx: &mut Context<Self>,
24619    ) -> Self {
24620        let base_text = match edit_action {
24621            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24622            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24623            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24624        }
24625        .map(|msg| msg.to_string())
24626        .unwrap_or_default();
24627
24628        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24629        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24630
24631        let prompt = cx.new(|cx| {
24632            let mut prompt = Editor::new(
24633                EditorMode::AutoHeight {
24634                    min_lines: 1,
24635                    max_lines: Some(Self::MAX_LINES as usize),
24636                },
24637                buffer,
24638                None,
24639                window,
24640                cx,
24641            );
24642            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24643            prompt.set_show_cursor_when_unfocused(false, cx);
24644            prompt.set_placeholder_text(
24645                match edit_action {
24646                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24647                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24648                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24649                },
24650                window,
24651                cx,
24652            );
24653
24654            prompt
24655        });
24656
24657        Self {
24658            prompt,
24659            editor,
24660            breakpoint_anchor,
24661            breakpoint,
24662            edit_action,
24663            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24664            block_ids: Default::default(),
24665            _subscriptions: vec![],
24666        }
24667    }
24668
24669    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24670        self.block_ids.extend(block_ids)
24671    }
24672
24673    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24674        if let Some(editor) = self.editor.upgrade() {
24675            let message = self
24676                .prompt
24677                .read(cx)
24678                .buffer
24679                .read(cx)
24680                .as_singleton()
24681                .expect("A multi buffer in breakpoint prompt isn't possible")
24682                .read(cx)
24683                .as_rope()
24684                .to_string();
24685
24686            editor.update(cx, |editor, cx| {
24687                editor.edit_breakpoint_at_anchor(
24688                    self.breakpoint_anchor,
24689                    self.breakpoint.clone(),
24690                    match self.edit_action {
24691                        BreakpointPromptEditAction::Log => {
24692                            BreakpointEditAction::EditLogMessage(message.into())
24693                        }
24694                        BreakpointPromptEditAction::Condition => {
24695                            BreakpointEditAction::EditCondition(message.into())
24696                        }
24697                        BreakpointPromptEditAction::HitCondition => {
24698                            BreakpointEditAction::EditHitCondition(message.into())
24699                        }
24700                    },
24701                    cx,
24702                );
24703
24704                editor.remove_blocks(self.block_ids.clone(), None, cx);
24705                cx.focus_self(window);
24706            });
24707        }
24708    }
24709
24710    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24711        self.editor
24712            .update(cx, |editor, cx| {
24713                editor.remove_blocks(self.block_ids.clone(), None, cx);
24714                window.focus(&editor.focus_handle);
24715            })
24716            .log_err();
24717    }
24718
24719    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24720        let settings = ThemeSettings::get_global(cx);
24721        let text_style = TextStyle {
24722            color: if self.prompt.read(cx).read_only(cx) {
24723                cx.theme().colors().text_disabled
24724            } else {
24725                cx.theme().colors().text
24726            },
24727            font_family: settings.buffer_font.family.clone(),
24728            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24729            font_size: settings.buffer_font_size(cx).into(),
24730            font_weight: settings.buffer_font.weight,
24731            line_height: relative(settings.buffer_line_height.value()),
24732            ..Default::default()
24733        };
24734        EditorElement::new(
24735            &self.prompt,
24736            EditorStyle {
24737                background: cx.theme().colors().editor_background,
24738                local_player: cx.theme().players().local(),
24739                text: text_style,
24740                ..Default::default()
24741            },
24742        )
24743    }
24744}
24745
24746impl Render for BreakpointPromptEditor {
24747    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24748        let editor_margins = *self.editor_margins.lock();
24749        let gutter_dimensions = editor_margins.gutter;
24750        h_flex()
24751            .key_context("Editor")
24752            .bg(cx.theme().colors().editor_background)
24753            .border_y_1()
24754            .border_color(cx.theme().status().info_border)
24755            .size_full()
24756            .py(window.line_height() / 2.5)
24757            .on_action(cx.listener(Self::confirm))
24758            .on_action(cx.listener(Self::cancel))
24759            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24760            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24761    }
24762}
24763
24764impl Focusable for BreakpointPromptEditor {
24765    fn focus_handle(&self, cx: &App) -> FocusHandle {
24766        self.prompt.focus_handle(cx)
24767    }
24768}
24769
24770fn all_edits_insertions_or_deletions(
24771    edits: &Vec<(Range<Anchor>, String)>,
24772    snapshot: &MultiBufferSnapshot,
24773) -> bool {
24774    let mut all_insertions = true;
24775    let mut all_deletions = true;
24776
24777    for (range, new_text) in edits.iter() {
24778        let range_is_empty = range.to_offset(snapshot).is_empty();
24779        let text_is_empty = new_text.is_empty();
24780
24781        if range_is_empty != text_is_empty {
24782            if range_is_empty {
24783                all_deletions = false;
24784            } else {
24785                all_insertions = false;
24786            }
24787        } else {
24788            return false;
24789        }
24790
24791        if !all_insertions && !all_deletions {
24792            return false;
24793        }
24794    }
24795    all_insertions || all_deletions
24796}
24797
24798struct MissingEditPredictionKeybindingTooltip;
24799
24800impl Render for MissingEditPredictionKeybindingTooltip {
24801    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24802        ui::tooltip_container(cx, |container, cx| {
24803            container
24804                .flex_shrink_0()
24805                .max_w_80()
24806                .min_h(rems_from_px(124.))
24807                .justify_between()
24808                .child(
24809                    v_flex()
24810                        .flex_1()
24811                        .text_ui_sm(cx)
24812                        .child(Label::new("Conflict with Accept Keybinding"))
24813                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24814                )
24815                .child(
24816                    h_flex()
24817                        .pb_1()
24818                        .gap_1()
24819                        .items_end()
24820                        .w_full()
24821                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24822                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
24823                        }))
24824                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24825                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24826                        })),
24827                )
24828        })
24829    }
24830}
24831
24832#[derive(Debug, Clone, Copy, PartialEq)]
24833pub struct LineHighlight {
24834    pub background: Background,
24835    pub border: Option<gpui::Hsla>,
24836    pub include_gutter: bool,
24837    pub type_id: Option<TypeId>,
24838}
24839
24840struct LineManipulationResult {
24841    pub new_text: String,
24842    pub line_count_before: usize,
24843    pub line_count_after: usize,
24844}
24845
24846fn render_diff_hunk_controls(
24847    row: u32,
24848    status: &DiffHunkStatus,
24849    hunk_range: Range<Anchor>,
24850    is_created_file: bool,
24851    line_height: Pixels,
24852    editor: &Entity<Editor>,
24853    _window: &mut Window,
24854    cx: &mut App,
24855) -> AnyElement {
24856    h_flex()
24857        .h(line_height)
24858        .mr_1()
24859        .gap_1()
24860        .px_0p5()
24861        .pb_1()
24862        .border_x_1()
24863        .border_b_1()
24864        .border_color(cx.theme().colors().border_variant)
24865        .rounded_b_lg()
24866        .bg(cx.theme().colors().editor_background)
24867        .gap_1()
24868        .block_mouse_except_scroll()
24869        .shadow_md()
24870        .child(if status.has_secondary_hunk() {
24871            Button::new(("stage", row as u64), "Stage")
24872                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24873                .tooltip({
24874                    let focus_handle = editor.focus_handle(cx);
24875                    move |_window, cx| {
24876                        Tooltip::for_action_in(
24877                            "Stage Hunk",
24878                            &::git::ToggleStaged,
24879                            &focus_handle,
24880                            cx,
24881                        )
24882                    }
24883                })
24884                .on_click({
24885                    let editor = editor.clone();
24886                    move |_event, _window, cx| {
24887                        editor.update(cx, |editor, cx| {
24888                            editor.stage_or_unstage_diff_hunks(
24889                                true,
24890                                vec![hunk_range.start..hunk_range.start],
24891                                cx,
24892                            );
24893                        });
24894                    }
24895                })
24896        } else {
24897            Button::new(("unstage", row as u64), "Unstage")
24898                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24899                .tooltip({
24900                    let focus_handle = editor.focus_handle(cx);
24901                    move |_window, cx| {
24902                        Tooltip::for_action_in(
24903                            "Unstage Hunk",
24904                            &::git::ToggleStaged,
24905                            &focus_handle,
24906                            cx,
24907                        )
24908                    }
24909                })
24910                .on_click({
24911                    let editor = editor.clone();
24912                    move |_event, _window, cx| {
24913                        editor.update(cx, |editor, cx| {
24914                            editor.stage_or_unstage_diff_hunks(
24915                                false,
24916                                vec![hunk_range.start..hunk_range.start],
24917                                cx,
24918                            );
24919                        });
24920                    }
24921                })
24922        })
24923        .child(
24924            Button::new(("restore", row as u64), "Restore")
24925                .tooltip({
24926                    let focus_handle = editor.focus_handle(cx);
24927                    move |_window, cx| {
24928                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
24929                    }
24930                })
24931                .on_click({
24932                    let editor = editor.clone();
24933                    move |_event, window, cx| {
24934                        editor.update(cx, |editor, cx| {
24935                            let snapshot = editor.snapshot(window, cx);
24936                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
24937                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24938                        });
24939                    }
24940                })
24941                .disabled(is_created_file),
24942        )
24943        .when(
24944            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24945            |el| {
24946                el.child(
24947                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24948                        .shape(IconButtonShape::Square)
24949                        .icon_size(IconSize::Small)
24950                        // .disabled(!has_multiple_hunks)
24951                        .tooltip({
24952                            let focus_handle = editor.focus_handle(cx);
24953                            move |_window, cx| {
24954                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
24955                            }
24956                        })
24957                        .on_click({
24958                            let editor = editor.clone();
24959                            move |_event, window, cx| {
24960                                editor.update(cx, |editor, cx| {
24961                                    let snapshot = editor.snapshot(window, cx);
24962                                    let position =
24963                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
24964                                    editor.go_to_hunk_before_or_after_position(
24965                                        &snapshot,
24966                                        position,
24967                                        Direction::Next,
24968                                        window,
24969                                        cx,
24970                                    );
24971                                    editor.expand_selected_diff_hunks(cx);
24972                                });
24973                            }
24974                        }),
24975                )
24976                .child(
24977                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24978                        .shape(IconButtonShape::Square)
24979                        .icon_size(IconSize::Small)
24980                        // .disabled(!has_multiple_hunks)
24981                        .tooltip({
24982                            let focus_handle = editor.focus_handle(cx);
24983                            move |_window, cx| {
24984                                Tooltip::for_action_in(
24985                                    "Previous Hunk",
24986                                    &GoToPreviousHunk,
24987                                    &focus_handle,
24988                                    cx,
24989                                )
24990                            }
24991                        })
24992                        .on_click({
24993                            let editor = editor.clone();
24994                            move |_event, window, cx| {
24995                                editor.update(cx, |editor, cx| {
24996                                    let snapshot = editor.snapshot(window, cx);
24997                                    let point =
24998                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
24999                                    editor.go_to_hunk_before_or_after_position(
25000                                        &snapshot,
25001                                        point,
25002                                        Direction::Prev,
25003                                        window,
25004                                        cx,
25005                                    );
25006                                    editor.expand_selected_diff_hunks(cx);
25007                                });
25008                            }
25009                        }),
25010                )
25011            },
25012        )
25013        .into_any_element()
25014}
25015
25016pub fn multibuffer_context_lines(cx: &App) -> u32 {
25017    EditorSettings::try_get(cx)
25018        .map(|settings| settings.excerpt_context_lines)
25019        .unwrap_or(2)
25020        .min(32)
25021}