editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//!
   11//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   12//!
   13//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   14pub mod actions;
   15mod blink_manager;
   16mod clangd_ext;
   17pub mod code_context_menus;
   18pub mod display_map;
   19mod editor_settings;
   20mod element;
   21mod git;
   22mod highlight_matching_bracket;
   23mod hover_links;
   24pub mod hover_popover;
   25mod indent_guides;
   26mod inlays;
   27pub mod items;
   28mod jsx_tag_auto_close;
   29mod linked_editing_ranges;
   30mod lsp_colors;
   31mod lsp_ext;
   32mod mouse_context_menu;
   33pub mod movement;
   34mod persistence;
   35mod rust_analyzer_ext;
   36pub mod scroll;
   37mod selections_collection;
   38pub mod tasks;
   39
   40#[cfg(test)]
   41mod code_completion_tests;
   42#[cfg(test)]
   43mod edit_prediction_tests;
   44#[cfg(test)]
   45mod editor_tests;
   46mod signature_help;
   47#[cfg(any(test, feature = "test-support"))]
   48pub mod test;
   49
   50pub(crate) use actions::*;
   51pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   52pub use edit_prediction::Direction;
   53pub use editor_settings::{
   54    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   55    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
   56};
   57pub use element::{
   58    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   59};
   60pub use git::blame::BlameRenderer;
   61pub use hover_popover::hover_markdown_style;
   62pub use inlays::Inlay;
   63pub use items::MAX_TAB_TITLE_LEN;
   64pub use lsp::CompletionContext;
   65pub use lsp_ext::lsp_tasks;
   66pub use multi_buffer::{
   67    Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, PathKey,
   68    RowInfo, ToOffset, ToPoint,
   69};
   70pub use text::Bias;
   71
   72use ::git::{
   73    Restore,
   74    blame::{BlameEntry, ParsedCommitMessage},
   75    status::FileStatus,
   76};
   77use aho_corasick::AhoCorasick;
   78use anyhow::{Context as _, Result, anyhow};
   79use blink_manager::BlinkManager;
   80use buffer_diff::DiffHunkStatus;
   81use client::{Collaborator, ParticipantIndex, parse_zed_link};
   82use clock::ReplicaId;
   83use code_context_menus::{
   84    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   85    CompletionsMenu, ContextMenuOrigin,
   86};
   87use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   88use convert_case::{Case, Casing};
   89use dap::TelemetrySpawnLocation;
   90use display_map::*;
   91use edit_prediction::{EditPredictionProvider, EditPredictionProviderHandle};
   92use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   93use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
   94use futures::{
   95    FutureExt, StreamExt as _,
   96    future::{self, Shared, join},
   97    stream::FuturesUnordered,
   98};
   99use fuzzy::{StringMatch, StringMatchCandidate};
  100use git::blame::{GitBlame, GlobalBlameRenderer};
  101use gpui::{
  102    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  103    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  104    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  105    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  106    MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, ScrollHandle,
  107    SharedString, Size, Stateful, Styled, Subscription, Task, TextStyle, TextStyleRefinement,
  108    UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
  109    div, point, prelude::*, pulsating_between, px, relative, size,
  110};
  111use hover_links::{HoverLink, HoveredLinkState, find_file};
  112use hover_popover::{HoverState, hide_hover};
  113use indent_guides::ActiveIndentGuidesState;
  114use inlays::{InlaySplice, inlay_hints::InlayHintRefreshReason};
  115use itertools::{Either, Itertools};
  116use language::{
  117    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  118    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  119    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  120    IndentSize, Language, OffsetRangeExt, Point, Runnable, RunnableRange, Selection, SelectionGoal,
  121    TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  122    language_settings::{
  123        self, LspInsertMode, RewrapBehavior, WordsCompletionMode, all_language_settings,
  124        language_settings,
  125    },
  126    point_from_lsp, point_to_lsp, text_diff_with_options,
  127};
  128use linked_editing_ranges::refresh_linked_ranges;
  129use lsp::{
  130    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  131    LanguageServerId,
  132};
  133use lsp_colors::LspColorData;
  134use markdown::Markdown;
  135use mouse_context_menu::MouseContextMenu;
  136use movement::TextLayoutDetails;
  137use multi_buffer::{
  138    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  139};
  140use parking_lot::Mutex;
  141use persistence::DB;
  142use project::{
  143    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  144    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, InlayId,
  145    InvalidationStrategy, Location, LocationLink, PrepareRenameResponse, Project, ProjectItem,
  146    ProjectPath, ProjectTransaction, TaskSourceKind,
  147    debugger::{
  148        breakpoint_store::{
  149            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  150            BreakpointStore, BreakpointStoreEvent,
  151        },
  152        session::{Session, SessionEvent},
  153    },
  154    git_store::GitStoreEvent,
  155    lsp_store::{
  156        CacheInlayHints, CompletionDocumentation, FormatTrigger, LspFormatTarget,
  157        OpenLspBufferHandle,
  158    },
  159    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  160};
  161use rand::seq::SliceRandom;
  162use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  163use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  164use selections_collection::{MutableSelectionsCollection, SelectionsCollection};
  165use serde::{Deserialize, Serialize};
  166use settings::{GitGutterSetting, Settings, SettingsLocation, SettingsStore, update_settings_file};
  167use smallvec::{SmallVec, smallvec};
  168use snippet::Snippet;
  169use std::{
  170    any::{Any, TypeId},
  171    borrow::Cow,
  172    cell::{OnceCell, RefCell},
  173    cmp::{self, Ordering, Reverse},
  174    iter::{self, Peekable},
  175    mem,
  176    num::NonZeroU32,
  177    ops::{Deref, DerefMut, Not, Range, RangeInclusive},
  178    path::{Path, PathBuf},
  179    rc::Rc,
  180    sync::Arc,
  181    time::{Duration, Instant},
  182};
  183use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  184use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
  185use theme::{
  186    ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  187    observe_buffer_font_size_adjustment,
  188};
  189use ui::{
  190    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  191    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  192};
  193use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  194use workspace::{
  195    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  196    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  197    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  198    item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  199    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  200    searchable::SearchEvent,
  201};
  202
  203use crate::{
  204    code_context_menus::CompletionsMenuSource,
  205    editor_settings::MultiCursorModifier,
  206    hover_links::{find_url, find_url_from_range},
  207    inlays::{
  208        InlineValueCache,
  209        inlay_hints::{LspInlayHintData, inlay_hint_settings},
  210    },
  211    scroll::{ScrollOffset, ScrollPixelOffset},
  212    selections_collection::resolve_selections_wrapping_blocks,
  213    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  214};
  215
  216pub const FILE_HEADER_HEIGHT: u32 = 2;
  217pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  218const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  219const MAX_LINE_LEN: usize = 1024;
  220const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  221const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  222pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  223#[doc(hidden)]
  224pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  225pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  226
  227pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  228pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  229pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  230pub const FETCH_COLORS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(150);
  231
  232pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  233pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  234pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  235
  236pub type RenderDiffHunkControlsFn = Arc<
  237    dyn Fn(
  238        u32,
  239        &DiffHunkStatus,
  240        Range<Anchor>,
  241        bool,
  242        Pixels,
  243        &Entity<Editor>,
  244        &mut Window,
  245        &mut App,
  246    ) -> AnyElement,
  247>;
  248
  249enum ReportEditorEvent {
  250    Saved { auto_saved: bool },
  251    EditorOpened,
  252    Closed,
  253}
  254
  255impl ReportEditorEvent {
  256    pub fn event_type(&self) -> &'static str {
  257        match self {
  258            Self::Saved { .. } => "Editor Saved",
  259            Self::EditorOpened => "Editor Opened",
  260            Self::Closed => "Editor Closed",
  261        }
  262    }
  263}
  264
  265pub enum ActiveDebugLine {}
  266pub enum DebugStackFrameLine {}
  267enum DocumentHighlightRead {}
  268enum DocumentHighlightWrite {}
  269enum InputComposition {}
  270pub enum PendingInput {}
  271enum SelectedTextHighlight {}
  272
  273pub enum ConflictsOuter {}
  274pub enum ConflictsOurs {}
  275pub enum ConflictsTheirs {}
  276pub enum ConflictsOursMarker {}
  277pub enum ConflictsTheirsMarker {}
  278
  279#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  280pub enum Navigated {
  281    Yes,
  282    No,
  283}
  284
  285impl Navigated {
  286    pub fn from_bool(yes: bool) -> Navigated {
  287        if yes { Navigated::Yes } else { Navigated::No }
  288    }
  289}
  290
  291#[derive(Debug, Clone, PartialEq, Eq)]
  292enum DisplayDiffHunk {
  293    Folded {
  294        display_row: DisplayRow,
  295    },
  296    Unfolded {
  297        is_created_file: bool,
  298        diff_base_byte_range: Range<usize>,
  299        display_row_range: Range<DisplayRow>,
  300        multi_buffer_range: Range<Anchor>,
  301        status: DiffHunkStatus,
  302    },
  303}
  304
  305pub enum HideMouseCursorOrigin {
  306    TypingAction,
  307    MovementAction,
  308}
  309
  310pub fn init_settings(cx: &mut App) {
  311    EditorSettings::register(cx);
  312}
  313
  314pub fn init(cx: &mut App) {
  315    init_settings(cx);
  316
  317    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  318
  319    workspace::register_project_item::<Editor>(cx);
  320    workspace::FollowableViewRegistry::register::<Editor>(cx);
  321    workspace::register_serializable_item::<Editor>(cx);
  322
  323    cx.observe_new(
  324        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  325            workspace.register_action(Editor::new_file);
  326            workspace.register_action(Editor::new_file_split);
  327            workspace.register_action(Editor::new_file_vertical);
  328            workspace.register_action(Editor::new_file_horizontal);
  329            workspace.register_action(Editor::cancel_language_server_work);
  330            workspace.register_action(Editor::toggle_focus);
  331        },
  332    )
  333    .detach();
  334
  335    cx.on_action(move |_: &workspace::NewFile, cx| {
  336        let app_state = workspace::AppState::global(cx);
  337        if let Some(app_state) = app_state.upgrade() {
  338            workspace::open_new(
  339                Default::default(),
  340                app_state,
  341                cx,
  342                |workspace, window, cx| {
  343                    Editor::new_file(workspace, &Default::default(), window, cx)
  344                },
  345            )
  346            .detach();
  347        }
  348    });
  349    cx.on_action(move |_: &workspace::NewWindow, cx| {
  350        let app_state = workspace::AppState::global(cx);
  351        if let Some(app_state) = app_state.upgrade() {
  352            workspace::open_new(
  353                Default::default(),
  354                app_state,
  355                cx,
  356                |workspace, window, cx| {
  357                    cx.activate(true);
  358                    Editor::new_file(workspace, &Default::default(), window, cx)
  359                },
  360            )
  361            .detach();
  362        }
  363    });
  364}
  365
  366pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  367    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  368}
  369
  370pub trait DiagnosticRenderer {
  371    fn render_group(
  372        &self,
  373        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  374        buffer_id: BufferId,
  375        snapshot: EditorSnapshot,
  376        editor: WeakEntity<Editor>,
  377        cx: &mut App,
  378    ) -> Vec<BlockProperties<Anchor>>;
  379
  380    fn render_hover(
  381        &self,
  382        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  383        range: Range<Point>,
  384        buffer_id: BufferId,
  385        cx: &mut App,
  386    ) -> Option<Entity<markdown::Markdown>>;
  387
  388    fn open_link(
  389        &self,
  390        editor: &mut Editor,
  391        link: SharedString,
  392        window: &mut Window,
  393        cx: &mut Context<Editor>,
  394    );
  395}
  396
  397pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  398
  399impl GlobalDiagnosticRenderer {
  400    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  401        cx.try_global::<Self>().map(|g| g.0.clone())
  402    }
  403}
  404
  405impl gpui::Global for GlobalDiagnosticRenderer {}
  406pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  407    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  408}
  409
  410pub struct SearchWithinRange;
  411
  412trait InvalidationRegion {
  413    fn ranges(&self) -> &[Range<Anchor>];
  414}
  415
  416#[derive(Clone, Debug, PartialEq)]
  417pub enum SelectPhase {
  418    Begin {
  419        position: DisplayPoint,
  420        add: bool,
  421        click_count: usize,
  422    },
  423    BeginColumnar {
  424        position: DisplayPoint,
  425        reset: bool,
  426        mode: ColumnarMode,
  427        goal_column: u32,
  428    },
  429    Extend {
  430        position: DisplayPoint,
  431        click_count: usize,
  432    },
  433    Update {
  434        position: DisplayPoint,
  435        goal_column: u32,
  436        scroll_delta: gpui::Point<f32>,
  437    },
  438    End,
  439}
  440
  441#[derive(Clone, Debug, PartialEq)]
  442pub enum ColumnarMode {
  443    FromMouse,
  444    FromSelection,
  445}
  446
  447#[derive(Clone, Debug)]
  448pub enum SelectMode {
  449    Character,
  450    Word(Range<Anchor>),
  451    Line(Range<Anchor>),
  452    All,
  453}
  454
  455#[derive(Copy, Clone, Default, PartialEq, Eq, Debug)]
  456pub enum SizingBehavior {
  457    /// The editor will layout itself using `size_full` and will include the vertical
  458    /// scroll margin as requested by user settings.
  459    #[default]
  460    Default,
  461    /// The editor will layout itself using `size_full`, but will not have any
  462    /// vertical overscroll.
  463    ExcludeOverscrollMargin,
  464    /// The editor will request a vertical size according to its content and will be
  465    /// layouted without a vertical scroll margin.
  466    SizeByContent,
  467}
  468
  469#[derive(Clone, PartialEq, Eq, Debug)]
  470pub enum EditorMode {
  471    SingleLine,
  472    AutoHeight {
  473        min_lines: usize,
  474        max_lines: Option<usize>,
  475    },
  476    Full {
  477        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  478        scale_ui_elements_with_buffer_font_size: bool,
  479        /// When set to `true`, the editor will render a background for the active line.
  480        show_active_line_background: bool,
  481        /// Determines the sizing behavior for this editor
  482        sizing_behavior: SizingBehavior,
  483    },
  484    Minimap {
  485        parent: WeakEntity<Editor>,
  486    },
  487}
  488
  489impl EditorMode {
  490    pub fn full() -> Self {
  491        Self::Full {
  492            scale_ui_elements_with_buffer_font_size: true,
  493            show_active_line_background: true,
  494            sizing_behavior: SizingBehavior::Default,
  495        }
  496    }
  497
  498    #[inline]
  499    pub fn is_full(&self) -> bool {
  500        matches!(self, Self::Full { .. })
  501    }
  502
  503    #[inline]
  504    pub fn is_single_line(&self) -> bool {
  505        matches!(self, Self::SingleLine { .. })
  506    }
  507
  508    #[inline]
  509    fn is_minimap(&self) -> bool {
  510        matches!(self, Self::Minimap { .. })
  511    }
  512}
  513
  514#[derive(Copy, Clone, Debug)]
  515pub enum SoftWrap {
  516    /// Prefer not to wrap at all.
  517    ///
  518    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  519    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  520    GitDiff,
  521    /// Prefer a single line generally, unless an overly long line is encountered.
  522    None,
  523    /// Soft wrap lines that exceed the editor width.
  524    EditorWidth,
  525    /// Soft wrap lines at the preferred line length.
  526    Column(u32),
  527    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  528    Bounded(u32),
  529}
  530
  531#[derive(Clone)]
  532pub struct EditorStyle {
  533    pub background: Hsla,
  534    pub border: Hsla,
  535    pub local_player: PlayerColor,
  536    pub text: TextStyle,
  537    pub scrollbar_width: Pixels,
  538    pub syntax: Arc<SyntaxTheme>,
  539    pub status: StatusColors,
  540    pub inlay_hints_style: HighlightStyle,
  541    pub edit_prediction_styles: EditPredictionStyles,
  542    pub unnecessary_code_fade: f32,
  543    pub show_underlines: bool,
  544}
  545
  546impl Default for EditorStyle {
  547    fn default() -> Self {
  548        Self {
  549            background: Hsla::default(),
  550            border: Hsla::default(),
  551            local_player: PlayerColor::default(),
  552            text: TextStyle::default(),
  553            scrollbar_width: Pixels::default(),
  554            syntax: Default::default(),
  555            // HACK: Status colors don't have a real default.
  556            // We should look into removing the status colors from the editor
  557            // style and retrieve them directly from the theme.
  558            status: StatusColors::dark(),
  559            inlay_hints_style: HighlightStyle::default(),
  560            edit_prediction_styles: EditPredictionStyles {
  561                insertion: HighlightStyle::default(),
  562                whitespace: HighlightStyle::default(),
  563            },
  564            unnecessary_code_fade: Default::default(),
  565            show_underlines: true,
  566        }
  567    }
  568}
  569
  570pub fn make_inlay_hints_style(cx: &mut App) -> HighlightStyle {
  571    let show_background = language_settings::language_settings(None, None, cx)
  572        .inlay_hints
  573        .show_background;
  574
  575    let mut style = cx.theme().syntax().get("hint");
  576
  577    if style.color.is_none() {
  578        style.color = Some(cx.theme().status().hint);
  579    }
  580
  581    if !show_background {
  582        style.background_color = None;
  583        return style;
  584    }
  585
  586    if style.background_color.is_none() {
  587        style.background_color = Some(cx.theme().status().hint_background);
  588    }
  589
  590    style
  591}
  592
  593pub fn make_suggestion_styles(cx: &mut App) -> EditPredictionStyles {
  594    EditPredictionStyles {
  595        insertion: HighlightStyle {
  596            color: Some(cx.theme().status().predictive),
  597            ..HighlightStyle::default()
  598        },
  599        whitespace: HighlightStyle {
  600            background_color: Some(cx.theme().status().created_background),
  601            ..HighlightStyle::default()
  602        },
  603    }
  604}
  605
  606type CompletionId = usize;
  607
  608pub(crate) enum EditDisplayMode {
  609    TabAccept,
  610    DiffPopover,
  611    Inline,
  612}
  613
  614enum EditPrediction {
  615    Edit {
  616        edits: Vec<(Range<Anchor>, String)>,
  617        edit_preview: Option<EditPreview>,
  618        display_mode: EditDisplayMode,
  619        snapshot: BufferSnapshot,
  620    },
  621    /// Move to a specific location in the active editor
  622    MoveWithin {
  623        target: Anchor,
  624        snapshot: BufferSnapshot,
  625    },
  626    /// Move to a specific location in a different editor (not the active one)
  627    MoveOutside {
  628        target: language::Anchor,
  629        snapshot: BufferSnapshot,
  630    },
  631}
  632
  633struct EditPredictionState {
  634    inlay_ids: Vec<InlayId>,
  635    completion: EditPrediction,
  636    completion_id: Option<SharedString>,
  637    invalidation_range: Option<Range<Anchor>>,
  638}
  639
  640enum EditPredictionSettings {
  641    Disabled,
  642    Enabled {
  643        show_in_menu: bool,
  644        preview_requires_modifier: bool,
  645    },
  646}
  647
  648enum EditPredictionHighlight {}
  649
  650#[derive(Debug, Clone)]
  651struct InlineDiagnostic {
  652    message: SharedString,
  653    group_id: usize,
  654    is_primary: bool,
  655    start: Point,
  656    severity: lsp::DiagnosticSeverity,
  657}
  658
  659pub enum MenuEditPredictionsPolicy {
  660    Never,
  661    ByProvider,
  662}
  663
  664pub enum EditPredictionPreview {
  665    /// Modifier is not pressed
  666    Inactive { released_too_fast: bool },
  667    /// Modifier pressed
  668    Active {
  669        since: Instant,
  670        previous_scroll_position: Option<ScrollAnchor>,
  671    },
  672}
  673
  674impl EditPredictionPreview {
  675    pub fn released_too_fast(&self) -> bool {
  676        match self {
  677            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  678            EditPredictionPreview::Active { .. } => false,
  679        }
  680    }
  681
  682    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  683        if let EditPredictionPreview::Active {
  684            previous_scroll_position,
  685            ..
  686        } = self
  687        {
  688            *previous_scroll_position = scroll_position;
  689        }
  690    }
  691}
  692
  693pub struct ContextMenuOptions {
  694    pub min_entries_visible: usize,
  695    pub max_entries_visible: usize,
  696    pub placement: Option<ContextMenuPlacement>,
  697}
  698
  699#[derive(Debug, Clone, PartialEq, Eq)]
  700pub enum ContextMenuPlacement {
  701    Above,
  702    Below,
  703}
  704
  705#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  706struct EditorActionId(usize);
  707
  708impl EditorActionId {
  709    pub fn post_inc(&mut self) -> Self {
  710        let answer = self.0;
  711
  712        *self = Self(answer + 1);
  713
  714        Self(answer)
  715    }
  716}
  717
  718// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  719// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  720
  721type BackgroundHighlight = (fn(&Theme) -> Hsla, Arc<[Range<Anchor>]>);
  722type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  723
  724#[derive(Default)]
  725struct ScrollbarMarkerState {
  726    scrollbar_size: Size<Pixels>,
  727    dirty: bool,
  728    markers: Arc<[PaintQuad]>,
  729    pending_refresh: Option<Task<Result<()>>>,
  730}
  731
  732impl ScrollbarMarkerState {
  733    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  734        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  735    }
  736}
  737
  738#[derive(Clone, Copy, PartialEq, Eq)]
  739pub enum MinimapVisibility {
  740    Disabled,
  741    Enabled {
  742        /// The configuration currently present in the users settings.
  743        setting_configuration: bool,
  744        /// Whether to override the currently set visibility from the users setting.
  745        toggle_override: bool,
  746    },
  747}
  748
  749impl MinimapVisibility {
  750    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  751        if mode.is_full() {
  752            Self::Enabled {
  753                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  754                toggle_override: false,
  755            }
  756        } else {
  757            Self::Disabled
  758        }
  759    }
  760
  761    fn hidden(&self) -> Self {
  762        match *self {
  763            Self::Enabled {
  764                setting_configuration,
  765                ..
  766            } => Self::Enabled {
  767                setting_configuration,
  768                toggle_override: setting_configuration,
  769            },
  770            Self::Disabled => Self::Disabled,
  771        }
  772    }
  773
  774    fn disabled(&self) -> bool {
  775        matches!(*self, Self::Disabled)
  776    }
  777
  778    fn settings_visibility(&self) -> bool {
  779        match *self {
  780            Self::Enabled {
  781                setting_configuration,
  782                ..
  783            } => setting_configuration,
  784            _ => false,
  785        }
  786    }
  787
  788    fn visible(&self) -> bool {
  789        match *self {
  790            Self::Enabled {
  791                setting_configuration,
  792                toggle_override,
  793            } => setting_configuration ^ toggle_override,
  794            _ => false,
  795        }
  796    }
  797
  798    fn toggle_visibility(&self) -> Self {
  799        match *self {
  800            Self::Enabled {
  801                toggle_override,
  802                setting_configuration,
  803            } => Self::Enabled {
  804                setting_configuration,
  805                toggle_override: !toggle_override,
  806            },
  807            Self::Disabled => Self::Disabled,
  808        }
  809    }
  810}
  811
  812#[derive(Clone, Debug)]
  813struct RunnableTasks {
  814    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  815    offset: multi_buffer::Anchor,
  816    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  817    column: u32,
  818    // Values of all named captures, including those starting with '_'
  819    extra_variables: HashMap<String, String>,
  820    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  821    context_range: Range<BufferOffset>,
  822}
  823
  824impl RunnableTasks {
  825    fn resolve<'a>(
  826        &'a self,
  827        cx: &'a task::TaskContext,
  828    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  829        self.templates.iter().filter_map(|(kind, template)| {
  830            template
  831                .resolve_task(&kind.to_id_base(), cx)
  832                .map(|task| (kind.clone(), task))
  833        })
  834    }
  835}
  836
  837#[derive(Clone)]
  838pub struct ResolvedTasks {
  839    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  840    position: Anchor,
  841}
  842
  843#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
  844struct BufferOffset(usize);
  845
  846/// Addons allow storing per-editor state in other crates (e.g. Vim)
  847pub trait Addon: 'static {
  848    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  849
  850    fn render_buffer_header_controls(
  851        &self,
  852        _: &ExcerptInfo,
  853        _: &Window,
  854        _: &App,
  855    ) -> Option<AnyElement> {
  856        None
  857    }
  858
  859    fn override_status_for_buffer_id(&self, _: BufferId, _: &App) -> Option<FileStatus> {
  860        None
  861    }
  862
  863    fn to_any(&self) -> &dyn std::any::Any;
  864
  865    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  866        None
  867    }
  868}
  869
  870struct ChangeLocation {
  871    current: Option<Vec<Anchor>>,
  872    original: Vec<Anchor>,
  873}
  874impl ChangeLocation {
  875    fn locations(&self) -> &[Anchor] {
  876        self.current.as_ref().unwrap_or(&self.original)
  877    }
  878}
  879
  880/// A set of caret positions, registered when the editor was edited.
  881pub struct ChangeList {
  882    changes: Vec<ChangeLocation>,
  883    /// Currently "selected" change.
  884    position: Option<usize>,
  885}
  886
  887impl ChangeList {
  888    pub fn new() -> Self {
  889        Self {
  890            changes: Vec::new(),
  891            position: None,
  892        }
  893    }
  894
  895    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  896    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  897    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  898        if self.changes.is_empty() {
  899            return None;
  900        }
  901
  902        let prev = self.position.unwrap_or(self.changes.len());
  903        let next = if direction == Direction::Prev {
  904            prev.saturating_sub(count)
  905        } else {
  906            (prev + count).min(self.changes.len() - 1)
  907        };
  908        self.position = Some(next);
  909        self.changes.get(next).map(|change| change.locations())
  910    }
  911
  912    /// Adds a new change to the list, resetting the change list position.
  913    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  914        self.position.take();
  915        if let Some(last) = self.changes.last_mut()
  916            && group
  917        {
  918            last.current = Some(new_positions)
  919        } else {
  920            self.changes.push(ChangeLocation {
  921                original: new_positions,
  922                current: None,
  923            });
  924        }
  925    }
  926
  927    pub fn last(&self) -> Option<&[Anchor]> {
  928        self.changes.last().map(|change| change.locations())
  929    }
  930
  931    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  932        self.changes.last().map(|change| change.original.as_slice())
  933    }
  934
  935    pub fn invert_last_group(&mut self) {
  936        if let Some(last) = self.changes.last_mut()
  937            && let Some(current) = last.current.as_mut()
  938        {
  939            mem::swap(&mut last.original, current);
  940        }
  941    }
  942}
  943
  944#[derive(Clone)]
  945struct InlineBlamePopoverState {
  946    scroll_handle: ScrollHandle,
  947    commit_message: Option<ParsedCommitMessage>,
  948    markdown: Entity<Markdown>,
  949}
  950
  951struct InlineBlamePopover {
  952    position: gpui::Point<Pixels>,
  953    hide_task: Option<Task<()>>,
  954    popover_bounds: Option<Bounds<Pixels>>,
  955    popover_state: InlineBlamePopoverState,
  956    keyboard_grace: bool,
  957}
  958
  959enum SelectionDragState {
  960    /// State when no drag related activity is detected.
  961    None,
  962    /// State when the mouse is down on a selection that is about to be dragged.
  963    ReadyToDrag {
  964        selection: Selection<Anchor>,
  965        click_position: gpui::Point<Pixels>,
  966        mouse_down_time: Instant,
  967    },
  968    /// State when the mouse is dragging the selection in the editor.
  969    Dragging {
  970        selection: Selection<Anchor>,
  971        drop_cursor: Selection<Anchor>,
  972        hide_drop_cursor: bool,
  973    },
  974}
  975
  976enum ColumnarSelectionState {
  977    FromMouse {
  978        selection_tail: Anchor,
  979        display_point: Option<DisplayPoint>,
  980    },
  981    FromSelection {
  982        selection_tail: Anchor,
  983    },
  984}
  985
  986/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
  987/// a breakpoint on them.
  988#[derive(Clone, Copy, Debug, PartialEq, Eq)]
  989struct PhantomBreakpointIndicator {
  990    display_row: DisplayRow,
  991    /// There's a small debounce between hovering over the line and showing the indicator.
  992    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
  993    is_active: bool,
  994    collides_with_existing_breakpoint: bool,
  995}
  996
  997/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
  998///
  999/// See the [module level documentation](self) for more information.
 1000pub struct Editor {
 1001    focus_handle: FocusHandle,
 1002    last_focused_descendant: Option<WeakFocusHandle>,
 1003    /// The text buffer being edited
 1004    buffer: Entity<MultiBuffer>,
 1005    /// Map of how text in the buffer should be displayed.
 1006    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1007    pub display_map: Entity<DisplayMap>,
 1008    placeholder_display_map: Option<Entity<DisplayMap>>,
 1009    pub selections: SelectionsCollection,
 1010    pub scroll_manager: ScrollManager,
 1011    /// When inline assist editors are linked, they all render cursors because
 1012    /// typing enters text into each of them, even the ones that aren't focused.
 1013    pub(crate) show_cursor_when_unfocused: bool,
 1014    columnar_selection_state: Option<ColumnarSelectionState>,
 1015    add_selections_state: Option<AddSelectionsState>,
 1016    select_next_state: Option<SelectNextState>,
 1017    select_prev_state: Option<SelectNextState>,
 1018    selection_history: SelectionHistory,
 1019    defer_selection_effects: bool,
 1020    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1021    autoclose_regions: Vec<AutocloseRegion>,
 1022    snippet_stack: InvalidationStack<SnippetState>,
 1023    select_syntax_node_history: SelectSyntaxNodeHistory,
 1024    ime_transaction: Option<TransactionId>,
 1025    pub diagnostics_max_severity: DiagnosticSeverity,
 1026    active_diagnostics: ActiveDiagnostic,
 1027    show_inline_diagnostics: bool,
 1028    inline_diagnostics_update: Task<()>,
 1029    inline_diagnostics_enabled: bool,
 1030    diagnostics_enabled: bool,
 1031    word_completions_enabled: bool,
 1032    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1033    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1034    hard_wrap: Option<usize>,
 1035    project: Option<Entity<Project>>,
 1036    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1037    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1038    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1039    blink_manager: Entity<BlinkManager>,
 1040    show_cursor_names: bool,
 1041    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1042    pub show_local_selections: bool,
 1043    mode: EditorMode,
 1044    show_breadcrumbs: bool,
 1045    show_gutter: bool,
 1046    show_scrollbars: ScrollbarAxes,
 1047    minimap_visibility: MinimapVisibility,
 1048    offset_content: bool,
 1049    disable_expand_excerpt_buttons: bool,
 1050    show_line_numbers: Option<bool>,
 1051    use_relative_line_numbers: Option<bool>,
 1052    show_git_diff_gutter: Option<bool>,
 1053    show_code_actions: Option<bool>,
 1054    show_runnables: Option<bool>,
 1055    show_breakpoints: Option<bool>,
 1056    show_wrap_guides: Option<bool>,
 1057    show_indent_guides: Option<bool>,
 1058    highlight_order: usize,
 1059    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1060    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1061    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1062    scrollbar_marker_state: ScrollbarMarkerState,
 1063    active_indent_guides_state: ActiveIndentGuidesState,
 1064    nav_history: Option<ItemNavHistory>,
 1065    context_menu: RefCell<Option<CodeContextMenu>>,
 1066    context_menu_options: Option<ContextMenuOptions>,
 1067    mouse_context_menu: Option<MouseContextMenu>,
 1068    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1069    inline_blame_popover: Option<InlineBlamePopover>,
 1070    inline_blame_popover_show_task: Option<Task<()>>,
 1071    signature_help_state: SignatureHelpState,
 1072    auto_signature_help: Option<bool>,
 1073    find_all_references_task_sources: Vec<Anchor>,
 1074    next_completion_id: CompletionId,
 1075    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1076    code_actions_task: Option<Task<Result<()>>>,
 1077    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1078    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1079    document_highlights_task: Option<Task<()>>,
 1080    linked_editing_range_task: Option<Task<Option<()>>>,
 1081    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1082    pending_rename: Option<RenameState>,
 1083    searchable: bool,
 1084    cursor_shape: CursorShape,
 1085    current_line_highlight: Option<CurrentLineHighlight>,
 1086    autoindent_mode: Option<AutoindentMode>,
 1087    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1088    input_enabled: bool,
 1089    use_modal_editing: bool,
 1090    read_only: bool,
 1091    leader_id: Option<CollaboratorId>,
 1092    remote_id: Option<ViewId>,
 1093    pub hover_state: HoverState,
 1094    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1095    gutter_hovered: bool,
 1096    hovered_link_state: Option<HoveredLinkState>,
 1097    edit_prediction_provider: Option<RegisteredEditPredictionProvider>,
 1098    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1099    active_edit_prediction: Option<EditPredictionState>,
 1100    /// Used to prevent flickering as the user types while the menu is open
 1101    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1102    edit_prediction_settings: EditPredictionSettings,
 1103    edit_predictions_hidden_for_vim_mode: bool,
 1104    show_edit_predictions_override: Option<bool>,
 1105    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1106    edit_prediction_preview: EditPredictionPreview,
 1107    edit_prediction_indent_conflict: bool,
 1108    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1109    next_inlay_id: usize,
 1110    next_color_inlay_id: usize,
 1111    _subscriptions: Vec<Subscription>,
 1112    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1113    gutter_dimensions: GutterDimensions,
 1114    style: Option<EditorStyle>,
 1115    text_style_refinement: Option<TextStyleRefinement>,
 1116    next_editor_action_id: EditorActionId,
 1117    editor_actions: Rc<
 1118        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1119    >,
 1120    use_autoclose: bool,
 1121    use_auto_surround: bool,
 1122    auto_replace_emoji_shortcode: bool,
 1123    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1124    show_git_blame_gutter: bool,
 1125    show_git_blame_inline: bool,
 1126    show_git_blame_inline_delay_task: Option<Task<()>>,
 1127    git_blame_inline_enabled: bool,
 1128    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1129    serialize_dirty_buffers: bool,
 1130    show_selection_menu: Option<bool>,
 1131    blame: Option<Entity<GitBlame>>,
 1132    blame_subscription: Option<Subscription>,
 1133    custom_context_menu: Option<
 1134        Box<
 1135            dyn 'static
 1136                + Fn(
 1137                    &mut Self,
 1138                    DisplayPoint,
 1139                    &mut Window,
 1140                    &mut Context<Self>,
 1141                ) -> Option<Entity<ui::ContextMenu>>,
 1142        >,
 1143    >,
 1144    last_bounds: Option<Bounds<Pixels>>,
 1145    last_position_map: Option<Rc<PositionMap>>,
 1146    expect_bounds_change: Option<Bounds<Pixels>>,
 1147    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1148    tasks_update_task: Option<Task<()>>,
 1149    breakpoint_store: Option<Entity<BreakpointStore>>,
 1150    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1151    hovered_diff_hunk_row: Option<DisplayRow>,
 1152    pull_diagnostics_task: Task<()>,
 1153    in_project_search: bool,
 1154    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1155    breadcrumb_header: Option<String>,
 1156    focused_block: Option<FocusedBlock>,
 1157    next_scroll_position: NextScrollCursorCenterTopBottom,
 1158    addons: HashMap<TypeId, Box<dyn Addon>>,
 1159    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1160    load_diff_task: Option<Shared<Task<()>>>,
 1161    /// Whether we are temporarily displaying a diff other than git's
 1162    temporary_diff_override: bool,
 1163    selection_mark_mode: bool,
 1164    toggle_fold_multiple_buffers: Task<()>,
 1165    _scroll_cursor_center_top_bottom_task: Task<()>,
 1166    serialize_selections: Task<()>,
 1167    serialize_folds: Task<()>,
 1168    mouse_cursor_hidden: bool,
 1169    minimap: Option<Entity<Self>>,
 1170    hide_mouse_mode: HideMouseMode,
 1171    pub change_list: ChangeList,
 1172    inline_value_cache: InlineValueCache,
 1173    selection_drag_state: SelectionDragState,
 1174    colors: Option<LspColorData>,
 1175    post_scroll_update: Task<()>,
 1176    refresh_colors_task: Task<()>,
 1177    inlay_hints: Option<LspInlayHintData>,
 1178    folding_newlines: Task<()>,
 1179    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1180}
 1181
 1182fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1183    if debounce_ms > 0 {
 1184        Some(Duration::from_millis(debounce_ms))
 1185    } else {
 1186        None
 1187    }
 1188}
 1189
 1190#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1191enum NextScrollCursorCenterTopBottom {
 1192    #[default]
 1193    Center,
 1194    Top,
 1195    Bottom,
 1196}
 1197
 1198impl NextScrollCursorCenterTopBottom {
 1199    fn next(&self) -> Self {
 1200        match self {
 1201            Self::Center => Self::Top,
 1202            Self::Top => Self::Bottom,
 1203            Self::Bottom => Self::Center,
 1204        }
 1205    }
 1206}
 1207
 1208#[derive(Clone)]
 1209pub struct EditorSnapshot {
 1210    pub mode: EditorMode,
 1211    show_gutter: bool,
 1212    show_line_numbers: Option<bool>,
 1213    show_git_diff_gutter: Option<bool>,
 1214    show_code_actions: Option<bool>,
 1215    show_runnables: Option<bool>,
 1216    show_breakpoints: Option<bool>,
 1217    git_blame_gutter_max_author_length: Option<usize>,
 1218    pub display_snapshot: DisplaySnapshot,
 1219    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1220    is_focused: bool,
 1221    scroll_anchor: ScrollAnchor,
 1222    ongoing_scroll: OngoingScroll,
 1223    current_line_highlight: CurrentLineHighlight,
 1224    gutter_hovered: bool,
 1225}
 1226
 1227#[derive(Default, Debug, Clone, Copy)]
 1228pub struct GutterDimensions {
 1229    pub left_padding: Pixels,
 1230    pub right_padding: Pixels,
 1231    pub width: Pixels,
 1232    pub margin: Pixels,
 1233    pub git_blame_entries_width: Option<Pixels>,
 1234}
 1235
 1236impl GutterDimensions {
 1237    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1238        Self {
 1239            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1240            ..Default::default()
 1241        }
 1242    }
 1243
 1244    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1245        -cx.text_system().descent(font_id, font_size)
 1246    }
 1247    /// The full width of the space taken up by the gutter.
 1248    pub fn full_width(&self) -> Pixels {
 1249        self.margin + self.width
 1250    }
 1251
 1252    /// The width of the space reserved for the fold indicators,
 1253    /// use alongside 'justify_end' and `gutter_width` to
 1254    /// right align content with the line numbers
 1255    pub fn fold_area_width(&self) -> Pixels {
 1256        self.margin + self.right_padding
 1257    }
 1258}
 1259
 1260struct CharacterDimensions {
 1261    em_width: Pixels,
 1262    em_advance: Pixels,
 1263    line_height: Pixels,
 1264}
 1265
 1266#[derive(Debug)]
 1267pub struct RemoteSelection {
 1268    pub replica_id: ReplicaId,
 1269    pub selection: Selection<Anchor>,
 1270    pub cursor_shape: CursorShape,
 1271    pub collaborator_id: CollaboratorId,
 1272    pub line_mode: bool,
 1273    pub user_name: Option<SharedString>,
 1274    pub color: PlayerColor,
 1275}
 1276
 1277#[derive(Clone, Debug)]
 1278struct SelectionHistoryEntry {
 1279    selections: Arc<[Selection<Anchor>]>,
 1280    select_next_state: Option<SelectNextState>,
 1281    select_prev_state: Option<SelectNextState>,
 1282    add_selections_state: Option<AddSelectionsState>,
 1283}
 1284
 1285#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 1286enum SelectionHistoryMode {
 1287    Normal,
 1288    Undoing,
 1289    Redoing,
 1290    Skipping,
 1291}
 1292
 1293#[derive(Clone, PartialEq, Eq, Hash)]
 1294struct HoveredCursor {
 1295    replica_id: ReplicaId,
 1296    selection_id: usize,
 1297}
 1298
 1299impl Default for SelectionHistoryMode {
 1300    fn default() -> Self {
 1301        Self::Normal
 1302    }
 1303}
 1304
 1305#[derive(Debug)]
 1306/// SelectionEffects controls the side-effects of updating the selection.
 1307///
 1308/// The default behaviour does "what you mostly want":
 1309/// - it pushes to the nav history if the cursor moved by >10 lines
 1310/// - it re-triggers completion requests
 1311/// - it scrolls to fit
 1312///
 1313/// You might want to modify these behaviours. For example when doing a "jump"
 1314/// like go to definition, we always want to add to nav history; but when scrolling
 1315/// in vim mode we never do.
 1316///
 1317/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1318/// move.
 1319#[derive(Clone)]
 1320pub struct SelectionEffects {
 1321    nav_history: Option<bool>,
 1322    completions: bool,
 1323    scroll: Option<Autoscroll>,
 1324}
 1325
 1326impl Default for SelectionEffects {
 1327    fn default() -> Self {
 1328        Self {
 1329            nav_history: None,
 1330            completions: true,
 1331            scroll: Some(Autoscroll::fit()),
 1332        }
 1333    }
 1334}
 1335impl SelectionEffects {
 1336    pub fn scroll(scroll: Autoscroll) -> Self {
 1337        Self {
 1338            scroll: Some(scroll),
 1339            ..Default::default()
 1340        }
 1341    }
 1342
 1343    pub fn no_scroll() -> Self {
 1344        Self {
 1345            scroll: None,
 1346            ..Default::default()
 1347        }
 1348    }
 1349
 1350    pub fn completions(self, completions: bool) -> Self {
 1351        Self {
 1352            completions,
 1353            ..self
 1354        }
 1355    }
 1356
 1357    pub fn nav_history(self, nav_history: bool) -> Self {
 1358        Self {
 1359            nav_history: Some(nav_history),
 1360            ..self
 1361        }
 1362    }
 1363}
 1364
 1365struct DeferredSelectionEffectsState {
 1366    changed: bool,
 1367    effects: SelectionEffects,
 1368    old_cursor_position: Anchor,
 1369    history_entry: SelectionHistoryEntry,
 1370}
 1371
 1372#[derive(Default)]
 1373struct SelectionHistory {
 1374    #[allow(clippy::type_complexity)]
 1375    selections_by_transaction:
 1376        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1377    mode: SelectionHistoryMode,
 1378    undo_stack: VecDeque<SelectionHistoryEntry>,
 1379    redo_stack: VecDeque<SelectionHistoryEntry>,
 1380}
 1381
 1382impl SelectionHistory {
 1383    #[track_caller]
 1384    fn insert_transaction(
 1385        &mut self,
 1386        transaction_id: TransactionId,
 1387        selections: Arc<[Selection<Anchor>]>,
 1388    ) {
 1389        if selections.is_empty() {
 1390            log::error!(
 1391                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1392                std::panic::Location::caller()
 1393            );
 1394            return;
 1395        }
 1396        self.selections_by_transaction
 1397            .insert(transaction_id, (selections, None));
 1398    }
 1399
 1400    #[allow(clippy::type_complexity)]
 1401    fn transaction(
 1402        &self,
 1403        transaction_id: TransactionId,
 1404    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1405        self.selections_by_transaction.get(&transaction_id)
 1406    }
 1407
 1408    #[allow(clippy::type_complexity)]
 1409    fn transaction_mut(
 1410        &mut self,
 1411        transaction_id: TransactionId,
 1412    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1413        self.selections_by_transaction.get_mut(&transaction_id)
 1414    }
 1415
 1416    fn push(&mut self, entry: SelectionHistoryEntry) {
 1417        if !entry.selections.is_empty() {
 1418            match self.mode {
 1419                SelectionHistoryMode::Normal => {
 1420                    self.push_undo(entry);
 1421                    self.redo_stack.clear();
 1422                }
 1423                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1424                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1425                SelectionHistoryMode::Skipping => {}
 1426            }
 1427        }
 1428    }
 1429
 1430    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1431        if self
 1432            .undo_stack
 1433            .back()
 1434            .is_none_or(|e| e.selections != entry.selections)
 1435        {
 1436            self.undo_stack.push_back(entry);
 1437            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1438                self.undo_stack.pop_front();
 1439            }
 1440        }
 1441    }
 1442
 1443    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1444        if self
 1445            .redo_stack
 1446            .back()
 1447            .is_none_or(|e| e.selections != entry.selections)
 1448        {
 1449            self.redo_stack.push_back(entry);
 1450            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1451                self.redo_stack.pop_front();
 1452            }
 1453        }
 1454    }
 1455}
 1456
 1457#[derive(Clone, Copy)]
 1458pub struct RowHighlightOptions {
 1459    pub autoscroll: bool,
 1460    pub include_gutter: bool,
 1461}
 1462
 1463impl Default for RowHighlightOptions {
 1464    fn default() -> Self {
 1465        Self {
 1466            autoscroll: Default::default(),
 1467            include_gutter: true,
 1468        }
 1469    }
 1470}
 1471
 1472struct RowHighlight {
 1473    index: usize,
 1474    range: Range<Anchor>,
 1475    color: Hsla,
 1476    options: RowHighlightOptions,
 1477    type_id: TypeId,
 1478}
 1479
 1480#[derive(Clone, Debug)]
 1481struct AddSelectionsState {
 1482    groups: Vec<AddSelectionsGroup>,
 1483}
 1484
 1485#[derive(Clone, Debug)]
 1486struct AddSelectionsGroup {
 1487    above: bool,
 1488    stack: Vec<usize>,
 1489}
 1490
 1491#[derive(Clone)]
 1492struct SelectNextState {
 1493    query: AhoCorasick,
 1494    wordwise: bool,
 1495    done: bool,
 1496}
 1497
 1498impl std::fmt::Debug for SelectNextState {
 1499    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1500        f.debug_struct(std::any::type_name::<Self>())
 1501            .field("wordwise", &self.wordwise)
 1502            .field("done", &self.done)
 1503            .finish()
 1504    }
 1505}
 1506
 1507#[derive(Debug)]
 1508struct AutocloseRegion {
 1509    selection_id: usize,
 1510    range: Range<Anchor>,
 1511    pair: BracketPair,
 1512}
 1513
 1514#[derive(Debug)]
 1515struct SnippetState {
 1516    ranges: Vec<Vec<Range<Anchor>>>,
 1517    active_index: usize,
 1518    choices: Vec<Option<Vec<String>>>,
 1519}
 1520
 1521#[doc(hidden)]
 1522pub struct RenameState {
 1523    pub range: Range<Anchor>,
 1524    pub old_name: Arc<str>,
 1525    pub editor: Entity<Editor>,
 1526    block_id: CustomBlockId,
 1527}
 1528
 1529struct InvalidationStack<T>(Vec<T>);
 1530
 1531struct RegisteredEditPredictionProvider {
 1532    provider: Arc<dyn EditPredictionProviderHandle>,
 1533    _subscription: Subscription,
 1534}
 1535
 1536#[derive(Debug, PartialEq, Eq)]
 1537pub struct ActiveDiagnosticGroup {
 1538    pub active_range: Range<Anchor>,
 1539    pub active_message: String,
 1540    pub group_id: usize,
 1541    pub blocks: HashSet<CustomBlockId>,
 1542}
 1543
 1544#[derive(Debug, PartialEq, Eq)]
 1545
 1546pub(crate) enum ActiveDiagnostic {
 1547    None,
 1548    All,
 1549    Group(ActiveDiagnosticGroup),
 1550}
 1551
 1552#[derive(Serialize, Deserialize, Clone, Debug)]
 1553pub struct ClipboardSelection {
 1554    /// The number of bytes in this selection.
 1555    pub len: usize,
 1556    /// Whether this was a full-line selection.
 1557    pub is_entire_line: bool,
 1558    /// The indentation of the first line when this content was originally copied.
 1559    pub first_line_indent: u32,
 1560}
 1561
 1562// selections, scroll behavior, was newest selection reversed
 1563type SelectSyntaxNodeHistoryState = (
 1564    Box<[Selection<usize>]>,
 1565    SelectSyntaxNodeScrollBehavior,
 1566    bool,
 1567);
 1568
 1569#[derive(Default)]
 1570struct SelectSyntaxNodeHistory {
 1571    stack: Vec<SelectSyntaxNodeHistoryState>,
 1572    // disable temporarily to allow changing selections without losing the stack
 1573    pub disable_clearing: bool,
 1574}
 1575
 1576impl SelectSyntaxNodeHistory {
 1577    pub fn try_clear(&mut self) {
 1578        if !self.disable_clearing {
 1579            self.stack.clear();
 1580        }
 1581    }
 1582
 1583    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1584        self.stack.push(selection);
 1585    }
 1586
 1587    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1588        self.stack.pop()
 1589    }
 1590}
 1591
 1592enum SelectSyntaxNodeScrollBehavior {
 1593    CursorTop,
 1594    FitSelection,
 1595    CursorBottom,
 1596}
 1597
 1598#[derive(Debug)]
 1599pub(crate) struct NavigationData {
 1600    cursor_anchor: Anchor,
 1601    cursor_position: Point,
 1602    scroll_anchor: ScrollAnchor,
 1603    scroll_top_row: u32,
 1604}
 1605
 1606#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1607pub enum GotoDefinitionKind {
 1608    Symbol,
 1609    Declaration,
 1610    Type,
 1611    Implementation,
 1612}
 1613
 1614pub enum FormatTarget {
 1615    Buffers(HashSet<Entity<Buffer>>),
 1616    Ranges(Vec<Range<MultiBufferPoint>>),
 1617}
 1618
 1619pub(crate) struct FocusedBlock {
 1620    id: BlockId,
 1621    focus_handle: WeakFocusHandle,
 1622}
 1623
 1624#[derive(Clone)]
 1625enum JumpData {
 1626    MultiBufferRow {
 1627        row: MultiBufferRow,
 1628        line_offset_from_top: u32,
 1629    },
 1630    MultiBufferPoint {
 1631        excerpt_id: ExcerptId,
 1632        position: Point,
 1633        anchor: text::Anchor,
 1634        line_offset_from_top: u32,
 1635    },
 1636}
 1637
 1638pub enum MultibufferSelectionMode {
 1639    First,
 1640    All,
 1641}
 1642
 1643#[derive(Clone, Copy, Debug, Default)]
 1644pub struct RewrapOptions {
 1645    pub override_language_settings: bool,
 1646    pub preserve_existing_whitespace: bool,
 1647}
 1648
 1649impl Editor {
 1650    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1651        let buffer = cx.new(|cx| Buffer::local("", cx));
 1652        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1653        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1654    }
 1655
 1656    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1657        let buffer = cx.new(|cx| Buffer::local("", cx));
 1658        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1659        Self::new(EditorMode::full(), buffer, None, window, cx)
 1660    }
 1661
 1662    pub fn auto_height(
 1663        min_lines: usize,
 1664        max_lines: usize,
 1665        window: &mut Window,
 1666        cx: &mut Context<Self>,
 1667    ) -> Self {
 1668        let buffer = cx.new(|cx| Buffer::local("", cx));
 1669        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1670        Self::new(
 1671            EditorMode::AutoHeight {
 1672                min_lines,
 1673                max_lines: Some(max_lines),
 1674            },
 1675            buffer,
 1676            None,
 1677            window,
 1678            cx,
 1679        )
 1680    }
 1681
 1682    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1683    /// The editor grows as tall as needed to fit its content.
 1684    pub fn auto_height_unbounded(
 1685        min_lines: usize,
 1686        window: &mut Window,
 1687        cx: &mut Context<Self>,
 1688    ) -> Self {
 1689        let buffer = cx.new(|cx| Buffer::local("", cx));
 1690        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1691        Self::new(
 1692            EditorMode::AutoHeight {
 1693                min_lines,
 1694                max_lines: None,
 1695            },
 1696            buffer,
 1697            None,
 1698            window,
 1699            cx,
 1700        )
 1701    }
 1702
 1703    pub fn for_buffer(
 1704        buffer: Entity<Buffer>,
 1705        project: Option<Entity<Project>>,
 1706        window: &mut Window,
 1707        cx: &mut Context<Self>,
 1708    ) -> Self {
 1709        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1710        Self::new(EditorMode::full(), buffer, project, window, cx)
 1711    }
 1712
 1713    pub fn for_multibuffer(
 1714        buffer: Entity<MultiBuffer>,
 1715        project: Option<Entity<Project>>,
 1716        window: &mut Window,
 1717        cx: &mut Context<Self>,
 1718    ) -> Self {
 1719        Self::new(EditorMode::full(), buffer, project, window, cx)
 1720    }
 1721
 1722    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1723        let mut clone = Self::new(
 1724            self.mode.clone(),
 1725            self.buffer.clone(),
 1726            self.project.clone(),
 1727            window,
 1728            cx,
 1729        );
 1730        self.display_map.update(cx, |display_map, cx| {
 1731            let snapshot = display_map.snapshot(cx);
 1732            clone.display_map.update(cx, |display_map, cx| {
 1733                display_map.set_state(&snapshot, cx);
 1734            });
 1735        });
 1736        clone.folds_did_change(cx);
 1737        clone.selections.clone_state(&self.selections);
 1738        clone.scroll_manager.clone_state(&self.scroll_manager);
 1739        clone.searchable = self.searchable;
 1740        clone.read_only = self.read_only;
 1741        clone
 1742    }
 1743
 1744    pub fn new(
 1745        mode: EditorMode,
 1746        buffer: Entity<MultiBuffer>,
 1747        project: Option<Entity<Project>>,
 1748        window: &mut Window,
 1749        cx: &mut Context<Self>,
 1750    ) -> Self {
 1751        Editor::new_internal(mode, buffer, project, None, window, cx)
 1752    }
 1753
 1754    fn new_internal(
 1755        mode: EditorMode,
 1756        multi_buffer: Entity<MultiBuffer>,
 1757        project: Option<Entity<Project>>,
 1758        display_map: Option<Entity<DisplayMap>>,
 1759        window: &mut Window,
 1760        cx: &mut Context<Self>,
 1761    ) -> Self {
 1762        debug_assert!(
 1763            display_map.is_none() || mode.is_minimap(),
 1764            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1765        );
 1766
 1767        let full_mode = mode.is_full();
 1768        let is_minimap = mode.is_minimap();
 1769        let diagnostics_max_severity = if full_mode {
 1770            EditorSettings::get_global(cx)
 1771                .diagnostics_max_severity
 1772                .unwrap_or(DiagnosticSeverity::Hint)
 1773        } else {
 1774            DiagnosticSeverity::Off
 1775        };
 1776        let style = window.text_style();
 1777        let font_size = style.font_size.to_pixels(window.rem_size());
 1778        let editor = cx.entity().downgrade();
 1779        let fold_placeholder = FoldPlaceholder {
 1780            constrain_width: false,
 1781            render: Arc::new(move |fold_id, fold_range, cx| {
 1782                let editor = editor.clone();
 1783                div()
 1784                    .id(fold_id)
 1785                    .bg(cx.theme().colors().ghost_element_background)
 1786                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1787                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1788                    .rounded_xs()
 1789                    .size_full()
 1790                    .cursor_pointer()
 1791                    .child("")
 1792                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1793                    .on_click(move |_, _window, cx| {
 1794                        editor
 1795                            .update(cx, |editor, cx| {
 1796                                editor.unfold_ranges(
 1797                                    &[fold_range.start..fold_range.end],
 1798                                    true,
 1799                                    false,
 1800                                    cx,
 1801                                );
 1802                                cx.stop_propagation();
 1803                            })
 1804                            .ok();
 1805                    })
 1806                    .into_any()
 1807            }),
 1808            merge_adjacent: true,
 1809            ..FoldPlaceholder::default()
 1810        };
 1811        let display_map = display_map.unwrap_or_else(|| {
 1812            cx.new(|cx| {
 1813                DisplayMap::new(
 1814                    multi_buffer.clone(),
 1815                    style.font(),
 1816                    font_size,
 1817                    None,
 1818                    FILE_HEADER_HEIGHT,
 1819                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1820                    fold_placeholder,
 1821                    diagnostics_max_severity,
 1822                    cx,
 1823                )
 1824            })
 1825        });
 1826
 1827        let selections = SelectionsCollection::new(display_map.clone(), multi_buffer.clone());
 1828
 1829        let blink_manager = cx.new(|cx| {
 1830            let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
 1831            if is_minimap {
 1832                blink_manager.disable(cx);
 1833            }
 1834            blink_manager
 1835        });
 1836
 1837        let soft_wrap_mode_override =
 1838            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1839
 1840        let mut project_subscriptions = Vec::new();
 1841        if full_mode && let Some(project) = project.as_ref() {
 1842            project_subscriptions.push(cx.subscribe_in(
 1843                project,
 1844                window,
 1845                |editor, _, event, window, cx| match event {
 1846                    project::Event::RefreshCodeLens => {
 1847                        // we always query lens with actions, without storing them, always refreshing them
 1848                    }
 1849                    project::Event::RefreshInlayHints {
 1850                        server_id,
 1851                        request_id,
 1852                    } => {
 1853                        editor.refresh_inlay_hints(
 1854                            InlayHintRefreshReason::RefreshRequested {
 1855                                server_id: *server_id,
 1856                                request_id: *request_id,
 1857                            },
 1858                            cx,
 1859                        );
 1860                    }
 1861                    project::Event::LanguageServerRemoved(..) => {
 1862                        if editor.tasks_update_task.is_none() {
 1863                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1864                        }
 1865                        editor.registered_buffers.clear();
 1866                        editor.register_visible_buffers(cx);
 1867                    }
 1868                    project::Event::LanguageServerAdded(..) => {
 1869                        if editor.tasks_update_task.is_none() {
 1870                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1871                        }
 1872                    }
 1873                    project::Event::SnippetEdit(id, snippet_edits) => {
 1874                        if let Some(buffer) = editor.buffer.read(cx).buffer(*id) {
 1875                            let focus_handle = editor.focus_handle(cx);
 1876                            if focus_handle.is_focused(window) {
 1877                                let snapshot = buffer.read(cx).snapshot();
 1878                                for (range, snippet) in snippet_edits {
 1879                                    let editor_range =
 1880                                        language::range_from_lsp(*range).to_offset(&snapshot);
 1881                                    editor
 1882                                        .insert_snippet(
 1883                                            &[editor_range],
 1884                                            snippet.clone(),
 1885                                            window,
 1886                                            cx,
 1887                                        )
 1888                                        .ok();
 1889                                }
 1890                            }
 1891                        }
 1892                    }
 1893                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 1894                        let buffer_id = *buffer_id;
 1895                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 1896                            editor.register_buffer(buffer_id, cx);
 1897                            editor.update_lsp_data(Some(buffer_id), window, cx);
 1898                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 1899                            refresh_linked_ranges(editor, window, cx);
 1900                            editor.refresh_code_actions(window, cx);
 1901                            editor.refresh_document_highlights(cx);
 1902                        }
 1903                    }
 1904
 1905                    project::Event::EntryRenamed(transaction) => {
 1906                        let Some(workspace) = editor.workspace() else {
 1907                            return;
 1908                        };
 1909                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 1910                        else {
 1911                            return;
 1912                        };
 1913                        if active_editor.entity_id() == cx.entity_id() {
 1914                            let edited_buffers_already_open = {
 1915                                let other_editors: Vec<Entity<Editor>> = workspace
 1916                                    .read(cx)
 1917                                    .panes()
 1918                                    .iter()
 1919                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 1920                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 1921                                    .collect();
 1922
 1923                                transaction.0.keys().all(|buffer| {
 1924                                    other_editors.iter().any(|editor| {
 1925                                        let multi_buffer = editor.read(cx).buffer();
 1926                                        multi_buffer.read(cx).is_singleton()
 1927                                            && multi_buffer.read(cx).as_singleton().map_or(
 1928                                                false,
 1929                                                |singleton| {
 1930                                                    singleton.entity_id() == buffer.entity_id()
 1931                                                },
 1932                                            )
 1933                                    })
 1934                                })
 1935                            };
 1936
 1937                            if !edited_buffers_already_open {
 1938                                let workspace = workspace.downgrade();
 1939                                let transaction = transaction.clone();
 1940                                cx.defer_in(window, move |_, window, cx| {
 1941                                    cx.spawn_in(window, async move |editor, cx| {
 1942                                        Self::open_project_transaction(
 1943                                            &editor,
 1944                                            workspace,
 1945                                            transaction,
 1946                                            "Rename".to_string(),
 1947                                            cx,
 1948                                        )
 1949                                        .await
 1950                                        .ok()
 1951                                    })
 1952                                    .detach();
 1953                                });
 1954                            }
 1955                        }
 1956                    }
 1957
 1958                    _ => {}
 1959                },
 1960            ));
 1961            if let Some(task_inventory) = project
 1962                .read(cx)
 1963                .task_store()
 1964                .read(cx)
 1965                .task_inventory()
 1966                .cloned()
 1967            {
 1968                project_subscriptions.push(cx.observe_in(
 1969                    &task_inventory,
 1970                    window,
 1971                    |editor, _, window, cx| {
 1972                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1973                    },
 1974                ));
 1975            };
 1976
 1977            project_subscriptions.push(cx.subscribe_in(
 1978                &project.read(cx).breakpoint_store(),
 1979                window,
 1980                |editor, _, event, window, cx| match event {
 1981                    BreakpointStoreEvent::ClearDebugLines => {
 1982                        editor.clear_row_highlights::<ActiveDebugLine>();
 1983                        editor.refresh_inline_values(cx);
 1984                    }
 1985                    BreakpointStoreEvent::SetDebugLine => {
 1986                        if editor.go_to_active_debug_line(window, cx) {
 1987                            cx.stop_propagation();
 1988                        }
 1989
 1990                        editor.refresh_inline_values(cx);
 1991                    }
 1992                    _ => {}
 1993                },
 1994            ));
 1995            let git_store = project.read(cx).git_store().clone();
 1996            let project = project.clone();
 1997            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 1998                if let GitStoreEvent::RepositoryAdded = event {
 1999                    this.load_diff_task = Some(
 2000                        update_uncommitted_diff_for_buffer(
 2001                            cx.entity(),
 2002                            &project,
 2003                            this.buffer.read(cx).all_buffers(),
 2004                            this.buffer.clone(),
 2005                            cx,
 2006                        )
 2007                        .shared(),
 2008                    );
 2009                }
 2010            }));
 2011        }
 2012
 2013        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2014
 2015        let inlay_hint_settings =
 2016            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2017        let focus_handle = cx.focus_handle();
 2018        if !is_minimap {
 2019            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2020                .detach();
 2021            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2022                .detach();
 2023            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2024                .detach();
 2025            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2026                .detach();
 2027            cx.observe_pending_input(window, Self::observe_pending_input)
 2028                .detach();
 2029        }
 2030
 2031        let show_indent_guides =
 2032            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2033                Some(false)
 2034            } else {
 2035                None
 2036            };
 2037
 2038        let breakpoint_store = match (&mode, project.as_ref()) {
 2039            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2040            _ => None,
 2041        };
 2042
 2043        let mut code_action_providers = Vec::new();
 2044        let mut load_uncommitted_diff = None;
 2045        if let Some(project) = project.clone() {
 2046            load_uncommitted_diff = Some(
 2047                update_uncommitted_diff_for_buffer(
 2048                    cx.entity(),
 2049                    &project,
 2050                    multi_buffer.read(cx).all_buffers(),
 2051                    multi_buffer.clone(),
 2052                    cx,
 2053                )
 2054                .shared(),
 2055            );
 2056            code_action_providers.push(Rc::new(project) as Rc<_>);
 2057        }
 2058
 2059        let mut editor = Self {
 2060            focus_handle,
 2061            show_cursor_when_unfocused: false,
 2062            last_focused_descendant: None,
 2063            buffer: multi_buffer.clone(),
 2064            display_map: display_map.clone(),
 2065            placeholder_display_map: None,
 2066            selections,
 2067            scroll_manager: ScrollManager::new(cx),
 2068            columnar_selection_state: None,
 2069            add_selections_state: None,
 2070            select_next_state: None,
 2071            select_prev_state: None,
 2072            selection_history: SelectionHistory::default(),
 2073            defer_selection_effects: false,
 2074            deferred_selection_effects_state: None,
 2075            autoclose_regions: Vec::new(),
 2076            snippet_stack: InvalidationStack::default(),
 2077            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2078            ime_transaction: None,
 2079            active_diagnostics: ActiveDiagnostic::None,
 2080            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2081            inline_diagnostics_update: Task::ready(()),
 2082            inline_diagnostics: Vec::new(),
 2083            soft_wrap_mode_override,
 2084            diagnostics_max_severity,
 2085            hard_wrap: None,
 2086            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2087            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2088            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2089            project,
 2090            blink_manager: blink_manager.clone(),
 2091            show_local_selections: true,
 2092            show_scrollbars: ScrollbarAxes {
 2093                horizontal: full_mode,
 2094                vertical: full_mode,
 2095            },
 2096            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2097            offset_content: !matches!(mode, EditorMode::SingleLine),
 2098            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2099            show_gutter: full_mode,
 2100            show_line_numbers: (!full_mode).then_some(false),
 2101            use_relative_line_numbers: None,
 2102            disable_expand_excerpt_buttons: !full_mode,
 2103            show_git_diff_gutter: None,
 2104            show_code_actions: None,
 2105            show_runnables: None,
 2106            show_breakpoints: None,
 2107            show_wrap_guides: None,
 2108            show_indent_guides,
 2109            highlight_order: 0,
 2110            highlighted_rows: HashMap::default(),
 2111            background_highlights: HashMap::default(),
 2112            gutter_highlights: HashMap::default(),
 2113            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2114            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2115            nav_history: None,
 2116            context_menu: RefCell::new(None),
 2117            context_menu_options: None,
 2118            mouse_context_menu: None,
 2119            completion_tasks: Vec::new(),
 2120            inline_blame_popover: None,
 2121            inline_blame_popover_show_task: None,
 2122            signature_help_state: SignatureHelpState::default(),
 2123            auto_signature_help: None,
 2124            find_all_references_task_sources: Vec::new(),
 2125            next_completion_id: 0,
 2126            next_inlay_id: 0,
 2127            code_action_providers,
 2128            available_code_actions: None,
 2129            code_actions_task: None,
 2130            quick_selection_highlight_task: None,
 2131            debounced_selection_highlight_task: None,
 2132            document_highlights_task: None,
 2133            linked_editing_range_task: None,
 2134            pending_rename: None,
 2135            searchable: !is_minimap,
 2136            cursor_shape: EditorSettings::get_global(cx)
 2137                .cursor_shape
 2138                .unwrap_or_default(),
 2139            current_line_highlight: None,
 2140            autoindent_mode: Some(AutoindentMode::EachLine),
 2141
 2142            workspace: None,
 2143            input_enabled: !is_minimap,
 2144            use_modal_editing: full_mode,
 2145            read_only: is_minimap,
 2146            use_autoclose: true,
 2147            use_auto_surround: true,
 2148            auto_replace_emoji_shortcode: false,
 2149            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2150            leader_id: None,
 2151            remote_id: None,
 2152            hover_state: HoverState::default(),
 2153            pending_mouse_down: None,
 2154            hovered_link_state: None,
 2155            edit_prediction_provider: None,
 2156            active_edit_prediction: None,
 2157            stale_edit_prediction_in_menu: None,
 2158            edit_prediction_preview: EditPredictionPreview::Inactive {
 2159                released_too_fast: false,
 2160            },
 2161            inline_diagnostics_enabled: full_mode,
 2162            diagnostics_enabled: full_mode,
 2163            word_completions_enabled: full_mode,
 2164            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2165            gutter_hovered: false,
 2166            pixel_position_of_newest_cursor: None,
 2167            last_bounds: None,
 2168            last_position_map: None,
 2169            expect_bounds_change: None,
 2170            gutter_dimensions: GutterDimensions::default(),
 2171            style: None,
 2172            show_cursor_names: false,
 2173            hovered_cursors: HashMap::default(),
 2174            next_editor_action_id: EditorActionId::default(),
 2175            editor_actions: Rc::default(),
 2176            edit_predictions_hidden_for_vim_mode: false,
 2177            show_edit_predictions_override: None,
 2178            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2179            edit_prediction_settings: EditPredictionSettings::Disabled,
 2180            edit_prediction_indent_conflict: false,
 2181            edit_prediction_requires_modifier_in_indent_conflict: true,
 2182            custom_context_menu: None,
 2183            show_git_blame_gutter: false,
 2184            show_git_blame_inline: false,
 2185            show_selection_menu: None,
 2186            show_git_blame_inline_delay_task: None,
 2187            git_blame_inline_enabled: full_mode
 2188                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2189            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2190            serialize_dirty_buffers: !is_minimap
 2191                && ProjectSettings::get_global(cx)
 2192                    .session
 2193                    .restore_unsaved_buffers,
 2194            blame: None,
 2195            blame_subscription: None,
 2196            tasks: BTreeMap::default(),
 2197
 2198            breakpoint_store,
 2199            gutter_breakpoint_indicator: (None, None),
 2200            hovered_diff_hunk_row: None,
 2201            _subscriptions: (!is_minimap)
 2202                .then(|| {
 2203                    vec![
 2204                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2205                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2206                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2207                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2208                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2209                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2210                        cx.observe_window_activation(window, |editor, window, cx| {
 2211                            let active = window.is_window_active();
 2212                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2213                                if active {
 2214                                    blink_manager.enable(cx);
 2215                                } else {
 2216                                    blink_manager.disable(cx);
 2217                                }
 2218                            });
 2219                            if active {
 2220                                editor.show_mouse_cursor(cx);
 2221                            }
 2222                        }),
 2223                    ]
 2224                })
 2225                .unwrap_or_default(),
 2226            tasks_update_task: None,
 2227            pull_diagnostics_task: Task::ready(()),
 2228            colors: None,
 2229            refresh_colors_task: Task::ready(()),
 2230            inlay_hints: None,
 2231            next_color_inlay_id: 0,
 2232            post_scroll_update: Task::ready(()),
 2233            linked_edit_ranges: Default::default(),
 2234            in_project_search: false,
 2235            previous_search_ranges: None,
 2236            breadcrumb_header: None,
 2237            focused_block: None,
 2238            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2239            addons: HashMap::default(),
 2240            registered_buffers: HashMap::default(),
 2241            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2242            selection_mark_mode: false,
 2243            toggle_fold_multiple_buffers: Task::ready(()),
 2244            serialize_selections: Task::ready(()),
 2245            serialize_folds: Task::ready(()),
 2246            text_style_refinement: None,
 2247            load_diff_task: load_uncommitted_diff,
 2248            temporary_diff_override: false,
 2249            mouse_cursor_hidden: false,
 2250            minimap: None,
 2251            hide_mouse_mode: EditorSettings::get_global(cx)
 2252                .hide_mouse
 2253                .unwrap_or_default(),
 2254            change_list: ChangeList::new(),
 2255            mode,
 2256            selection_drag_state: SelectionDragState::None,
 2257            folding_newlines: Task::ready(()),
 2258            lookup_key: None,
 2259        };
 2260
 2261        if is_minimap {
 2262            return editor;
 2263        }
 2264
 2265        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2266            editor
 2267                ._subscriptions
 2268                .push(cx.observe(breakpoints, |_, _, cx| {
 2269                    cx.notify();
 2270                }));
 2271        }
 2272        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2273        editor._subscriptions.extend(project_subscriptions);
 2274
 2275        editor._subscriptions.push(cx.subscribe_in(
 2276            &cx.entity(),
 2277            window,
 2278            |editor, _, e: &EditorEvent, window, cx| match e {
 2279                EditorEvent::ScrollPositionChanged { local, .. } => {
 2280                    if *local {
 2281                        let new_anchor = editor.scroll_manager.anchor();
 2282                        let snapshot = editor.snapshot(window, cx);
 2283                        editor.update_restoration_data(cx, move |data| {
 2284                            data.scroll_position = (
 2285                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2286                                new_anchor.offset,
 2287                            );
 2288                        });
 2289                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2290                        editor.inline_blame_popover.take();
 2291                    }
 2292                }
 2293                EditorEvent::Edited { .. } => {
 2294                    if vim_flavor(cx).is_none() {
 2295                        let display_map = editor.display_snapshot(cx);
 2296                        let selections = editor.selections.all_adjusted_display(&display_map);
 2297                        let pop_state = editor
 2298                            .change_list
 2299                            .last()
 2300                            .map(|previous| {
 2301                                previous.len() == selections.len()
 2302                                    && previous.iter().enumerate().all(|(ix, p)| {
 2303                                        p.to_display_point(&display_map).row()
 2304                                            == selections[ix].head().row()
 2305                                    })
 2306                            })
 2307                            .unwrap_or(false);
 2308                        let new_positions = selections
 2309                            .into_iter()
 2310                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2311                            .collect();
 2312                        editor
 2313                            .change_list
 2314                            .push_to_change_list(pop_state, new_positions);
 2315                    }
 2316                }
 2317                _ => (),
 2318            },
 2319        ));
 2320
 2321        if let Some(dap_store) = editor
 2322            .project
 2323            .as_ref()
 2324            .map(|project| project.read(cx).dap_store())
 2325        {
 2326            let weak_editor = cx.weak_entity();
 2327
 2328            editor
 2329                ._subscriptions
 2330                .push(
 2331                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2332                        let session_entity = cx.entity();
 2333                        weak_editor
 2334                            .update(cx, |editor, cx| {
 2335                                editor._subscriptions.push(
 2336                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2337                                );
 2338                            })
 2339                            .ok();
 2340                    }),
 2341                );
 2342
 2343            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2344                editor
 2345                    ._subscriptions
 2346                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2347            }
 2348        }
 2349
 2350        // skip adding the initial selection to selection history
 2351        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2352        editor.end_selection(window, cx);
 2353        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2354
 2355        editor.scroll_manager.show_scrollbars(window, cx);
 2356        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2357
 2358        if full_mode {
 2359            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2360            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2361
 2362            if editor.git_blame_inline_enabled {
 2363                editor.start_git_blame_inline(false, window, cx);
 2364            }
 2365
 2366            editor.go_to_active_debug_line(window, cx);
 2367
 2368            editor.minimap =
 2369                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2370            editor.colors = Some(LspColorData::new(cx));
 2371            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2372
 2373            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2374                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2375            }
 2376            editor.update_lsp_data(None, window, cx);
 2377            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2378        }
 2379
 2380        editor
 2381    }
 2382
 2383    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2384        self.selections.display_map(cx)
 2385    }
 2386
 2387    pub fn deploy_mouse_context_menu(
 2388        &mut self,
 2389        position: gpui::Point<Pixels>,
 2390        context_menu: Entity<ContextMenu>,
 2391        window: &mut Window,
 2392        cx: &mut Context<Self>,
 2393    ) {
 2394        self.mouse_context_menu = Some(MouseContextMenu::new(
 2395            self,
 2396            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2397            context_menu,
 2398            window,
 2399            cx,
 2400        ));
 2401    }
 2402
 2403    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2404        self.mouse_context_menu
 2405            .as_ref()
 2406            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2407    }
 2408
 2409    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2410        if self
 2411            .selections
 2412            .pending_anchor()
 2413            .is_some_and(|pending_selection| {
 2414                let snapshot = self.buffer().read(cx).snapshot(cx);
 2415                pending_selection.range().includes(range, &snapshot)
 2416            })
 2417        {
 2418            return true;
 2419        }
 2420
 2421        self.selections
 2422            .disjoint_in_range::<usize>(range.clone(), &self.display_snapshot(cx))
 2423            .into_iter()
 2424            .any(|selection| {
 2425                // This is needed to cover a corner case, if we just check for an existing
 2426                // selection in the fold range, having a cursor at the start of the fold
 2427                // marks it as selected. Non-empty selections don't cause this.
 2428                let length = selection.end - selection.start;
 2429                length > 0
 2430            })
 2431    }
 2432
 2433    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2434        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2435    }
 2436
 2437    fn key_context_internal(
 2438        &self,
 2439        has_active_edit_prediction: bool,
 2440        window: &mut Window,
 2441        cx: &mut App,
 2442    ) -> KeyContext {
 2443        let mut key_context = KeyContext::new_with_defaults();
 2444        key_context.add("Editor");
 2445        let mode = match self.mode {
 2446            EditorMode::SingleLine => "single_line",
 2447            EditorMode::AutoHeight { .. } => "auto_height",
 2448            EditorMode::Minimap { .. } => "minimap",
 2449            EditorMode::Full { .. } => "full",
 2450        };
 2451
 2452        if EditorSettings::jupyter_enabled(cx) {
 2453            key_context.add("jupyter");
 2454        }
 2455
 2456        key_context.set("mode", mode);
 2457        if self.pending_rename.is_some() {
 2458            key_context.add("renaming");
 2459        }
 2460
 2461        if !self.snippet_stack.is_empty() {
 2462            key_context.add("in_snippet");
 2463        }
 2464
 2465        match self.context_menu.borrow().as_ref() {
 2466            Some(CodeContextMenu::Completions(menu)) => {
 2467                if menu.visible() {
 2468                    key_context.add("menu");
 2469                    key_context.add("showing_completions");
 2470                }
 2471            }
 2472            Some(CodeContextMenu::CodeActions(menu)) => {
 2473                if menu.visible() {
 2474                    key_context.add("menu");
 2475                    key_context.add("showing_code_actions")
 2476                }
 2477            }
 2478            None => {}
 2479        }
 2480
 2481        if self.signature_help_state.has_multiple_signatures() {
 2482            key_context.add("showing_signature_help");
 2483        }
 2484
 2485        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2486        if !self.focus_handle(cx).contains_focused(window, cx)
 2487            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2488        {
 2489            for addon in self.addons.values() {
 2490                addon.extend_key_context(&mut key_context, cx)
 2491            }
 2492        }
 2493
 2494        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2495            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2496                Some(
 2497                    file.full_path(cx)
 2498                        .extension()?
 2499                        .to_string_lossy()
 2500                        .into_owned(),
 2501                )
 2502            }) {
 2503                key_context.set("extension", extension);
 2504            }
 2505        } else {
 2506            key_context.add("multibuffer");
 2507        }
 2508
 2509        if has_active_edit_prediction {
 2510            if self.edit_prediction_in_conflict() {
 2511                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2512            } else {
 2513                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2514                key_context.add("copilot_suggestion");
 2515            }
 2516        }
 2517
 2518        if self.selection_mark_mode {
 2519            key_context.add("selection_mode");
 2520        }
 2521
 2522        let disjoint = self.selections.disjoint_anchors();
 2523        let snapshot = self.snapshot(window, cx);
 2524        let snapshot = snapshot.buffer_snapshot();
 2525        if self.mode == EditorMode::SingleLine
 2526            && let [selection] = disjoint
 2527            && selection.start == selection.end
 2528            && selection.end.to_offset(snapshot) == snapshot.len()
 2529        {
 2530            key_context.add("end_of_input");
 2531        }
 2532
 2533        key_context
 2534    }
 2535
 2536    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2537        self.last_bounds.as_ref()
 2538    }
 2539
 2540    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2541        if self.mouse_cursor_hidden {
 2542            self.mouse_cursor_hidden = false;
 2543            cx.notify();
 2544        }
 2545    }
 2546
 2547    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2548        let hide_mouse_cursor = match origin {
 2549            HideMouseCursorOrigin::TypingAction => {
 2550                matches!(
 2551                    self.hide_mouse_mode,
 2552                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2553                )
 2554            }
 2555            HideMouseCursorOrigin::MovementAction => {
 2556                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2557            }
 2558        };
 2559        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2560            self.mouse_cursor_hidden = hide_mouse_cursor;
 2561            cx.notify();
 2562        }
 2563    }
 2564
 2565    pub fn edit_prediction_in_conflict(&self) -> bool {
 2566        if !self.show_edit_predictions_in_menu() {
 2567            return false;
 2568        }
 2569
 2570        let showing_completions = self
 2571            .context_menu
 2572            .borrow()
 2573            .as_ref()
 2574            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2575
 2576        showing_completions
 2577            || self.edit_prediction_requires_modifier()
 2578            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2579            // bindings to insert tab characters.
 2580            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2581    }
 2582
 2583    pub fn accept_edit_prediction_keybind(
 2584        &self,
 2585        accept_partial: bool,
 2586        window: &mut Window,
 2587        cx: &mut App,
 2588    ) -> AcceptEditPredictionBinding {
 2589        let key_context = self.key_context_internal(true, window, cx);
 2590        let in_conflict = self.edit_prediction_in_conflict();
 2591
 2592        let bindings = if accept_partial {
 2593            window.bindings_for_action_in_context(&AcceptPartialEditPrediction, key_context)
 2594        } else {
 2595            window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2596        };
 2597
 2598        // TODO: if the binding contains multiple keystrokes, display all of them, not
 2599        // just the first one.
 2600        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2601            !in_conflict
 2602                || binding
 2603                    .keystrokes()
 2604                    .first()
 2605                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2606        }))
 2607    }
 2608
 2609    pub fn new_file(
 2610        workspace: &mut Workspace,
 2611        _: &workspace::NewFile,
 2612        window: &mut Window,
 2613        cx: &mut Context<Workspace>,
 2614    ) {
 2615        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2616            "Failed to create buffer",
 2617            window,
 2618            cx,
 2619            |e, _, _| match e.error_code() {
 2620                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2621                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2622                e.error_tag("required").unwrap_or("the latest version")
 2623            )),
 2624                _ => None,
 2625            },
 2626        );
 2627    }
 2628
 2629    pub fn new_in_workspace(
 2630        workspace: &mut Workspace,
 2631        window: &mut Window,
 2632        cx: &mut Context<Workspace>,
 2633    ) -> Task<Result<Entity<Editor>>> {
 2634        let project = workspace.project().clone();
 2635        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2636
 2637        cx.spawn_in(window, async move |workspace, cx| {
 2638            let buffer = create.await?;
 2639            workspace.update_in(cx, |workspace, window, cx| {
 2640                let editor =
 2641                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2642                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2643                editor
 2644            })
 2645        })
 2646    }
 2647
 2648    fn new_file_vertical(
 2649        workspace: &mut Workspace,
 2650        _: &workspace::NewFileSplitVertical,
 2651        window: &mut Window,
 2652        cx: &mut Context<Workspace>,
 2653    ) {
 2654        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2655    }
 2656
 2657    fn new_file_horizontal(
 2658        workspace: &mut Workspace,
 2659        _: &workspace::NewFileSplitHorizontal,
 2660        window: &mut Window,
 2661        cx: &mut Context<Workspace>,
 2662    ) {
 2663        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2664    }
 2665
 2666    fn new_file_split(
 2667        workspace: &mut Workspace,
 2668        action: &workspace::NewFileSplit,
 2669        window: &mut Window,
 2670        cx: &mut Context<Workspace>,
 2671    ) {
 2672        Self::new_file_in_direction(workspace, action.0, window, cx)
 2673    }
 2674
 2675    fn new_file_in_direction(
 2676        workspace: &mut Workspace,
 2677        direction: SplitDirection,
 2678        window: &mut Window,
 2679        cx: &mut Context<Workspace>,
 2680    ) {
 2681        let project = workspace.project().clone();
 2682        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2683
 2684        cx.spawn_in(window, async move |workspace, cx| {
 2685            let buffer = create.await?;
 2686            workspace.update_in(cx, move |workspace, window, cx| {
 2687                workspace.split_item(
 2688                    direction,
 2689                    Box::new(
 2690                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2691                    ),
 2692                    window,
 2693                    cx,
 2694                )
 2695            })?;
 2696            anyhow::Ok(())
 2697        })
 2698        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2699            match e.error_code() {
 2700                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2701                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2702                e.error_tag("required").unwrap_or("the latest version")
 2703            )),
 2704                _ => None,
 2705            }
 2706        });
 2707    }
 2708
 2709    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2710        self.leader_id
 2711    }
 2712
 2713    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2714        &self.buffer
 2715    }
 2716
 2717    pub fn project(&self) -> Option<&Entity<Project>> {
 2718        self.project.as_ref()
 2719    }
 2720
 2721    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2722        self.workspace.as_ref()?.0.upgrade()
 2723    }
 2724
 2725    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2726        self.buffer().read(cx).title(cx)
 2727    }
 2728
 2729    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2730        let git_blame_gutter_max_author_length = self
 2731            .render_git_blame_gutter(cx)
 2732            .then(|| {
 2733                if let Some(blame) = self.blame.as_ref() {
 2734                    let max_author_length =
 2735                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2736                    Some(max_author_length)
 2737                } else {
 2738                    None
 2739                }
 2740            })
 2741            .flatten();
 2742
 2743        EditorSnapshot {
 2744            mode: self.mode.clone(),
 2745            show_gutter: self.show_gutter,
 2746            show_line_numbers: self.show_line_numbers,
 2747            show_git_diff_gutter: self.show_git_diff_gutter,
 2748            show_code_actions: self.show_code_actions,
 2749            show_runnables: self.show_runnables,
 2750            show_breakpoints: self.show_breakpoints,
 2751            git_blame_gutter_max_author_length,
 2752            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2753            placeholder_display_snapshot: self
 2754                .placeholder_display_map
 2755                .as_ref()
 2756                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2757            scroll_anchor: self.scroll_manager.anchor(),
 2758            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2759            is_focused: self.focus_handle.is_focused(window),
 2760            current_line_highlight: self
 2761                .current_line_highlight
 2762                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2763            gutter_hovered: self.gutter_hovered,
 2764        }
 2765    }
 2766
 2767    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2768        self.buffer.read(cx).language_at(point, cx)
 2769    }
 2770
 2771    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2772        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2773    }
 2774
 2775    pub fn active_excerpt(
 2776        &self,
 2777        cx: &App,
 2778    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2779        self.buffer
 2780            .read(cx)
 2781            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2782    }
 2783
 2784    pub fn mode(&self) -> &EditorMode {
 2785        &self.mode
 2786    }
 2787
 2788    pub fn set_mode(&mut self, mode: EditorMode) {
 2789        self.mode = mode;
 2790    }
 2791
 2792    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2793        self.collaboration_hub.as_deref()
 2794    }
 2795
 2796    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 2797        self.collaboration_hub = Some(hub);
 2798    }
 2799
 2800    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 2801        self.in_project_search = in_project_search;
 2802    }
 2803
 2804    pub fn set_custom_context_menu(
 2805        &mut self,
 2806        f: impl 'static
 2807        + Fn(
 2808            &mut Self,
 2809            DisplayPoint,
 2810            &mut Window,
 2811            &mut Context<Self>,
 2812        ) -> Option<Entity<ui::ContextMenu>>,
 2813    ) {
 2814        self.custom_context_menu = Some(Box::new(f))
 2815    }
 2816
 2817    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 2818        self.completion_provider = provider;
 2819    }
 2820
 2821    #[cfg(any(test, feature = "test-support"))]
 2822    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 2823        self.completion_provider.clone()
 2824    }
 2825
 2826    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 2827        self.semantics_provider.clone()
 2828    }
 2829
 2830    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 2831        self.semantics_provider = provider;
 2832    }
 2833
 2834    pub fn set_edit_prediction_provider<T>(
 2835        &mut self,
 2836        provider: Option<Entity<T>>,
 2837        window: &mut Window,
 2838        cx: &mut Context<Self>,
 2839    ) where
 2840        T: EditPredictionProvider,
 2841    {
 2842        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionProvider {
 2843            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 2844                if this.focus_handle.is_focused(window) {
 2845                    this.update_visible_edit_prediction(window, cx);
 2846                }
 2847            }),
 2848            provider: Arc::new(provider),
 2849        });
 2850        self.update_edit_prediction_settings(cx);
 2851        self.refresh_edit_prediction(false, false, window, cx);
 2852    }
 2853
 2854    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 2855        self.placeholder_display_map
 2856            .as_ref()
 2857            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 2858    }
 2859
 2860    pub fn set_placeholder_text(
 2861        &mut self,
 2862        placeholder_text: &str,
 2863        window: &mut Window,
 2864        cx: &mut Context<Self>,
 2865    ) {
 2866        let multibuffer = cx
 2867            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 2868
 2869        let style = window.text_style();
 2870
 2871        self.placeholder_display_map = Some(cx.new(|cx| {
 2872            DisplayMap::new(
 2873                multibuffer,
 2874                style.font(),
 2875                style.font_size.to_pixels(window.rem_size()),
 2876                None,
 2877                FILE_HEADER_HEIGHT,
 2878                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2879                Default::default(),
 2880                DiagnosticSeverity::Off,
 2881                cx,
 2882            )
 2883        }));
 2884        cx.notify();
 2885    }
 2886
 2887    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 2888        self.cursor_shape = cursor_shape;
 2889
 2890        // Disrupt blink for immediate user feedback that the cursor shape has changed
 2891        self.blink_manager.update(cx, BlinkManager::show_cursor);
 2892
 2893        cx.notify();
 2894    }
 2895
 2896    pub fn set_current_line_highlight(
 2897        &mut self,
 2898        current_line_highlight: Option<CurrentLineHighlight>,
 2899    ) {
 2900        self.current_line_highlight = current_line_highlight;
 2901    }
 2902
 2903    pub fn range_for_match<T: std::marker::Copy>(
 2904        &self,
 2905        range: &Range<T>,
 2906        collapse: bool,
 2907    ) -> Range<T> {
 2908        if collapse {
 2909            return range.start..range.start;
 2910        }
 2911        range.clone()
 2912    }
 2913
 2914    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 2915        if self.display_map.read(cx).clip_at_line_ends != clip {
 2916            self.display_map
 2917                .update(cx, |map, _| map.clip_at_line_ends = clip);
 2918        }
 2919    }
 2920
 2921    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 2922        self.input_enabled = input_enabled;
 2923    }
 2924
 2925    pub fn set_edit_predictions_hidden_for_vim_mode(
 2926        &mut self,
 2927        hidden: bool,
 2928        window: &mut Window,
 2929        cx: &mut Context<Self>,
 2930    ) {
 2931        if hidden != self.edit_predictions_hidden_for_vim_mode {
 2932            self.edit_predictions_hidden_for_vim_mode = hidden;
 2933            if hidden {
 2934                self.update_visible_edit_prediction(window, cx);
 2935            } else {
 2936                self.refresh_edit_prediction(true, false, window, cx);
 2937            }
 2938        }
 2939    }
 2940
 2941    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 2942        self.menu_edit_predictions_policy = value;
 2943    }
 2944
 2945    pub fn set_autoindent(&mut self, autoindent: bool) {
 2946        if autoindent {
 2947            self.autoindent_mode = Some(AutoindentMode::EachLine);
 2948        } else {
 2949            self.autoindent_mode = None;
 2950        }
 2951    }
 2952
 2953    pub fn read_only(&self, cx: &App) -> bool {
 2954        self.read_only || self.buffer.read(cx).read_only()
 2955    }
 2956
 2957    pub fn set_read_only(&mut self, read_only: bool) {
 2958        self.read_only = read_only;
 2959    }
 2960
 2961    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 2962        self.use_autoclose = autoclose;
 2963    }
 2964
 2965    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 2966        self.use_auto_surround = auto_surround;
 2967    }
 2968
 2969    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 2970        self.auto_replace_emoji_shortcode = auto_replace;
 2971    }
 2972
 2973    pub fn toggle_edit_predictions(
 2974        &mut self,
 2975        _: &ToggleEditPrediction,
 2976        window: &mut Window,
 2977        cx: &mut Context<Self>,
 2978    ) {
 2979        if self.show_edit_predictions_override.is_some() {
 2980            self.set_show_edit_predictions(None, window, cx);
 2981        } else {
 2982            let show_edit_predictions = !self.edit_predictions_enabled();
 2983            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 2984        }
 2985    }
 2986
 2987    pub fn set_show_edit_predictions(
 2988        &mut self,
 2989        show_edit_predictions: Option<bool>,
 2990        window: &mut Window,
 2991        cx: &mut Context<Self>,
 2992    ) {
 2993        self.show_edit_predictions_override = show_edit_predictions;
 2994        self.update_edit_prediction_settings(cx);
 2995
 2996        if let Some(false) = show_edit_predictions {
 2997            self.discard_edit_prediction(false, cx);
 2998        } else {
 2999            self.refresh_edit_prediction(false, true, window, cx);
 3000        }
 3001    }
 3002
 3003    fn edit_predictions_disabled_in_scope(
 3004        &self,
 3005        buffer: &Entity<Buffer>,
 3006        buffer_position: language::Anchor,
 3007        cx: &App,
 3008    ) -> bool {
 3009        let snapshot = buffer.read(cx).snapshot();
 3010        let settings = snapshot.settings_at(buffer_position, cx);
 3011
 3012        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3013            return false;
 3014        };
 3015
 3016        scope.override_name().is_some_and(|scope_name| {
 3017            settings
 3018                .edit_predictions_disabled_in
 3019                .iter()
 3020                .any(|s| s == scope_name)
 3021        })
 3022    }
 3023
 3024    pub fn set_use_modal_editing(&mut self, to: bool) {
 3025        self.use_modal_editing = to;
 3026    }
 3027
 3028    pub fn use_modal_editing(&self) -> bool {
 3029        self.use_modal_editing
 3030    }
 3031
 3032    fn selections_did_change(
 3033        &mut self,
 3034        local: bool,
 3035        old_cursor_position: &Anchor,
 3036        effects: SelectionEffects,
 3037        window: &mut Window,
 3038        cx: &mut Context<Self>,
 3039    ) {
 3040        window.invalidate_character_coordinates();
 3041
 3042        // Copy selections to primary selection buffer
 3043        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3044        if local {
 3045            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3046            let buffer_handle = self.buffer.read(cx).read(cx);
 3047
 3048            let mut text = String::new();
 3049            for (index, selection) in selections.iter().enumerate() {
 3050                let text_for_selection = buffer_handle
 3051                    .text_for_range(selection.start..selection.end)
 3052                    .collect::<String>();
 3053
 3054                text.push_str(&text_for_selection);
 3055                if index != selections.len() - 1 {
 3056                    text.push('\n');
 3057                }
 3058            }
 3059
 3060            if !text.is_empty() {
 3061                cx.write_to_primary(ClipboardItem::new_string(text));
 3062            }
 3063        }
 3064
 3065        let selection_anchors = self.selections.disjoint_anchors_arc();
 3066
 3067        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3068            self.buffer.update(cx, |buffer, cx| {
 3069                buffer.set_active_selections(
 3070                    &selection_anchors,
 3071                    self.selections.line_mode(),
 3072                    self.cursor_shape,
 3073                    cx,
 3074                )
 3075            });
 3076        }
 3077        let display_map = self
 3078            .display_map
 3079            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3080        let buffer = display_map.buffer_snapshot();
 3081        if self.selections.count() == 1 {
 3082            self.add_selections_state = None;
 3083        }
 3084        self.select_next_state = None;
 3085        self.select_prev_state = None;
 3086        self.select_syntax_node_history.try_clear();
 3087        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3088        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3089        self.take_rename(false, window, cx);
 3090
 3091        let newest_selection = self.selections.newest_anchor();
 3092        let new_cursor_position = newest_selection.head();
 3093        let selection_start = newest_selection.start;
 3094
 3095        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3096            self.push_to_nav_history(
 3097                *old_cursor_position,
 3098                Some(new_cursor_position.to_point(buffer)),
 3099                false,
 3100                effects.nav_history == Some(true),
 3101                cx,
 3102            );
 3103        }
 3104
 3105        if local {
 3106            if let Some(buffer_id) = new_cursor_position.buffer_id {
 3107                self.register_buffer(buffer_id, cx);
 3108            }
 3109
 3110            let mut context_menu = self.context_menu.borrow_mut();
 3111            let completion_menu = match context_menu.as_ref() {
 3112                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3113                Some(CodeContextMenu::CodeActions(_)) => {
 3114                    *context_menu = None;
 3115                    None
 3116                }
 3117                None => None,
 3118            };
 3119            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3120            drop(context_menu);
 3121
 3122            if effects.completions
 3123                && let Some(completion_position) = completion_position
 3124            {
 3125                let start_offset = selection_start.to_offset(buffer);
 3126                let position_matches = start_offset == completion_position.to_offset(buffer);
 3127                let continue_showing = if position_matches {
 3128                    if self.snippet_stack.is_empty() {
 3129                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3130                            == Some(CharKind::Word)
 3131                    } else {
 3132                        // Snippet choices can be shown even when the cursor is in whitespace.
 3133                        // Dismissing the menu with actions like backspace is handled by
 3134                        // invalidation regions.
 3135                        true
 3136                    }
 3137                } else {
 3138                    false
 3139                };
 3140
 3141                if continue_showing {
 3142                    self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 3143                } else {
 3144                    self.hide_context_menu(window, cx);
 3145                }
 3146            }
 3147
 3148            hide_hover(self, cx);
 3149
 3150            if old_cursor_position.to_display_point(&display_map).row()
 3151                != new_cursor_position.to_display_point(&display_map).row()
 3152            {
 3153                self.available_code_actions.take();
 3154            }
 3155            self.refresh_code_actions(window, cx);
 3156            self.refresh_document_highlights(cx);
 3157            refresh_linked_ranges(self, window, cx);
 3158
 3159            self.refresh_selected_text_highlights(false, window, cx);
 3160            self.refresh_matching_bracket_highlights(window, cx);
 3161            self.update_visible_edit_prediction(window, cx);
 3162            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3163            self.inline_blame_popover.take();
 3164            if self.git_blame_inline_enabled {
 3165                self.start_inline_blame_timer(window, cx);
 3166            }
 3167        }
 3168
 3169        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3170        cx.emit(EditorEvent::SelectionsChanged { local });
 3171
 3172        let selections = &self.selections.disjoint_anchors_arc();
 3173        if selections.len() == 1 {
 3174            cx.emit(SearchEvent::ActiveMatchChanged)
 3175        }
 3176        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3177            let inmemory_selections = selections
 3178                .iter()
 3179                .map(|s| {
 3180                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3181                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3182                })
 3183                .collect();
 3184            self.update_restoration_data(cx, |data| {
 3185                data.selections = inmemory_selections;
 3186            });
 3187
 3188            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3189                && let Some(workspace_id) =
 3190                    self.workspace.as_ref().and_then(|workspace| workspace.1)
 3191            {
 3192                let snapshot = self.buffer().read(cx).snapshot(cx);
 3193                let selections = selections.clone();
 3194                let background_executor = cx.background_executor().clone();
 3195                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3196                self.serialize_selections = cx.background_spawn(async move {
 3197                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3198                    let db_selections = selections
 3199                        .iter()
 3200                        .map(|selection| {
 3201                            (
 3202                                selection.start.to_offset(&snapshot),
 3203                                selection.end.to_offset(&snapshot),
 3204                            )
 3205                        })
 3206                        .collect();
 3207
 3208                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3209                        .await
 3210                        .with_context(|| {
 3211                            format!(
 3212                                "persisting editor selections for editor {editor_id}, \
 3213                                workspace {workspace_id:?}"
 3214                            )
 3215                        })
 3216                        .log_err();
 3217                });
 3218            }
 3219        }
 3220
 3221        cx.notify();
 3222    }
 3223
 3224    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3225        use text::ToOffset as _;
 3226        use text::ToPoint as _;
 3227
 3228        if self.mode.is_minimap()
 3229            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3230        {
 3231            return;
 3232        }
 3233
 3234        if !self.buffer().read(cx).is_singleton() {
 3235            return;
 3236        }
 3237
 3238        let display_snapshot = self
 3239            .display_map
 3240            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3241        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3242            return;
 3243        };
 3244        let inmemory_folds = display_snapshot
 3245            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3246            .map(|fold| {
 3247                fold.range.start.text_anchor.to_point(&snapshot)
 3248                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3249            })
 3250            .collect();
 3251        self.update_restoration_data(cx, |data| {
 3252            data.folds = inmemory_folds;
 3253        });
 3254
 3255        let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) else {
 3256            return;
 3257        };
 3258        let background_executor = cx.background_executor().clone();
 3259        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3260        let db_folds = display_snapshot
 3261            .folds_in_range(0..display_snapshot.buffer_snapshot().len())
 3262            .map(|fold| {
 3263                (
 3264                    fold.range.start.text_anchor.to_offset(&snapshot),
 3265                    fold.range.end.text_anchor.to_offset(&snapshot),
 3266                )
 3267            })
 3268            .collect();
 3269        self.serialize_folds = cx.background_spawn(async move {
 3270            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3271            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3272                .await
 3273                .with_context(|| {
 3274                    format!(
 3275                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3276                    )
 3277                })
 3278                .log_err();
 3279        });
 3280    }
 3281
 3282    pub fn sync_selections(
 3283        &mut self,
 3284        other: Entity<Editor>,
 3285        cx: &mut Context<Self>,
 3286    ) -> gpui::Subscription {
 3287        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3288        if !other_selections.is_empty() {
 3289            self.selections.change_with(cx, |selections| {
 3290                selections.select_anchors(other_selections);
 3291            });
 3292        }
 3293
 3294        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3295            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3296                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3297                if other_selections.is_empty() {
 3298                    return;
 3299                }
 3300                this.selections.change_with(cx, |selections| {
 3301                    selections.select_anchors(other_selections);
 3302                });
 3303            }
 3304        });
 3305
 3306        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3307            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3308                let these_selections = this.selections.disjoint_anchors().to_vec();
 3309                if these_selections.is_empty() {
 3310                    return;
 3311                }
 3312                other.update(cx, |other_editor, cx| {
 3313                    other_editor.selections.change_with(cx, |selections| {
 3314                        selections.select_anchors(these_selections);
 3315                    })
 3316                });
 3317            }
 3318        });
 3319
 3320        Subscription::join(other_subscription, this_subscription)
 3321    }
 3322
 3323    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3324    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3325    /// effects of selection change occur at the end of the transaction.
 3326    pub fn change_selections<R>(
 3327        &mut self,
 3328        effects: SelectionEffects,
 3329        window: &mut Window,
 3330        cx: &mut Context<Self>,
 3331        change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
 3332    ) -> R {
 3333        if let Some(state) = &mut self.deferred_selection_effects_state {
 3334            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3335            state.effects.completions = effects.completions;
 3336            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3337            let (changed, result) = self.selections.change_with(cx, change);
 3338            state.changed |= changed;
 3339            return result;
 3340        }
 3341        let mut state = DeferredSelectionEffectsState {
 3342            changed: false,
 3343            effects,
 3344            old_cursor_position: self.selections.newest_anchor().head(),
 3345            history_entry: SelectionHistoryEntry {
 3346                selections: self.selections.disjoint_anchors_arc(),
 3347                select_next_state: self.select_next_state.clone(),
 3348                select_prev_state: self.select_prev_state.clone(),
 3349                add_selections_state: self.add_selections_state.clone(),
 3350            },
 3351        };
 3352        let (changed, result) = self.selections.change_with(cx, change);
 3353        state.changed = state.changed || changed;
 3354        if self.defer_selection_effects {
 3355            self.deferred_selection_effects_state = Some(state);
 3356        } else {
 3357            self.apply_selection_effects(state, window, cx);
 3358        }
 3359        result
 3360    }
 3361
 3362    /// Defers the effects of selection change, so that the effects of multiple calls to
 3363    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3364    /// to selection history and the state of popovers based on selection position aren't
 3365    /// erroneously updated.
 3366    pub fn with_selection_effects_deferred<R>(
 3367        &mut self,
 3368        window: &mut Window,
 3369        cx: &mut Context<Self>,
 3370        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3371    ) -> R {
 3372        let already_deferred = self.defer_selection_effects;
 3373        self.defer_selection_effects = true;
 3374        let result = update(self, window, cx);
 3375        if !already_deferred {
 3376            self.defer_selection_effects = false;
 3377            if let Some(state) = self.deferred_selection_effects_state.take() {
 3378                self.apply_selection_effects(state, window, cx);
 3379            }
 3380        }
 3381        result
 3382    }
 3383
 3384    fn apply_selection_effects(
 3385        &mut self,
 3386        state: DeferredSelectionEffectsState,
 3387        window: &mut Window,
 3388        cx: &mut Context<Self>,
 3389    ) {
 3390        if state.changed {
 3391            self.selection_history.push(state.history_entry);
 3392
 3393            if let Some(autoscroll) = state.effects.scroll {
 3394                self.request_autoscroll(autoscroll, cx);
 3395            }
 3396
 3397            let old_cursor_position = &state.old_cursor_position;
 3398
 3399            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3400
 3401            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3402                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3403            }
 3404        }
 3405    }
 3406
 3407    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3408    where
 3409        I: IntoIterator<Item = (Range<S>, T)>,
 3410        S: ToOffset,
 3411        T: Into<Arc<str>>,
 3412    {
 3413        if self.read_only(cx) {
 3414            return;
 3415        }
 3416
 3417        self.buffer
 3418            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3419    }
 3420
 3421    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3422    where
 3423        I: IntoIterator<Item = (Range<S>, T)>,
 3424        S: ToOffset,
 3425        T: Into<Arc<str>>,
 3426    {
 3427        if self.read_only(cx) {
 3428            return;
 3429        }
 3430
 3431        self.buffer.update(cx, |buffer, cx| {
 3432            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3433        });
 3434    }
 3435
 3436    pub fn edit_with_block_indent<I, S, T>(
 3437        &mut self,
 3438        edits: I,
 3439        original_indent_columns: Vec<Option<u32>>,
 3440        cx: &mut Context<Self>,
 3441    ) where
 3442        I: IntoIterator<Item = (Range<S>, T)>,
 3443        S: ToOffset,
 3444        T: Into<Arc<str>>,
 3445    {
 3446        if self.read_only(cx) {
 3447            return;
 3448        }
 3449
 3450        self.buffer.update(cx, |buffer, cx| {
 3451            buffer.edit(
 3452                edits,
 3453                Some(AutoindentMode::Block {
 3454                    original_indent_columns,
 3455                }),
 3456                cx,
 3457            )
 3458        });
 3459    }
 3460
 3461    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3462        self.hide_context_menu(window, cx);
 3463
 3464        match phase {
 3465            SelectPhase::Begin {
 3466                position,
 3467                add,
 3468                click_count,
 3469            } => self.begin_selection(position, add, click_count, window, cx),
 3470            SelectPhase::BeginColumnar {
 3471                position,
 3472                goal_column,
 3473                reset,
 3474                mode,
 3475            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3476            SelectPhase::Extend {
 3477                position,
 3478                click_count,
 3479            } => self.extend_selection(position, click_count, window, cx),
 3480            SelectPhase::Update {
 3481                position,
 3482                goal_column,
 3483                scroll_delta,
 3484            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3485            SelectPhase::End => self.end_selection(window, cx),
 3486        }
 3487    }
 3488
 3489    fn extend_selection(
 3490        &mut self,
 3491        position: DisplayPoint,
 3492        click_count: usize,
 3493        window: &mut Window,
 3494        cx: &mut Context<Self>,
 3495    ) {
 3496        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3497        let tail = self.selections.newest::<usize>(&display_map).tail();
 3498        let click_count = click_count.max(match self.selections.select_mode() {
 3499            SelectMode::Character => 1,
 3500            SelectMode::Word(_) => 2,
 3501            SelectMode::Line(_) => 3,
 3502            SelectMode::All => 4,
 3503        });
 3504        self.begin_selection(position, false, click_count, window, cx);
 3505
 3506        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3507
 3508        let current_selection = match self.selections.select_mode() {
 3509            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3510            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3511        };
 3512
 3513        let mut pending_selection = self
 3514            .selections
 3515            .pending_anchor()
 3516            .cloned()
 3517            .expect("extend_selection not called with pending selection");
 3518
 3519        if pending_selection
 3520            .start
 3521            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3522            == Ordering::Greater
 3523        {
 3524            pending_selection.start = current_selection.start;
 3525        }
 3526        if pending_selection
 3527            .end
 3528            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3529            == Ordering::Less
 3530        {
 3531            pending_selection.end = current_selection.end;
 3532            pending_selection.reversed = true;
 3533        }
 3534
 3535        let mut pending_mode = self.selections.pending_mode().unwrap();
 3536        match &mut pending_mode {
 3537            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3538            _ => {}
 3539        }
 3540
 3541        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3542            SelectionEffects::scroll(Autoscroll::fit())
 3543        } else {
 3544            SelectionEffects::no_scroll()
 3545        };
 3546
 3547        self.change_selections(effects, window, cx, |s| {
 3548            s.set_pending(pending_selection.clone(), pending_mode);
 3549            s.set_is_extending(true);
 3550        });
 3551    }
 3552
 3553    fn begin_selection(
 3554        &mut self,
 3555        position: DisplayPoint,
 3556        add: bool,
 3557        click_count: usize,
 3558        window: &mut Window,
 3559        cx: &mut Context<Self>,
 3560    ) {
 3561        if !self.focus_handle.is_focused(window) {
 3562            self.last_focused_descendant = None;
 3563            window.focus(&self.focus_handle);
 3564        }
 3565
 3566        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3567        let buffer = display_map.buffer_snapshot();
 3568        let position = display_map.clip_point(position, Bias::Left);
 3569
 3570        let start;
 3571        let end;
 3572        let mode;
 3573        let mut auto_scroll;
 3574        match click_count {
 3575            1 => {
 3576                start = buffer.anchor_before(position.to_point(&display_map));
 3577                end = start;
 3578                mode = SelectMode::Character;
 3579                auto_scroll = true;
 3580            }
 3581            2 => {
 3582                let position = display_map
 3583                    .clip_point(position, Bias::Left)
 3584                    .to_offset(&display_map, Bias::Left);
 3585                let (range, _) = buffer.surrounding_word(position, None);
 3586                start = buffer.anchor_before(range.start);
 3587                end = buffer.anchor_before(range.end);
 3588                mode = SelectMode::Word(start..end);
 3589                auto_scroll = true;
 3590            }
 3591            3 => {
 3592                let position = display_map
 3593                    .clip_point(position, Bias::Left)
 3594                    .to_point(&display_map);
 3595                let line_start = display_map.prev_line_boundary(position).0;
 3596                let next_line_start = buffer.clip_point(
 3597                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3598                    Bias::Left,
 3599                );
 3600                start = buffer.anchor_before(line_start);
 3601                end = buffer.anchor_before(next_line_start);
 3602                mode = SelectMode::Line(start..end);
 3603                auto_scroll = true;
 3604            }
 3605            _ => {
 3606                start = buffer.anchor_before(0);
 3607                end = buffer.anchor_before(buffer.len());
 3608                mode = SelectMode::All;
 3609                auto_scroll = false;
 3610            }
 3611        }
 3612        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3613
 3614        let point_to_delete: Option<usize> = {
 3615            let selected_points: Vec<Selection<Point>> =
 3616                self.selections.disjoint_in_range(start..end, &display_map);
 3617
 3618            if !add || click_count > 1 {
 3619                None
 3620            } else if !selected_points.is_empty() {
 3621                Some(selected_points[0].id)
 3622            } else {
 3623                let clicked_point_already_selected =
 3624                    self.selections.disjoint_anchors().iter().find(|selection| {
 3625                        selection.start.to_point(buffer) == start.to_point(buffer)
 3626                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3627                    });
 3628
 3629                clicked_point_already_selected.map(|selection| selection.id)
 3630            }
 3631        };
 3632
 3633        let selections_count = self.selections.count();
 3634        let effects = if auto_scroll {
 3635            SelectionEffects::default()
 3636        } else {
 3637            SelectionEffects::no_scroll()
 3638        };
 3639
 3640        self.change_selections(effects, window, cx, |s| {
 3641            if let Some(point_to_delete) = point_to_delete {
 3642                s.delete(point_to_delete);
 3643
 3644                if selections_count == 1 {
 3645                    s.set_pending_anchor_range(start..end, mode);
 3646                }
 3647            } else {
 3648                if !add {
 3649                    s.clear_disjoint();
 3650                }
 3651
 3652                s.set_pending_anchor_range(start..end, mode);
 3653            }
 3654        });
 3655    }
 3656
 3657    fn begin_columnar_selection(
 3658        &mut self,
 3659        position: DisplayPoint,
 3660        goal_column: u32,
 3661        reset: bool,
 3662        mode: ColumnarMode,
 3663        window: &mut Window,
 3664        cx: &mut Context<Self>,
 3665    ) {
 3666        if !self.focus_handle.is_focused(window) {
 3667            self.last_focused_descendant = None;
 3668            window.focus(&self.focus_handle);
 3669        }
 3670
 3671        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3672
 3673        if reset {
 3674            let pointer_position = display_map
 3675                .buffer_snapshot()
 3676                .anchor_before(position.to_point(&display_map));
 3677
 3678            self.change_selections(
 3679                SelectionEffects::scroll(Autoscroll::newest()),
 3680                window,
 3681                cx,
 3682                |s| {
 3683                    s.clear_disjoint();
 3684                    s.set_pending_anchor_range(
 3685                        pointer_position..pointer_position,
 3686                        SelectMode::Character,
 3687                    );
 3688                },
 3689            );
 3690        };
 3691
 3692        let tail = self.selections.newest::<Point>(&display_map).tail();
 3693        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3694        self.columnar_selection_state = match mode {
 3695            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3696                selection_tail: selection_anchor,
 3697                display_point: if reset {
 3698                    if position.column() != goal_column {
 3699                        Some(DisplayPoint::new(position.row(), goal_column))
 3700                    } else {
 3701                        None
 3702                    }
 3703                } else {
 3704                    None
 3705                },
 3706            }),
 3707            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3708                selection_tail: selection_anchor,
 3709            }),
 3710        };
 3711
 3712        if !reset {
 3713            self.select_columns(position, goal_column, &display_map, window, cx);
 3714        }
 3715    }
 3716
 3717    fn update_selection(
 3718        &mut self,
 3719        position: DisplayPoint,
 3720        goal_column: u32,
 3721        scroll_delta: gpui::Point<f32>,
 3722        window: &mut Window,
 3723        cx: &mut Context<Self>,
 3724    ) {
 3725        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3726
 3727        if self.columnar_selection_state.is_some() {
 3728            self.select_columns(position, goal_column, &display_map, window, cx);
 3729        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3730            let buffer = display_map.buffer_snapshot();
 3731            let head;
 3732            let tail;
 3733            let mode = self.selections.pending_mode().unwrap();
 3734            match &mode {
 3735                SelectMode::Character => {
 3736                    head = position.to_point(&display_map);
 3737                    tail = pending.tail().to_point(buffer);
 3738                }
 3739                SelectMode::Word(original_range) => {
 3740                    let offset = display_map
 3741                        .clip_point(position, Bias::Left)
 3742                        .to_offset(&display_map, Bias::Left);
 3743                    let original_range = original_range.to_offset(buffer);
 3744
 3745                    let head_offset = if buffer.is_inside_word(offset, None)
 3746                        || original_range.contains(&offset)
 3747                    {
 3748                        let (word_range, _) = buffer.surrounding_word(offset, None);
 3749                        if word_range.start < original_range.start {
 3750                            word_range.start
 3751                        } else {
 3752                            word_range.end
 3753                        }
 3754                    } else {
 3755                        offset
 3756                    };
 3757
 3758                    head = head_offset.to_point(buffer);
 3759                    if head_offset <= original_range.start {
 3760                        tail = original_range.end.to_point(buffer);
 3761                    } else {
 3762                        tail = original_range.start.to_point(buffer);
 3763                    }
 3764                }
 3765                SelectMode::Line(original_range) => {
 3766                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 3767
 3768                    let position = display_map
 3769                        .clip_point(position, Bias::Left)
 3770                        .to_point(&display_map);
 3771                    let line_start = display_map.prev_line_boundary(position).0;
 3772                    let next_line_start = buffer.clip_point(
 3773                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3774                        Bias::Left,
 3775                    );
 3776
 3777                    if line_start < original_range.start {
 3778                        head = line_start
 3779                    } else {
 3780                        head = next_line_start
 3781                    }
 3782
 3783                    if head <= original_range.start {
 3784                        tail = original_range.end;
 3785                    } else {
 3786                        tail = original_range.start;
 3787                    }
 3788                }
 3789                SelectMode::All => {
 3790                    return;
 3791                }
 3792            };
 3793
 3794            if head < tail {
 3795                pending.start = buffer.anchor_before(head);
 3796                pending.end = buffer.anchor_before(tail);
 3797                pending.reversed = true;
 3798            } else {
 3799                pending.start = buffer.anchor_before(tail);
 3800                pending.end = buffer.anchor_before(head);
 3801                pending.reversed = false;
 3802            }
 3803
 3804            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3805                s.set_pending(pending.clone(), mode);
 3806            });
 3807        } else {
 3808            log::error!("update_selection dispatched with no pending selection");
 3809            return;
 3810        }
 3811
 3812        self.apply_scroll_delta(scroll_delta, window, cx);
 3813        cx.notify();
 3814    }
 3815
 3816    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 3817        self.columnar_selection_state.take();
 3818        if let Some(pending_mode) = self.selections.pending_mode() {
 3819            let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 3820            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3821                s.select(selections);
 3822                s.clear_pending();
 3823                if s.is_extending() {
 3824                    s.set_is_extending(false);
 3825                } else {
 3826                    s.set_select_mode(pending_mode);
 3827                }
 3828            });
 3829        }
 3830    }
 3831
 3832    fn select_columns(
 3833        &mut self,
 3834        head: DisplayPoint,
 3835        goal_column: u32,
 3836        display_map: &DisplaySnapshot,
 3837        window: &mut Window,
 3838        cx: &mut Context<Self>,
 3839    ) {
 3840        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 3841            return;
 3842        };
 3843
 3844        let tail = match columnar_state {
 3845            ColumnarSelectionState::FromMouse {
 3846                selection_tail,
 3847                display_point,
 3848            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 3849            ColumnarSelectionState::FromSelection { selection_tail } => {
 3850                selection_tail.to_display_point(display_map)
 3851            }
 3852        };
 3853
 3854        let start_row = cmp::min(tail.row(), head.row());
 3855        let end_row = cmp::max(tail.row(), head.row());
 3856        let start_column = cmp::min(tail.column(), goal_column);
 3857        let end_column = cmp::max(tail.column(), goal_column);
 3858        let reversed = start_column < tail.column();
 3859
 3860        let selection_ranges = (start_row.0..=end_row.0)
 3861            .map(DisplayRow)
 3862            .filter_map(|row| {
 3863                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 3864                    || start_column <= display_map.line_len(row))
 3865                    && !display_map.is_block_line(row)
 3866                {
 3867                    let start = display_map
 3868                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 3869                        .to_point(display_map);
 3870                    let end = display_map
 3871                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 3872                        .to_point(display_map);
 3873                    if reversed {
 3874                        Some(end..start)
 3875                    } else {
 3876                        Some(start..end)
 3877                    }
 3878                } else {
 3879                    None
 3880                }
 3881            })
 3882            .collect::<Vec<_>>();
 3883        if selection_ranges.is_empty() {
 3884            return;
 3885        }
 3886
 3887        let ranges = match columnar_state {
 3888            ColumnarSelectionState::FromMouse { .. } => {
 3889                let mut non_empty_ranges = selection_ranges
 3890                    .iter()
 3891                    .filter(|selection_range| selection_range.start != selection_range.end)
 3892                    .peekable();
 3893                if non_empty_ranges.peek().is_some() {
 3894                    non_empty_ranges.cloned().collect()
 3895                } else {
 3896                    selection_ranges
 3897                }
 3898            }
 3899            _ => selection_ranges,
 3900        };
 3901
 3902        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 3903            s.select_ranges(ranges);
 3904        });
 3905        cx.notify();
 3906    }
 3907
 3908    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 3909        self.selections
 3910            .all_adjusted(snapshot)
 3911            .iter()
 3912            .any(|selection| !selection.is_empty())
 3913    }
 3914
 3915    pub fn has_pending_nonempty_selection(&self) -> bool {
 3916        let pending_nonempty_selection = match self.selections.pending_anchor() {
 3917            Some(Selection { start, end, .. }) => start != end,
 3918            None => false,
 3919        };
 3920
 3921        pending_nonempty_selection
 3922            || (self.columnar_selection_state.is_some()
 3923                && self.selections.disjoint_anchors().len() > 1)
 3924    }
 3925
 3926    pub fn has_pending_selection(&self) -> bool {
 3927        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 3928    }
 3929
 3930    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 3931        self.selection_mark_mode = false;
 3932        self.selection_drag_state = SelectionDragState::None;
 3933
 3934        if self.clear_expanded_diff_hunks(cx) {
 3935            cx.notify();
 3936            return;
 3937        }
 3938        if self.dismiss_menus_and_popups(true, window, cx) {
 3939            return;
 3940        }
 3941
 3942        if self.mode.is_full()
 3943            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 3944        {
 3945            return;
 3946        }
 3947
 3948        cx.propagate();
 3949    }
 3950
 3951    pub fn dismiss_menus_and_popups(
 3952        &mut self,
 3953        is_user_requested: bool,
 3954        window: &mut Window,
 3955        cx: &mut Context<Self>,
 3956    ) -> bool {
 3957        if self.take_rename(false, window, cx).is_some() {
 3958            return true;
 3959        }
 3960
 3961        if self.hide_blame_popover(true, cx) {
 3962            return true;
 3963        }
 3964
 3965        if hide_hover(self, cx) {
 3966            return true;
 3967        }
 3968
 3969        if self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape) {
 3970            return true;
 3971        }
 3972
 3973        if self.hide_context_menu(window, cx).is_some() {
 3974            return true;
 3975        }
 3976
 3977        if self.mouse_context_menu.take().is_some() {
 3978            return true;
 3979        }
 3980
 3981        if is_user_requested && self.discard_edit_prediction(true, cx) {
 3982            return true;
 3983        }
 3984
 3985        if self.snippet_stack.pop().is_some() {
 3986            return true;
 3987        }
 3988
 3989        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 3990            self.dismiss_diagnostics(cx);
 3991            return true;
 3992        }
 3993
 3994        false
 3995    }
 3996
 3997    fn linked_editing_ranges_for(
 3998        &self,
 3999        selection: Range<text::Anchor>,
 4000        cx: &App,
 4001    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4002        if self.linked_edit_ranges.is_empty() {
 4003            return None;
 4004        }
 4005        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4006            selection.end.buffer_id.and_then(|end_buffer_id| {
 4007                if selection.start.buffer_id != Some(end_buffer_id) {
 4008                    return None;
 4009                }
 4010                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4011                let snapshot = buffer.read(cx).snapshot();
 4012                self.linked_edit_ranges
 4013                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4014                    .map(|ranges| (ranges, snapshot, buffer))
 4015            })?;
 4016        use text::ToOffset as TO;
 4017        // find offset from the start of current range to current cursor position
 4018        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4019
 4020        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4021        let start_difference = start_offset - start_byte_offset;
 4022        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4023        let end_difference = end_offset - start_byte_offset;
 4024        // Current range has associated linked ranges.
 4025        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4026        for range in linked_ranges.iter() {
 4027            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4028            let end_offset = start_offset + end_difference;
 4029            let start_offset = start_offset + start_difference;
 4030            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4031                continue;
 4032            }
 4033            if self.selections.disjoint_anchor_ranges().any(|s| {
 4034                if s.start.buffer_id != selection.start.buffer_id
 4035                    || s.end.buffer_id != selection.end.buffer_id
 4036                {
 4037                    return false;
 4038                }
 4039                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4040                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4041            }) {
 4042                continue;
 4043            }
 4044            let start = buffer_snapshot.anchor_after(start_offset);
 4045            let end = buffer_snapshot.anchor_after(end_offset);
 4046            linked_edits
 4047                .entry(buffer.clone())
 4048                .or_default()
 4049                .push(start..end);
 4050        }
 4051        Some(linked_edits)
 4052    }
 4053
 4054    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4055        let text: Arc<str> = text.into();
 4056
 4057        if self.read_only(cx) {
 4058            return;
 4059        }
 4060
 4061        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4062
 4063        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4064        let mut bracket_inserted = false;
 4065        let mut edits = Vec::new();
 4066        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4067        let mut new_selections = Vec::with_capacity(selections.len());
 4068        let mut new_autoclose_regions = Vec::new();
 4069        let snapshot = self.buffer.read(cx).read(cx);
 4070        let mut clear_linked_edit_ranges = false;
 4071
 4072        for (selection, autoclose_region) in
 4073            self.selections_with_autoclose_regions(selections, &snapshot)
 4074        {
 4075            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4076                // Determine if the inserted text matches the opening or closing
 4077                // bracket of any of this language's bracket pairs.
 4078                let mut bracket_pair = None;
 4079                let mut is_bracket_pair_start = false;
 4080                let mut is_bracket_pair_end = false;
 4081                if !text.is_empty() {
 4082                    let mut bracket_pair_matching_end = None;
 4083                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4084                    //  and they are removing the character that triggered IME popup.
 4085                    for (pair, enabled) in scope.brackets() {
 4086                        if !pair.close && !pair.surround {
 4087                            continue;
 4088                        }
 4089
 4090                        if enabled && pair.start.ends_with(text.as_ref()) {
 4091                            let prefix_len = pair.start.len() - text.len();
 4092                            let preceding_text_matches_prefix = prefix_len == 0
 4093                                || (selection.start.column >= (prefix_len as u32)
 4094                                    && snapshot.contains_str_at(
 4095                                        Point::new(
 4096                                            selection.start.row,
 4097                                            selection.start.column - (prefix_len as u32),
 4098                                        ),
 4099                                        &pair.start[..prefix_len],
 4100                                    ));
 4101                            if preceding_text_matches_prefix {
 4102                                bracket_pair = Some(pair.clone());
 4103                                is_bracket_pair_start = true;
 4104                                break;
 4105                            }
 4106                        }
 4107                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4108                        {
 4109                            // take first bracket pair matching end, but don't break in case a later bracket
 4110                            // pair matches start
 4111                            bracket_pair_matching_end = Some(pair.clone());
 4112                        }
 4113                    }
 4114                    if let Some(end) = bracket_pair_matching_end
 4115                        && bracket_pair.is_none()
 4116                    {
 4117                        bracket_pair = Some(end);
 4118                        is_bracket_pair_end = true;
 4119                    }
 4120                }
 4121
 4122                if let Some(bracket_pair) = bracket_pair {
 4123                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4124                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4125                    let auto_surround =
 4126                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4127                    if selection.is_empty() {
 4128                        if is_bracket_pair_start {
 4129                            // If the inserted text is a suffix of an opening bracket and the
 4130                            // selection is preceded by the rest of the opening bracket, then
 4131                            // insert the closing bracket.
 4132                            let following_text_allows_autoclose = snapshot
 4133                                .chars_at(selection.start)
 4134                                .next()
 4135                                .is_none_or(|c| scope.should_autoclose_before(c));
 4136
 4137                            let preceding_text_allows_autoclose = selection.start.column == 0
 4138                                || snapshot
 4139                                    .reversed_chars_at(selection.start)
 4140                                    .next()
 4141                                    .is_none_or(|c| {
 4142                                        bracket_pair.start != bracket_pair.end
 4143                                            || !snapshot
 4144                                                .char_classifier_at(selection.start)
 4145                                                .is_word(c)
 4146                                    });
 4147
 4148                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4149                                && bracket_pair.start.len() == 1
 4150                            {
 4151                                let target = bracket_pair.start.chars().next().unwrap();
 4152                                let current_line_count = snapshot
 4153                                    .reversed_chars_at(selection.start)
 4154                                    .take_while(|&c| c != '\n')
 4155                                    .filter(|&c| c == target)
 4156                                    .count();
 4157                                current_line_count % 2 == 1
 4158                            } else {
 4159                                false
 4160                            };
 4161
 4162                            if autoclose
 4163                                && bracket_pair.close
 4164                                && following_text_allows_autoclose
 4165                                && preceding_text_allows_autoclose
 4166                                && !is_closing_quote
 4167                            {
 4168                                let anchor = snapshot.anchor_before(selection.end);
 4169                                new_selections.push((selection.map(|_| anchor), text.len()));
 4170                                new_autoclose_regions.push((
 4171                                    anchor,
 4172                                    text.len(),
 4173                                    selection.id,
 4174                                    bracket_pair.clone(),
 4175                                ));
 4176                                edits.push((
 4177                                    selection.range(),
 4178                                    format!("{}{}", text, bracket_pair.end).into(),
 4179                                ));
 4180                                bracket_inserted = true;
 4181                                continue;
 4182                            }
 4183                        }
 4184
 4185                        if let Some(region) = autoclose_region {
 4186                            // If the selection is followed by an auto-inserted closing bracket,
 4187                            // then don't insert that closing bracket again; just move the selection
 4188                            // past the closing bracket.
 4189                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4190                                && text.as_ref() == region.pair.end.as_str()
 4191                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4192                            if should_skip {
 4193                                let anchor = snapshot.anchor_after(selection.end);
 4194                                new_selections
 4195                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4196                                continue;
 4197                            }
 4198                        }
 4199
 4200                        let always_treat_brackets_as_autoclosed = snapshot
 4201                            .language_settings_at(selection.start, cx)
 4202                            .always_treat_brackets_as_autoclosed;
 4203                        if always_treat_brackets_as_autoclosed
 4204                            && is_bracket_pair_end
 4205                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4206                        {
 4207                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4208                            // and the inserted text is a closing bracket and the selection is followed
 4209                            // by the closing bracket then move the selection past the closing bracket.
 4210                            let anchor = snapshot.anchor_after(selection.end);
 4211                            new_selections.push((selection.map(|_| anchor), text.len()));
 4212                            continue;
 4213                        }
 4214                    }
 4215                    // If an opening bracket is 1 character long and is typed while
 4216                    // text is selected, then surround that text with the bracket pair.
 4217                    else if auto_surround
 4218                        && bracket_pair.surround
 4219                        && is_bracket_pair_start
 4220                        && bracket_pair.start.chars().count() == 1
 4221                    {
 4222                        edits.push((selection.start..selection.start, text.clone()));
 4223                        edits.push((
 4224                            selection.end..selection.end,
 4225                            bracket_pair.end.as_str().into(),
 4226                        ));
 4227                        bracket_inserted = true;
 4228                        new_selections.push((
 4229                            Selection {
 4230                                id: selection.id,
 4231                                start: snapshot.anchor_after(selection.start),
 4232                                end: snapshot.anchor_before(selection.end),
 4233                                reversed: selection.reversed,
 4234                                goal: selection.goal,
 4235                            },
 4236                            0,
 4237                        ));
 4238                        continue;
 4239                    }
 4240                }
 4241            }
 4242
 4243            if self.auto_replace_emoji_shortcode
 4244                && selection.is_empty()
 4245                && text.as_ref().ends_with(':')
 4246                && let Some(possible_emoji_short_code) =
 4247                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4248                && !possible_emoji_short_code.is_empty()
 4249                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4250            {
 4251                let emoji_shortcode_start = Point::new(
 4252                    selection.start.row,
 4253                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4254                );
 4255
 4256                // Remove shortcode from buffer
 4257                edits.push((
 4258                    emoji_shortcode_start..selection.start,
 4259                    "".to_string().into(),
 4260                ));
 4261                new_selections.push((
 4262                    Selection {
 4263                        id: selection.id,
 4264                        start: snapshot.anchor_after(emoji_shortcode_start),
 4265                        end: snapshot.anchor_before(selection.start),
 4266                        reversed: selection.reversed,
 4267                        goal: selection.goal,
 4268                    },
 4269                    0,
 4270                ));
 4271
 4272                // Insert emoji
 4273                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4274                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4275                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4276
 4277                continue;
 4278            }
 4279
 4280            // If not handling any auto-close operation, then just replace the selected
 4281            // text with the given input and move the selection to the end of the
 4282            // newly inserted text.
 4283            let anchor = snapshot.anchor_after(selection.end);
 4284            if !self.linked_edit_ranges.is_empty() {
 4285                let start_anchor = snapshot.anchor_before(selection.start);
 4286
 4287                let is_word_char = text.chars().next().is_none_or(|char| {
 4288                    let classifier = snapshot
 4289                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4290                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4291                    classifier.is_word(char)
 4292                });
 4293
 4294                if is_word_char {
 4295                    if let Some(ranges) = self
 4296                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4297                    {
 4298                        for (buffer, edits) in ranges {
 4299                            linked_edits
 4300                                .entry(buffer.clone())
 4301                                .or_default()
 4302                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4303                        }
 4304                    }
 4305                } else {
 4306                    clear_linked_edit_ranges = true;
 4307                }
 4308            }
 4309
 4310            new_selections.push((selection.map(|_| anchor), 0));
 4311            edits.push((selection.start..selection.end, text.clone()));
 4312        }
 4313
 4314        drop(snapshot);
 4315
 4316        self.transact(window, cx, |this, window, cx| {
 4317            if clear_linked_edit_ranges {
 4318                this.linked_edit_ranges.clear();
 4319            }
 4320            let initial_buffer_versions =
 4321                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4322
 4323            this.buffer.update(cx, |buffer, cx| {
 4324                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4325            });
 4326            for (buffer, edits) in linked_edits {
 4327                buffer.update(cx, |buffer, cx| {
 4328                    let snapshot = buffer.snapshot();
 4329                    let edits = edits
 4330                        .into_iter()
 4331                        .map(|(range, text)| {
 4332                            use text::ToPoint as TP;
 4333                            let end_point = TP::to_point(&range.end, &snapshot);
 4334                            let start_point = TP::to_point(&range.start, &snapshot);
 4335                            (start_point..end_point, text)
 4336                        })
 4337                        .sorted_by_key(|(range, _)| range.start);
 4338                    buffer.edit(edits, None, cx);
 4339                })
 4340            }
 4341            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4342            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4343            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4344            let new_selections =
 4345                resolve_selections_wrapping_blocks::<usize, _>(new_anchor_selections, &map)
 4346                    .zip(new_selection_deltas)
 4347                    .map(|(selection, delta)| Selection {
 4348                        id: selection.id,
 4349                        start: selection.start + delta,
 4350                        end: selection.end + delta,
 4351                        reversed: selection.reversed,
 4352                        goal: SelectionGoal::None,
 4353                    })
 4354                    .collect::<Vec<_>>();
 4355
 4356            let mut i = 0;
 4357            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4358                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4359                let start = map.buffer_snapshot().anchor_before(position);
 4360                let end = map.buffer_snapshot().anchor_after(position);
 4361                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4362                    match existing_state
 4363                        .range
 4364                        .start
 4365                        .cmp(&start, map.buffer_snapshot())
 4366                    {
 4367                        Ordering::Less => i += 1,
 4368                        Ordering::Greater => break,
 4369                        Ordering::Equal => {
 4370                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4371                                Ordering::Less => i += 1,
 4372                                Ordering::Equal => break,
 4373                                Ordering::Greater => break,
 4374                            }
 4375                        }
 4376                    }
 4377                }
 4378                this.autoclose_regions.insert(
 4379                    i,
 4380                    AutocloseRegion {
 4381                        selection_id,
 4382                        range: start..end,
 4383                        pair,
 4384                    },
 4385                );
 4386            }
 4387
 4388            let had_active_edit_prediction = this.has_active_edit_prediction();
 4389            this.change_selections(
 4390                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4391                window,
 4392                cx,
 4393                |s| s.select(new_selections),
 4394            );
 4395
 4396            if !bracket_inserted
 4397                && let Some(on_type_format_task) =
 4398                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4399            {
 4400                on_type_format_task.detach_and_log_err(cx);
 4401            }
 4402
 4403            let editor_settings = EditorSettings::get_global(cx);
 4404            if bracket_inserted
 4405                && (editor_settings.auto_signature_help
 4406                    || editor_settings.show_signature_help_after_edits)
 4407            {
 4408                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4409            }
 4410
 4411            let trigger_in_words =
 4412                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4413            if this.hard_wrap.is_some() {
 4414                let latest: Range<Point> = this.selections.newest(&map).range();
 4415                if latest.is_empty()
 4416                    && this
 4417                        .buffer()
 4418                        .read(cx)
 4419                        .snapshot(cx)
 4420                        .line_len(MultiBufferRow(latest.start.row))
 4421                        == latest.start.column
 4422                {
 4423                    this.rewrap_impl(
 4424                        RewrapOptions {
 4425                            override_language_settings: true,
 4426                            preserve_existing_whitespace: true,
 4427                        },
 4428                        cx,
 4429                    )
 4430                }
 4431            }
 4432            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4433            refresh_linked_ranges(this, window, cx);
 4434            this.refresh_edit_prediction(true, false, window, cx);
 4435            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4436        });
 4437    }
 4438
 4439    fn find_possible_emoji_shortcode_at_position(
 4440        snapshot: &MultiBufferSnapshot,
 4441        position: Point,
 4442    ) -> Option<String> {
 4443        let mut chars = Vec::new();
 4444        let mut found_colon = false;
 4445        for char in snapshot.reversed_chars_at(position).take(100) {
 4446            // Found a possible emoji shortcode in the middle of the buffer
 4447            if found_colon {
 4448                if char.is_whitespace() {
 4449                    chars.reverse();
 4450                    return Some(chars.iter().collect());
 4451                }
 4452                // If the previous character is not a whitespace, we are in the middle of a word
 4453                // and we only want to complete the shortcode if the word is made up of other emojis
 4454                let mut containing_word = String::new();
 4455                for ch in snapshot
 4456                    .reversed_chars_at(position)
 4457                    .skip(chars.len() + 1)
 4458                    .take(100)
 4459                {
 4460                    if ch.is_whitespace() {
 4461                        break;
 4462                    }
 4463                    containing_word.push(ch);
 4464                }
 4465                let containing_word = containing_word.chars().rev().collect::<String>();
 4466                if util::word_consists_of_emojis(containing_word.as_str()) {
 4467                    chars.reverse();
 4468                    return Some(chars.iter().collect());
 4469                }
 4470            }
 4471
 4472            if char.is_whitespace() || !char.is_ascii() {
 4473                return None;
 4474            }
 4475            if char == ':' {
 4476                found_colon = true;
 4477            } else {
 4478                chars.push(char);
 4479            }
 4480        }
 4481        // Found a possible emoji shortcode at the beginning of the buffer
 4482        chars.reverse();
 4483        Some(chars.iter().collect())
 4484    }
 4485
 4486    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4487        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4488        self.transact(window, cx, |this, window, cx| {
 4489            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4490                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
 4491                let multi_buffer = this.buffer.read(cx);
 4492                let buffer = multi_buffer.snapshot(cx);
 4493                selections
 4494                    .iter()
 4495                    .map(|selection| {
 4496                        let start_point = selection.start.to_point(&buffer);
 4497                        let mut existing_indent =
 4498                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4499                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4500                        let start = selection.start;
 4501                        let end = selection.end;
 4502                        let selection_is_empty = start == end;
 4503                        let language_scope = buffer.language_scope_at(start);
 4504                        let (
 4505                            comment_delimiter,
 4506                            doc_delimiter,
 4507                            insert_extra_newline,
 4508                            indent_on_newline,
 4509                            indent_on_extra_newline,
 4510                        ) = if let Some(language) = &language_scope {
 4511                            let mut insert_extra_newline =
 4512                                insert_extra_newline_brackets(&buffer, start..end, language)
 4513                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4514
 4515                            // Comment extension on newline is allowed only for cursor selections
 4516                            let comment_delimiter = maybe!({
 4517                                if !selection_is_empty {
 4518                                    return None;
 4519                                }
 4520
 4521                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4522                                    return None;
 4523                                }
 4524
 4525                                let delimiters = language.line_comment_prefixes();
 4526                                let max_len_of_delimiter =
 4527                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4528                                let (snapshot, range) =
 4529                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4530
 4531                                let num_of_whitespaces = snapshot
 4532                                    .chars_for_range(range.clone())
 4533                                    .take_while(|c| c.is_whitespace())
 4534                                    .count();
 4535                                let comment_candidate = snapshot
 4536                                    .chars_for_range(range.clone())
 4537                                    .skip(num_of_whitespaces)
 4538                                    .take(max_len_of_delimiter)
 4539                                    .collect::<String>();
 4540                                let (delimiter, trimmed_len) = delimiters
 4541                                    .iter()
 4542                                    .filter_map(|delimiter| {
 4543                                        let prefix = delimiter.trim_end();
 4544                                        if comment_candidate.starts_with(prefix) {
 4545                                            Some((delimiter, prefix.len()))
 4546                                        } else {
 4547                                            None
 4548                                        }
 4549                                    })
 4550                                    .max_by_key(|(_, len)| *len)?;
 4551
 4552                                if let Some(BlockCommentConfig {
 4553                                    start: block_start, ..
 4554                                }) = language.block_comment()
 4555                                {
 4556                                    let block_start_trimmed = block_start.trim_end();
 4557                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4558                                        let line_content = snapshot
 4559                                            .chars_for_range(range)
 4560                                            .skip(num_of_whitespaces)
 4561                                            .take(block_start_trimmed.len())
 4562                                            .collect::<String>();
 4563
 4564                                        if line_content.starts_with(block_start_trimmed) {
 4565                                            return None;
 4566                                        }
 4567                                    }
 4568                                }
 4569
 4570                                let cursor_is_placed_after_comment_marker =
 4571                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4572                                if cursor_is_placed_after_comment_marker {
 4573                                    Some(delimiter.clone())
 4574                                } else {
 4575                                    None
 4576                                }
 4577                            });
 4578
 4579                            let mut indent_on_newline = IndentSize::spaces(0);
 4580                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4581
 4582                            let doc_delimiter = maybe!({
 4583                                if !selection_is_empty {
 4584                                    return None;
 4585                                }
 4586
 4587                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4588                                    return None;
 4589                                }
 4590
 4591                                let BlockCommentConfig {
 4592                                    start: start_tag,
 4593                                    end: end_tag,
 4594                                    prefix: delimiter,
 4595                                    tab_size: len,
 4596                                } = language.documentation_comment()?;
 4597                                let is_within_block_comment = buffer
 4598                                    .language_scope_at(start_point)
 4599                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4600                                if !is_within_block_comment {
 4601                                    return None;
 4602                                }
 4603
 4604                                let (snapshot, range) =
 4605                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4606
 4607                                let num_of_whitespaces = snapshot
 4608                                    .chars_for_range(range.clone())
 4609                                    .take_while(|c| c.is_whitespace())
 4610                                    .count();
 4611
 4612                                // 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.
 4613                                let column = start_point.column;
 4614                                let cursor_is_after_start_tag = {
 4615                                    let start_tag_len = start_tag.len();
 4616                                    let start_tag_line = snapshot
 4617                                        .chars_for_range(range.clone())
 4618                                        .skip(num_of_whitespaces)
 4619                                        .take(start_tag_len)
 4620                                        .collect::<String>();
 4621                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4622                                        num_of_whitespaces + start_tag_len <= column as usize
 4623                                    } else {
 4624                                        false
 4625                                    }
 4626                                };
 4627
 4628                                let cursor_is_after_delimiter = {
 4629                                    let delimiter_trim = delimiter.trim_end();
 4630                                    let delimiter_line = snapshot
 4631                                        .chars_for_range(range.clone())
 4632                                        .skip(num_of_whitespaces)
 4633                                        .take(delimiter_trim.len())
 4634                                        .collect::<String>();
 4635                                    if delimiter_line.starts_with(delimiter_trim) {
 4636                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4637                                    } else {
 4638                                        false
 4639                                    }
 4640                                };
 4641
 4642                                let cursor_is_before_end_tag_if_exists = {
 4643                                    let mut char_position = 0u32;
 4644                                    let mut end_tag_offset = None;
 4645
 4646                                    'outer: for chunk in snapshot.text_for_range(range) {
 4647                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4648                                            let chars_before_match =
 4649                                                chunk[..byte_pos].chars().count() as u32;
 4650                                            end_tag_offset =
 4651                                                Some(char_position + chars_before_match);
 4652                                            break 'outer;
 4653                                        }
 4654                                        char_position += chunk.chars().count() as u32;
 4655                                    }
 4656
 4657                                    if let Some(end_tag_offset) = end_tag_offset {
 4658                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4659                                        if cursor_is_after_start_tag {
 4660                                            if cursor_is_before_end_tag {
 4661                                                insert_extra_newline = true;
 4662                                            }
 4663                                            let cursor_is_at_start_of_end_tag =
 4664                                                column == end_tag_offset;
 4665                                            if cursor_is_at_start_of_end_tag {
 4666                                                indent_on_extra_newline.len = *len;
 4667                                            }
 4668                                        }
 4669                                        cursor_is_before_end_tag
 4670                                    } else {
 4671                                        true
 4672                                    }
 4673                                };
 4674
 4675                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4676                                    && cursor_is_before_end_tag_if_exists
 4677                                {
 4678                                    if cursor_is_after_start_tag {
 4679                                        indent_on_newline.len = *len;
 4680                                    }
 4681                                    Some(delimiter.clone())
 4682                                } else {
 4683                                    None
 4684                                }
 4685                            });
 4686
 4687                            (
 4688                                comment_delimiter,
 4689                                doc_delimiter,
 4690                                insert_extra_newline,
 4691                                indent_on_newline,
 4692                                indent_on_extra_newline,
 4693                            )
 4694                        } else {
 4695                            (
 4696                                None,
 4697                                None,
 4698                                false,
 4699                                IndentSize::default(),
 4700                                IndentSize::default(),
 4701                            )
 4702                        };
 4703
 4704                        let prevent_auto_indent = doc_delimiter.is_some();
 4705                        let delimiter = comment_delimiter.or(doc_delimiter);
 4706
 4707                        let capacity_for_delimiter =
 4708                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4709                        let mut new_text = String::with_capacity(
 4710                            1 + capacity_for_delimiter
 4711                                + existing_indent.len as usize
 4712                                + indent_on_newline.len as usize
 4713                                + indent_on_extra_newline.len as usize,
 4714                        );
 4715                        new_text.push('\n');
 4716                        new_text.extend(existing_indent.chars());
 4717                        new_text.extend(indent_on_newline.chars());
 4718
 4719                        if let Some(delimiter) = &delimiter {
 4720                            new_text.push_str(delimiter);
 4721                        }
 4722
 4723                        if insert_extra_newline {
 4724                            new_text.push('\n');
 4725                            new_text.extend(existing_indent.chars());
 4726                            new_text.extend(indent_on_extra_newline.chars());
 4727                        }
 4728
 4729                        let anchor = buffer.anchor_after(end);
 4730                        let new_selection = selection.map(|_| anchor);
 4731                        (
 4732                            ((start..end, new_text), prevent_auto_indent),
 4733                            (insert_extra_newline, new_selection),
 4734                        )
 4735                    })
 4736                    .unzip()
 4737            };
 4738
 4739            let mut auto_indent_edits = Vec::new();
 4740            let mut edits = Vec::new();
 4741            for (edit, prevent_auto_indent) in edits_with_flags {
 4742                if prevent_auto_indent {
 4743                    edits.push(edit);
 4744                } else {
 4745                    auto_indent_edits.push(edit);
 4746                }
 4747            }
 4748            if !edits.is_empty() {
 4749                this.edit(edits, cx);
 4750            }
 4751            if !auto_indent_edits.is_empty() {
 4752                this.edit_with_autoindent(auto_indent_edits, cx);
 4753            }
 4754
 4755            let buffer = this.buffer.read(cx).snapshot(cx);
 4756            let new_selections = selection_info
 4757                .into_iter()
 4758                .map(|(extra_newline_inserted, new_selection)| {
 4759                    let mut cursor = new_selection.end.to_point(&buffer);
 4760                    if extra_newline_inserted {
 4761                        cursor.row -= 1;
 4762                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 4763                    }
 4764                    new_selection.map(|_| cursor)
 4765                })
 4766                .collect();
 4767
 4768            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 4769            this.refresh_edit_prediction(true, false, window, cx);
 4770        });
 4771    }
 4772
 4773    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 4774        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4775
 4776        let buffer = self.buffer.read(cx);
 4777        let snapshot = buffer.snapshot(cx);
 4778
 4779        let mut edits = Vec::new();
 4780        let mut rows = Vec::new();
 4781
 4782        for (rows_inserted, selection) in self
 4783            .selections
 4784            .all_adjusted(&self.display_snapshot(cx))
 4785            .into_iter()
 4786            .enumerate()
 4787        {
 4788            let cursor = selection.head();
 4789            let row = cursor.row;
 4790
 4791            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 4792
 4793            let newline = "\n".to_string();
 4794            edits.push((start_of_line..start_of_line, newline));
 4795
 4796            rows.push(row + rows_inserted as u32);
 4797        }
 4798
 4799        self.transact(window, cx, |editor, window, cx| {
 4800            editor.edit(edits, cx);
 4801
 4802            editor.change_selections(Default::default(), window, cx, |s| {
 4803                let mut index = 0;
 4804                s.move_cursors_with(|map, _, _| {
 4805                    let row = rows[index];
 4806                    index += 1;
 4807
 4808                    let point = Point::new(row, 0);
 4809                    let boundary = map.next_line_boundary(point).1;
 4810                    let clipped = map.clip_point(boundary, Bias::Left);
 4811
 4812                    (clipped, SelectionGoal::None)
 4813                });
 4814            });
 4815
 4816            let mut indent_edits = Vec::new();
 4817            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4818            for row in rows {
 4819                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4820                for (row, indent) in indents {
 4821                    if indent.len == 0 {
 4822                        continue;
 4823                    }
 4824
 4825                    let text = match indent.kind {
 4826                        IndentKind::Space => " ".repeat(indent.len as usize),
 4827                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4828                    };
 4829                    let point = Point::new(row.0, 0);
 4830                    indent_edits.push((point..point, text));
 4831                }
 4832            }
 4833            editor.edit(indent_edits, cx);
 4834        });
 4835    }
 4836
 4837    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 4838        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4839
 4840        let buffer = self.buffer.read(cx);
 4841        let snapshot = buffer.snapshot(cx);
 4842
 4843        let mut edits = Vec::new();
 4844        let mut rows = Vec::new();
 4845        let mut rows_inserted = 0;
 4846
 4847        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 4848            let cursor = selection.head();
 4849            let row = cursor.row;
 4850
 4851            let point = Point::new(row + 1, 0);
 4852            let start_of_line = snapshot.clip_point(point, Bias::Left);
 4853
 4854            let newline = "\n".to_string();
 4855            edits.push((start_of_line..start_of_line, newline));
 4856
 4857            rows_inserted += 1;
 4858            rows.push(row + rows_inserted);
 4859        }
 4860
 4861        self.transact(window, cx, |editor, window, cx| {
 4862            editor.edit(edits, cx);
 4863
 4864            editor.change_selections(Default::default(), window, cx, |s| {
 4865                let mut index = 0;
 4866                s.move_cursors_with(|map, _, _| {
 4867                    let row = rows[index];
 4868                    index += 1;
 4869
 4870                    let point = Point::new(row, 0);
 4871                    let boundary = map.next_line_boundary(point).1;
 4872                    let clipped = map.clip_point(boundary, Bias::Left);
 4873
 4874                    (clipped, SelectionGoal::None)
 4875                });
 4876            });
 4877
 4878            let mut indent_edits = Vec::new();
 4879            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 4880            for row in rows {
 4881                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 4882                for (row, indent) in indents {
 4883                    if indent.len == 0 {
 4884                        continue;
 4885                    }
 4886
 4887                    let text = match indent.kind {
 4888                        IndentKind::Space => " ".repeat(indent.len as usize),
 4889                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 4890                    };
 4891                    let point = Point::new(row.0, 0);
 4892                    indent_edits.push((point..point, text));
 4893                }
 4894            }
 4895            editor.edit(indent_edits, cx);
 4896        });
 4897    }
 4898
 4899    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4900        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 4901            original_indent_columns: Vec::new(),
 4902        });
 4903        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 4904    }
 4905
 4906    fn insert_with_autoindent_mode(
 4907        &mut self,
 4908        text: &str,
 4909        autoindent_mode: Option<AutoindentMode>,
 4910        window: &mut Window,
 4911        cx: &mut Context<Self>,
 4912    ) {
 4913        if self.read_only(cx) {
 4914            return;
 4915        }
 4916
 4917        let text: Arc<str> = text.into();
 4918        self.transact(window, cx, |this, window, cx| {
 4919            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 4920            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 4921                let anchors = {
 4922                    let snapshot = buffer.read(cx);
 4923                    old_selections
 4924                        .iter()
 4925                        .map(|s| {
 4926                            let anchor = snapshot.anchor_after(s.head());
 4927                            s.map(|_| anchor)
 4928                        })
 4929                        .collect::<Vec<_>>()
 4930                };
 4931                buffer.edit(
 4932                    old_selections
 4933                        .iter()
 4934                        .map(|s| (s.start..s.end, text.clone())),
 4935                    autoindent_mode,
 4936                    cx,
 4937                );
 4938                anchors
 4939            });
 4940
 4941            this.change_selections(Default::default(), window, cx, |s| {
 4942                s.select_anchors(selection_anchors);
 4943            });
 4944
 4945            cx.notify();
 4946        });
 4947    }
 4948
 4949    fn trigger_completion_on_input(
 4950        &mut self,
 4951        text: &str,
 4952        trigger_in_words: bool,
 4953        window: &mut Window,
 4954        cx: &mut Context<Self>,
 4955    ) {
 4956        let completions_source = self
 4957            .context_menu
 4958            .borrow()
 4959            .as_ref()
 4960            .and_then(|menu| match menu {
 4961                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 4962                CodeContextMenu::CodeActions(_) => None,
 4963            });
 4964
 4965        match completions_source {
 4966            Some(CompletionsMenuSource::Words { .. }) => {
 4967                self.open_or_update_completions_menu(
 4968                    Some(CompletionsMenuSource::Words {
 4969                        ignore_threshold: false,
 4970                    }),
 4971                    None,
 4972                    window,
 4973                    cx,
 4974                );
 4975            }
 4976            Some(CompletionsMenuSource::Normal)
 4977            | Some(CompletionsMenuSource::SnippetChoices)
 4978            | None
 4979                if self.is_completion_trigger(
 4980                    text,
 4981                    trigger_in_words,
 4982                    completions_source.is_some(),
 4983                    cx,
 4984                ) =>
 4985            {
 4986                self.show_completions(
 4987                    &ShowCompletions {
 4988                        trigger: Some(text.to_owned()).filter(|x| !x.is_empty()),
 4989                    },
 4990                    window,
 4991                    cx,
 4992                )
 4993            }
 4994            _ => {
 4995                self.hide_context_menu(window, cx);
 4996            }
 4997        }
 4998    }
 4999
 5000    fn is_completion_trigger(
 5001        &self,
 5002        text: &str,
 5003        trigger_in_words: bool,
 5004        menu_is_open: bool,
 5005        cx: &mut Context<Self>,
 5006    ) -> bool {
 5007        let position = self.selections.newest_anchor().head();
 5008        let Some(buffer) = self.buffer.read(cx).buffer_for_anchor(position, cx) else {
 5009            return false;
 5010        };
 5011
 5012        if let Some(completion_provider) = &self.completion_provider {
 5013            completion_provider.is_completion_trigger(
 5014                &buffer,
 5015                position.text_anchor,
 5016                text,
 5017                trigger_in_words,
 5018                menu_is_open,
 5019                cx,
 5020            )
 5021        } else {
 5022            false
 5023        }
 5024    }
 5025
 5026    /// If any empty selections is touching the start of its innermost containing autoclose
 5027    /// region, expand it to select the brackets.
 5028    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5029        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5030        let buffer = self.buffer.read(cx).read(cx);
 5031        let new_selections = self
 5032            .selections_with_autoclose_regions(selections, &buffer)
 5033            .map(|(mut selection, region)| {
 5034                if !selection.is_empty() {
 5035                    return selection;
 5036                }
 5037
 5038                if let Some(region) = region {
 5039                    let mut range = region.range.to_offset(&buffer);
 5040                    if selection.start == range.start && range.start >= region.pair.start.len() {
 5041                        range.start -= region.pair.start.len();
 5042                        if buffer.contains_str_at(range.start, &region.pair.start)
 5043                            && buffer.contains_str_at(range.end, &region.pair.end)
 5044                        {
 5045                            range.end += region.pair.end.len();
 5046                            selection.start = range.start;
 5047                            selection.end = range.end;
 5048
 5049                            return selection;
 5050                        }
 5051                    }
 5052                }
 5053
 5054                let always_treat_brackets_as_autoclosed = buffer
 5055                    .language_settings_at(selection.start, cx)
 5056                    .always_treat_brackets_as_autoclosed;
 5057
 5058                if !always_treat_brackets_as_autoclosed {
 5059                    return selection;
 5060                }
 5061
 5062                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5063                    for (pair, enabled) in scope.brackets() {
 5064                        if !enabled || !pair.close {
 5065                            continue;
 5066                        }
 5067
 5068                        if buffer.contains_str_at(selection.start, &pair.end) {
 5069                            let pair_start_len = pair.start.len();
 5070                            if buffer.contains_str_at(
 5071                                selection.start.saturating_sub(pair_start_len),
 5072                                &pair.start,
 5073                            ) {
 5074                                selection.start -= pair_start_len;
 5075                                selection.end += pair.end.len();
 5076
 5077                                return selection;
 5078                            }
 5079                        }
 5080                    }
 5081                }
 5082
 5083                selection
 5084            })
 5085            .collect();
 5086
 5087        drop(buffer);
 5088        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5089            selections.select(new_selections)
 5090        });
 5091    }
 5092
 5093    /// Iterate the given selections, and for each one, find the smallest surrounding
 5094    /// autoclose region. This uses the ordering of the selections and the autoclose
 5095    /// regions to avoid repeated comparisons.
 5096    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5097        &'a self,
 5098        selections: impl IntoIterator<Item = Selection<D>>,
 5099        buffer: &'a MultiBufferSnapshot,
 5100    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5101        let mut i = 0;
 5102        let mut regions = self.autoclose_regions.as_slice();
 5103        selections.into_iter().map(move |selection| {
 5104            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5105
 5106            let mut enclosing = None;
 5107            while let Some(pair_state) = regions.get(i) {
 5108                if pair_state.range.end.to_offset(buffer) < range.start {
 5109                    regions = &regions[i + 1..];
 5110                    i = 0;
 5111                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5112                    break;
 5113                } else {
 5114                    if pair_state.selection_id == selection.id {
 5115                        enclosing = Some(pair_state);
 5116                    }
 5117                    i += 1;
 5118                }
 5119            }
 5120
 5121            (selection, enclosing)
 5122        })
 5123    }
 5124
 5125    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5126    fn invalidate_autoclose_regions(
 5127        &mut self,
 5128        mut selections: &[Selection<Anchor>],
 5129        buffer: &MultiBufferSnapshot,
 5130    ) {
 5131        self.autoclose_regions.retain(|state| {
 5132            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5133                return false;
 5134            }
 5135
 5136            let mut i = 0;
 5137            while let Some(selection) = selections.get(i) {
 5138                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5139                    selections = &selections[1..];
 5140                    continue;
 5141                }
 5142                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5143                    break;
 5144                }
 5145                if selection.id == state.selection_id {
 5146                    return true;
 5147                } else {
 5148                    i += 1;
 5149                }
 5150            }
 5151            false
 5152        });
 5153    }
 5154
 5155    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5156        let offset = position.to_offset(buffer);
 5157        let (word_range, kind) =
 5158            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5159        if offset > word_range.start && kind == Some(CharKind::Word) {
 5160            Some(
 5161                buffer
 5162                    .text_for_range(word_range.start..offset)
 5163                    .collect::<String>(),
 5164            )
 5165        } else {
 5166            None
 5167        }
 5168    }
 5169
 5170    pub fn visible_excerpts(
 5171        &self,
 5172        cx: &mut Context<Editor>,
 5173    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5174        let Some(project) = self.project() else {
 5175            return HashMap::default();
 5176        };
 5177        let project = project.read(cx);
 5178        let multi_buffer = self.buffer().read(cx);
 5179        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5180        let multi_buffer_visible_start = self
 5181            .scroll_manager
 5182            .anchor()
 5183            .anchor
 5184            .to_point(&multi_buffer_snapshot);
 5185        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5186            multi_buffer_visible_start
 5187                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5188            Bias::Left,
 5189        );
 5190        multi_buffer_snapshot
 5191            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5192            .into_iter()
 5193            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5194            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5195                let buffer_file = project::File::from_dyn(buffer.file())?;
 5196                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5197                let worktree_entry = buffer_worktree
 5198                    .read(cx)
 5199                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5200                if worktree_entry.is_ignored {
 5201                    None
 5202                } else {
 5203                    Some((
 5204                        excerpt_id,
 5205                        (
 5206                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5207                            buffer.version().clone(),
 5208                            excerpt_visible_range,
 5209                        ),
 5210                    ))
 5211                }
 5212            })
 5213            .collect()
 5214    }
 5215
 5216    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5217        TextLayoutDetails {
 5218            text_system: window.text_system().clone(),
 5219            editor_style: self.style.clone().unwrap(),
 5220            rem_size: window.rem_size(),
 5221            scroll_anchor: self.scroll_manager.anchor(),
 5222            visible_rows: self.visible_line_count(),
 5223            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5224        }
 5225    }
 5226
 5227    fn trigger_on_type_formatting(
 5228        &self,
 5229        input: String,
 5230        window: &mut Window,
 5231        cx: &mut Context<Self>,
 5232    ) -> Option<Task<Result<()>>> {
 5233        if input.len() != 1 {
 5234            return None;
 5235        }
 5236
 5237        let project = self.project()?;
 5238        let position = self.selections.newest_anchor().head();
 5239        let (buffer, buffer_position) = self
 5240            .buffer
 5241            .read(cx)
 5242            .text_anchor_for_position(position, cx)?;
 5243
 5244        let settings = language_settings::language_settings(
 5245            buffer
 5246                .read(cx)
 5247                .language_at(buffer_position)
 5248                .map(|l| l.name()),
 5249            buffer.read(cx).file(),
 5250            cx,
 5251        );
 5252        if !settings.use_on_type_format {
 5253            return None;
 5254        }
 5255
 5256        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5257        // hence we do LSP request & edit on host side only — add formats to host's history.
 5258        let push_to_lsp_host_history = true;
 5259        // If this is not the host, append its history with new edits.
 5260        let push_to_client_history = project.read(cx).is_via_collab();
 5261
 5262        let on_type_formatting = project.update(cx, |project, cx| {
 5263            project.on_type_format(
 5264                buffer.clone(),
 5265                buffer_position,
 5266                input,
 5267                push_to_lsp_host_history,
 5268                cx,
 5269            )
 5270        });
 5271        Some(cx.spawn_in(window, async move |editor, cx| {
 5272            if let Some(transaction) = on_type_formatting.await? {
 5273                if push_to_client_history {
 5274                    buffer
 5275                        .update(cx, |buffer, _| {
 5276                            buffer.push_transaction(transaction, Instant::now());
 5277                            buffer.finalize_last_transaction();
 5278                        })
 5279                        .ok();
 5280                }
 5281                editor.update(cx, |editor, cx| {
 5282                    editor.refresh_document_highlights(cx);
 5283                })?;
 5284            }
 5285            Ok(())
 5286        }))
 5287    }
 5288
 5289    pub fn show_word_completions(
 5290        &mut self,
 5291        _: &ShowWordCompletions,
 5292        window: &mut Window,
 5293        cx: &mut Context<Self>,
 5294    ) {
 5295        self.open_or_update_completions_menu(
 5296            Some(CompletionsMenuSource::Words {
 5297                ignore_threshold: true,
 5298            }),
 5299            None,
 5300            window,
 5301            cx,
 5302        );
 5303    }
 5304
 5305    pub fn show_completions(
 5306        &mut self,
 5307        options: &ShowCompletions,
 5308        window: &mut Window,
 5309        cx: &mut Context<Self>,
 5310    ) {
 5311        self.open_or_update_completions_menu(None, options.trigger.as_deref(), window, cx);
 5312    }
 5313
 5314    fn open_or_update_completions_menu(
 5315        &mut self,
 5316        requested_source: Option<CompletionsMenuSource>,
 5317        trigger: Option<&str>,
 5318        window: &mut Window,
 5319        cx: &mut Context<Self>,
 5320    ) {
 5321        if self.pending_rename.is_some() {
 5322            return;
 5323        }
 5324
 5325        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5326
 5327        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5328        // inserted and selected. To handle that case, the start of the selection is used so that
 5329        // the menu starts with all choices.
 5330        let position = self
 5331            .selections
 5332            .newest_anchor()
 5333            .start
 5334            .bias_right(&multibuffer_snapshot);
 5335        if position.diff_base_anchor.is_some() {
 5336            return;
 5337        }
 5338        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5339        let Some(buffer) = buffer_position
 5340            .buffer_id
 5341            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5342        else {
 5343            return;
 5344        };
 5345        let buffer_snapshot = buffer.read(cx).snapshot();
 5346
 5347        let query: Option<Arc<String>> =
 5348            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5349                .map(|query| query.into());
 5350
 5351        drop(multibuffer_snapshot);
 5352
 5353        // Hide the current completions menu when query is empty. Without this, cached
 5354        // completions from before the trigger char may be reused (#32774).
 5355        if query.is_none() {
 5356            let menu_is_open = matches!(
 5357                self.context_menu.borrow().as_ref(),
 5358                Some(CodeContextMenu::Completions(_))
 5359            );
 5360            if menu_is_open {
 5361                self.hide_context_menu(window, cx);
 5362            }
 5363        }
 5364
 5365        let mut ignore_word_threshold = false;
 5366        let provider = match requested_source {
 5367            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5368            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5369                ignore_word_threshold = ignore_threshold;
 5370                None
 5371            }
 5372            Some(CompletionsMenuSource::SnippetChoices) => {
 5373                log::error!("bug: SnippetChoices requested_source is not handled");
 5374                None
 5375            }
 5376        };
 5377
 5378        let sort_completions = provider
 5379            .as_ref()
 5380            .is_some_and(|provider| provider.sort_completions());
 5381
 5382        let filter_completions = provider
 5383            .as_ref()
 5384            .is_none_or(|provider| provider.filter_completions());
 5385
 5386        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5387            if filter_completions {
 5388                menu.filter(query.clone(), provider.clone(), window, cx);
 5389            }
 5390            // When `is_incomplete` is false, no need to re-query completions when the current query
 5391            // is a suffix of the initial query.
 5392            if !menu.is_incomplete {
 5393                // If the new query is a suffix of the old query (typing more characters) and
 5394                // the previous result was complete, the existing completions can be filtered.
 5395                //
 5396                // Note that this is always true for snippet completions.
 5397                let query_matches = match (&menu.initial_query, &query) {
 5398                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5399                    (None, _) => true,
 5400                    _ => false,
 5401                };
 5402                if query_matches {
 5403                    let position_matches = if menu.initial_position == position {
 5404                        true
 5405                    } else {
 5406                        let snapshot = self.buffer.read(cx).read(cx);
 5407                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5408                    };
 5409                    if position_matches {
 5410                        return;
 5411                    }
 5412                }
 5413            }
 5414        };
 5415
 5416        let trigger_kind = match trigger {
 5417            Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
 5418                CompletionTriggerKind::TRIGGER_CHARACTER
 5419            }
 5420            _ => CompletionTriggerKind::INVOKED,
 5421        };
 5422        let completion_context = CompletionContext {
 5423            trigger_character: trigger.and_then(|trigger| {
 5424                if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
 5425                    Some(String::from(trigger))
 5426                } else {
 5427                    None
 5428                }
 5429            }),
 5430            trigger_kind,
 5431        };
 5432
 5433        let Anchor {
 5434            excerpt_id: buffer_excerpt_id,
 5435            text_anchor: buffer_position,
 5436            ..
 5437        } = buffer_position;
 5438
 5439        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5440            buffer_snapshot.surrounding_word(buffer_position, None)
 5441        {
 5442            let word_to_exclude = buffer_snapshot
 5443                .text_for_range(word_range.clone())
 5444                .collect::<String>();
 5445            (
 5446                buffer_snapshot.anchor_before(word_range.start)
 5447                    ..buffer_snapshot.anchor_after(buffer_position),
 5448                Some(word_to_exclude),
 5449            )
 5450        } else {
 5451            (buffer_position..buffer_position, None)
 5452        };
 5453
 5454        let language = buffer_snapshot
 5455            .language_at(buffer_position)
 5456            .map(|language| language.name());
 5457
 5458        let completion_settings = language_settings(language.clone(), buffer_snapshot.file(), cx)
 5459            .completions
 5460            .clone();
 5461
 5462        let show_completion_documentation = buffer_snapshot
 5463            .settings_at(buffer_position, cx)
 5464            .show_completion_documentation;
 5465
 5466        // The document can be large, so stay in reasonable bounds when searching for words,
 5467        // otherwise completion pop-up might be slow to appear.
 5468        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5469        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5470        let min_word_search = buffer_snapshot.clip_point(
 5471            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5472            Bias::Left,
 5473        );
 5474        let max_word_search = buffer_snapshot.clip_point(
 5475            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5476            Bias::Right,
 5477        );
 5478        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5479            ..buffer_snapshot.point_to_offset(max_word_search);
 5480
 5481        let skip_digits = query
 5482            .as_ref()
 5483            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5484
 5485        let omit_word_completions = !self.word_completions_enabled
 5486            || (!ignore_word_threshold
 5487                && match &query {
 5488                    Some(query) => query.chars().count() < completion_settings.words_min_length,
 5489                    None => completion_settings.words_min_length != 0,
 5490                });
 5491
 5492        let (mut words, provider_responses) = match &provider {
 5493            Some(provider) => {
 5494                let provider_responses = provider.completions(
 5495                    buffer_excerpt_id,
 5496                    &buffer,
 5497                    buffer_position,
 5498                    completion_context,
 5499                    window,
 5500                    cx,
 5501                );
 5502
 5503                let words = match (omit_word_completions, completion_settings.words) {
 5504                    (true, _) | (_, WordsCompletionMode::Disabled) => {
 5505                        Task::ready(BTreeMap::default())
 5506                    }
 5507                    (false, WordsCompletionMode::Enabled | WordsCompletionMode::Fallback) => cx
 5508                        .background_spawn(async move {
 5509                            buffer_snapshot.words_in_range(WordsQuery {
 5510                                fuzzy_contents: None,
 5511                                range: word_search_range,
 5512                                skip_digits,
 5513                            })
 5514                        }),
 5515                };
 5516
 5517                (words, provider_responses)
 5518            }
 5519            None => {
 5520                let words = if omit_word_completions {
 5521                    Task::ready(BTreeMap::default())
 5522                } else {
 5523                    cx.background_spawn(async move {
 5524                        buffer_snapshot.words_in_range(WordsQuery {
 5525                            fuzzy_contents: None,
 5526                            range: word_search_range,
 5527                            skip_digits,
 5528                        })
 5529                    })
 5530                };
 5531                (words, Task::ready(Ok(Vec::new())))
 5532            }
 5533        };
 5534
 5535        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5536
 5537        let id = post_inc(&mut self.next_completion_id);
 5538        let task = cx.spawn_in(window, async move |editor, cx| {
 5539            let Ok(()) = editor.update(cx, |this, _| {
 5540                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5541            }) else {
 5542                return;
 5543            };
 5544
 5545            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5546            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5547            let mut completions = Vec::new();
 5548            let mut is_incomplete = false;
 5549            let mut display_options: Option<CompletionDisplayOptions> = None;
 5550            if let Some(provider_responses) = provider_responses.await.log_err()
 5551                && !provider_responses.is_empty()
 5552            {
 5553                for response in provider_responses {
 5554                    completions.extend(response.completions);
 5555                    is_incomplete = is_incomplete || response.is_incomplete;
 5556                    match display_options.as_mut() {
 5557                        None => {
 5558                            display_options = Some(response.display_options);
 5559                        }
 5560                        Some(options) => options.merge(&response.display_options),
 5561                    }
 5562                }
 5563                if completion_settings.words == WordsCompletionMode::Fallback {
 5564                    words = Task::ready(BTreeMap::default());
 5565                }
 5566            }
 5567            let display_options = display_options.unwrap_or_default();
 5568
 5569            let mut words = words.await;
 5570            if let Some(word_to_exclude) = &word_to_exclude {
 5571                words.remove(word_to_exclude);
 5572            }
 5573            for lsp_completion in &completions {
 5574                words.remove(&lsp_completion.new_text);
 5575            }
 5576            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5577                replace_range: word_replace_range.clone(),
 5578                new_text: word.clone(),
 5579                label: CodeLabel::plain(word, None),
 5580                icon_path: None,
 5581                documentation: None,
 5582                source: CompletionSource::BufferWord {
 5583                    word_range,
 5584                    resolved: false,
 5585                },
 5586                insert_text_mode: Some(InsertTextMode::AS_IS),
 5587                confirm: None,
 5588            }));
 5589
 5590            let menu = if completions.is_empty() {
 5591                None
 5592            } else {
 5593                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5594                    let languages = editor
 5595                        .workspace
 5596                        .as_ref()
 5597                        .and_then(|(workspace, _)| workspace.upgrade())
 5598                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5599                    let menu = CompletionsMenu::new(
 5600                        id,
 5601                        requested_source.unwrap_or(CompletionsMenuSource::Normal),
 5602                        sort_completions,
 5603                        show_completion_documentation,
 5604                        position,
 5605                        query.clone(),
 5606                        is_incomplete,
 5607                        buffer.clone(),
 5608                        completions.into(),
 5609                        display_options,
 5610                        snippet_sort_order,
 5611                        languages,
 5612                        language,
 5613                        cx,
 5614                    );
 5615
 5616                    let query = if filter_completions { query } else { None };
 5617                    let matches_task = if let Some(query) = query {
 5618                        menu.do_async_filtering(query, cx)
 5619                    } else {
 5620                        Task::ready(menu.unfiltered_matches())
 5621                    };
 5622                    (menu, matches_task)
 5623                }) else {
 5624                    return;
 5625                };
 5626
 5627                let matches = matches_task.await;
 5628
 5629                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5630                    // Newer menu already set, so exit.
 5631                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5632                        editor.context_menu.borrow().as_ref()
 5633                        && prev_menu.id > id
 5634                    {
 5635                        return;
 5636                    };
 5637
 5638                    // Only valid to take prev_menu because it the new menu is immediately set
 5639                    // below, or the menu is hidden.
 5640                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5641                        editor.context_menu.borrow_mut().take()
 5642                    {
 5643                        let position_matches =
 5644                            if prev_menu.initial_position == menu.initial_position {
 5645                                true
 5646                            } else {
 5647                                let snapshot = editor.buffer.read(cx).read(cx);
 5648                                prev_menu.initial_position.to_offset(&snapshot)
 5649                                    == menu.initial_position.to_offset(&snapshot)
 5650                            };
 5651                        if position_matches {
 5652                            // Preserve markdown cache before `set_filter_results` because it will
 5653                            // try to populate the documentation cache.
 5654                            menu.preserve_markdown_cache(prev_menu);
 5655                        }
 5656                    };
 5657
 5658                    menu.set_filter_results(matches, provider, window, cx);
 5659                }) else {
 5660                    return;
 5661                };
 5662
 5663                menu.visible().then_some(menu)
 5664            };
 5665
 5666            editor
 5667                .update_in(cx, |editor, window, cx| {
 5668                    if editor.focus_handle.is_focused(window)
 5669                        && let Some(menu) = menu
 5670                    {
 5671                        *editor.context_menu.borrow_mut() =
 5672                            Some(CodeContextMenu::Completions(menu));
 5673
 5674                        crate::hover_popover::hide_hover(editor, cx);
 5675                        if editor.show_edit_predictions_in_menu() {
 5676                            editor.update_visible_edit_prediction(window, cx);
 5677                        } else {
 5678                            editor.discard_edit_prediction(false, cx);
 5679                        }
 5680
 5681                        cx.notify();
 5682                        return;
 5683                    }
 5684
 5685                    if editor.completion_tasks.len() <= 1 {
 5686                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5687                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5688                        // If it was already hidden and we don't show edit predictions in the menu,
 5689                        // we should also show the edit prediction when available.
 5690                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5691                            editor.update_visible_edit_prediction(window, cx);
 5692                        }
 5693                    }
 5694                })
 5695                .ok();
 5696        });
 5697
 5698        self.completion_tasks.push((id, task));
 5699    }
 5700
 5701    #[cfg(feature = "test-support")]
 5702    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 5703        let menu = self.context_menu.borrow();
 5704        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 5705            let completions = menu.completions.borrow();
 5706            Some(completions.to_vec())
 5707        } else {
 5708            None
 5709        }
 5710    }
 5711
 5712    pub fn with_completions_menu_matching_id<R>(
 5713        &self,
 5714        id: CompletionId,
 5715        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 5716    ) -> R {
 5717        let mut context_menu = self.context_menu.borrow_mut();
 5718        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 5719            return f(None);
 5720        };
 5721        if completions_menu.id != id {
 5722            return f(None);
 5723        }
 5724        f(Some(completions_menu))
 5725    }
 5726
 5727    pub fn confirm_completion(
 5728        &mut self,
 5729        action: &ConfirmCompletion,
 5730        window: &mut Window,
 5731        cx: &mut Context<Self>,
 5732    ) -> Option<Task<Result<()>>> {
 5733        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5734        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 5735    }
 5736
 5737    pub fn confirm_completion_insert(
 5738        &mut self,
 5739        _: &ConfirmCompletionInsert,
 5740        window: &mut Window,
 5741        cx: &mut Context<Self>,
 5742    ) -> Option<Task<Result<()>>> {
 5743        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5744        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 5745    }
 5746
 5747    pub fn confirm_completion_replace(
 5748        &mut self,
 5749        _: &ConfirmCompletionReplace,
 5750        window: &mut Window,
 5751        cx: &mut Context<Self>,
 5752    ) -> Option<Task<Result<()>>> {
 5753        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5754        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 5755    }
 5756
 5757    pub fn compose_completion(
 5758        &mut self,
 5759        action: &ComposeCompletion,
 5760        window: &mut Window,
 5761        cx: &mut Context<Self>,
 5762    ) -> Option<Task<Result<()>>> {
 5763        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5764        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 5765    }
 5766
 5767    fn do_completion(
 5768        &mut self,
 5769        item_ix: Option<usize>,
 5770        intent: CompletionIntent,
 5771        window: &mut Window,
 5772        cx: &mut Context<Editor>,
 5773    ) -> Option<Task<Result<()>>> {
 5774        use language::ToOffset as _;
 5775
 5776        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 5777        else {
 5778            return None;
 5779        };
 5780
 5781        let candidate_id = {
 5782            let entries = completions_menu.entries.borrow();
 5783            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 5784            if self.show_edit_predictions_in_menu() {
 5785                self.discard_edit_prediction(true, cx);
 5786            }
 5787            mat.candidate_id
 5788        };
 5789
 5790        let completion = completions_menu
 5791            .completions
 5792            .borrow()
 5793            .get(candidate_id)?
 5794            .clone();
 5795        cx.stop_propagation();
 5796
 5797        let buffer_handle = completions_menu.buffer.clone();
 5798
 5799        let CompletionEdit {
 5800            new_text,
 5801            snippet,
 5802            replace_range,
 5803        } = process_completion_for_edit(
 5804            &completion,
 5805            intent,
 5806            &buffer_handle,
 5807            &completions_menu.initial_position.text_anchor,
 5808            cx,
 5809        );
 5810
 5811        let buffer = buffer_handle.read(cx);
 5812        let snapshot = self.buffer.read(cx).snapshot(cx);
 5813        let newest_anchor = self.selections.newest_anchor();
 5814        let replace_range_multibuffer = {
 5815            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 5816            excerpt.map_range_from_buffer(replace_range.clone())
 5817        };
 5818        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 5819            return None;
 5820        }
 5821
 5822        let old_text = buffer
 5823            .text_for_range(replace_range.clone())
 5824            .collect::<String>();
 5825        let lookbehind = newest_anchor
 5826            .start
 5827            .text_anchor
 5828            .to_offset(buffer)
 5829            .saturating_sub(replace_range.start);
 5830        let lookahead = replace_range
 5831            .end
 5832            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 5833        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 5834        let suffix = &old_text[lookbehind.min(old_text.len())..];
 5835
 5836        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
 5837        let mut ranges = Vec::new();
 5838        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 5839
 5840        for selection in &selections {
 5841            let range = if selection.id == newest_anchor.id {
 5842                replace_range_multibuffer.clone()
 5843            } else {
 5844                let mut range = selection.range();
 5845
 5846                // if prefix is present, don't duplicate it
 5847                if snapshot.contains_str_at(range.start.saturating_sub(lookbehind), prefix) {
 5848                    range.start = range.start.saturating_sub(lookbehind);
 5849
 5850                    // if suffix is also present, mimic the newest cursor and replace it
 5851                    if selection.id != newest_anchor.id
 5852                        && snapshot.contains_str_at(range.end, suffix)
 5853                    {
 5854                        range.end += lookahead;
 5855                    }
 5856                }
 5857                range
 5858            };
 5859
 5860            ranges.push(range.clone());
 5861
 5862            if !self.linked_edit_ranges.is_empty() {
 5863                let start_anchor = snapshot.anchor_before(range.start);
 5864                let end_anchor = snapshot.anchor_after(range.end);
 5865                if let Some(ranges) = self
 5866                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 5867                {
 5868                    for (buffer, edits) in ranges {
 5869                        linked_edits
 5870                            .entry(buffer.clone())
 5871                            .or_default()
 5872                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 5873                    }
 5874                }
 5875            }
 5876        }
 5877
 5878        let common_prefix_len = old_text
 5879            .chars()
 5880            .zip(new_text.chars())
 5881            .take_while(|(a, b)| a == b)
 5882            .map(|(a, _)| a.len_utf8())
 5883            .sum::<usize>();
 5884
 5885        cx.emit(EditorEvent::InputHandled {
 5886            utf16_range_to_replace: None,
 5887            text: new_text[common_prefix_len..].into(),
 5888        });
 5889
 5890        self.transact(window, cx, |editor, window, cx| {
 5891            if let Some(mut snippet) = snippet {
 5892                snippet.text = new_text.to_string();
 5893                editor
 5894                    .insert_snippet(&ranges, snippet, window, cx)
 5895                    .log_err();
 5896            } else {
 5897                editor.buffer.update(cx, |multi_buffer, cx| {
 5898                    let auto_indent = match completion.insert_text_mode {
 5899                        Some(InsertTextMode::AS_IS) => None,
 5900                        _ => editor.autoindent_mode.clone(),
 5901                    };
 5902                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 5903                    multi_buffer.edit(edits, auto_indent, cx);
 5904                });
 5905            }
 5906            for (buffer, edits) in linked_edits {
 5907                buffer.update(cx, |buffer, cx| {
 5908                    let snapshot = buffer.snapshot();
 5909                    let edits = edits
 5910                        .into_iter()
 5911                        .map(|(range, text)| {
 5912                            use text::ToPoint as TP;
 5913                            let end_point = TP::to_point(&range.end, &snapshot);
 5914                            let start_point = TP::to_point(&range.start, &snapshot);
 5915                            (start_point..end_point, text)
 5916                        })
 5917                        .sorted_by_key(|(range, _)| range.start);
 5918                    buffer.edit(edits, None, cx);
 5919                })
 5920            }
 5921
 5922            editor.refresh_edit_prediction(true, false, window, cx);
 5923        });
 5924        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 5925
 5926        let show_new_completions_on_confirm = completion
 5927            .confirm
 5928            .as_ref()
 5929            .is_some_and(|confirm| confirm(intent, window, cx));
 5930        if show_new_completions_on_confirm {
 5931            self.show_completions(&ShowCompletions { trigger: None }, window, cx);
 5932        }
 5933
 5934        let provider = self.completion_provider.as_ref()?;
 5935        drop(completion);
 5936        let apply_edits = provider.apply_additional_edits_for_completion(
 5937            buffer_handle,
 5938            completions_menu.completions.clone(),
 5939            candidate_id,
 5940            true,
 5941            cx,
 5942        );
 5943
 5944        let editor_settings = EditorSettings::get_global(cx);
 5945        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 5946            // After the code completion is finished, users often want to know what signatures are needed.
 5947            // so we should automatically call signature_help
 5948            self.show_signature_help(&ShowSignatureHelp, window, cx);
 5949        }
 5950
 5951        Some(cx.foreground_executor().spawn(async move {
 5952            apply_edits.await?;
 5953            Ok(())
 5954        }))
 5955    }
 5956
 5957    pub fn toggle_code_actions(
 5958        &mut self,
 5959        action: &ToggleCodeActions,
 5960        window: &mut Window,
 5961        cx: &mut Context<Self>,
 5962    ) {
 5963        let quick_launch = action.quick_launch;
 5964        let mut context_menu = self.context_menu.borrow_mut();
 5965        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 5966            if code_actions.deployed_from == action.deployed_from {
 5967                // Toggle if we're selecting the same one
 5968                *context_menu = None;
 5969                cx.notify();
 5970                return;
 5971            } else {
 5972                // Otherwise, clear it and start a new one
 5973                *context_menu = None;
 5974                cx.notify();
 5975            }
 5976        }
 5977        drop(context_menu);
 5978        let snapshot = self.snapshot(window, cx);
 5979        let deployed_from = action.deployed_from.clone();
 5980        let action = action.clone();
 5981        self.completion_tasks.clear();
 5982        self.discard_edit_prediction(false, cx);
 5983
 5984        let multibuffer_point = match &action.deployed_from {
 5985            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 5986                DisplayPoint::new(*row, 0).to_point(&snapshot)
 5987            }
 5988            _ => self
 5989                .selections
 5990                .newest::<Point>(&snapshot.display_snapshot)
 5991                .head(),
 5992        };
 5993        let Some((buffer, buffer_row)) = snapshot
 5994            .buffer_snapshot()
 5995            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 5996            .and_then(|(buffer_snapshot, range)| {
 5997                self.buffer()
 5998                    .read(cx)
 5999                    .buffer(buffer_snapshot.remote_id())
 6000                    .map(|buffer| (buffer, range.start.row))
 6001            })
 6002        else {
 6003            return;
 6004        };
 6005        let buffer_id = buffer.read(cx).remote_id();
 6006        let tasks = self
 6007            .tasks
 6008            .get(&(buffer_id, buffer_row))
 6009            .map(|t| Arc::new(t.to_owned()));
 6010
 6011        if !self.focus_handle.is_focused(window) {
 6012            return;
 6013        }
 6014        let project = self.project.clone();
 6015
 6016        let code_actions_task = match deployed_from {
 6017            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6018            _ => self.code_actions(buffer_row, window, cx),
 6019        };
 6020
 6021        let runnable_task = match deployed_from {
 6022            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6023            _ => {
 6024                let mut task_context_task = Task::ready(None);
 6025                if let Some(tasks) = &tasks
 6026                    && let Some(project) = project
 6027                {
 6028                    task_context_task =
 6029                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6030                }
 6031
 6032                cx.spawn_in(window, {
 6033                    let buffer = buffer.clone();
 6034                    async move |editor, cx| {
 6035                        let task_context = task_context_task.await;
 6036
 6037                        let resolved_tasks =
 6038                            tasks
 6039                                .zip(task_context.clone())
 6040                                .map(|(tasks, task_context)| ResolvedTasks {
 6041                                    templates: tasks.resolve(&task_context).collect(),
 6042                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6043                                        multibuffer_point.row,
 6044                                        tasks.column,
 6045                                    )),
 6046                                });
 6047                        let debug_scenarios = editor
 6048                            .update(cx, |editor, cx| {
 6049                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6050                            })?
 6051                            .await;
 6052                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6053                    }
 6054                })
 6055            }
 6056        };
 6057
 6058        cx.spawn_in(window, async move |editor, cx| {
 6059            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6060            let code_actions = code_actions_task.await;
 6061            let spawn_straight_away = quick_launch
 6062                && resolved_tasks
 6063                    .as_ref()
 6064                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6065                && code_actions
 6066                    .as_ref()
 6067                    .is_none_or(|actions| actions.is_empty())
 6068                && debug_scenarios.is_empty();
 6069
 6070            editor.update_in(cx, |editor, window, cx| {
 6071                crate::hover_popover::hide_hover(editor, cx);
 6072                let actions = CodeActionContents::new(
 6073                    resolved_tasks,
 6074                    code_actions,
 6075                    debug_scenarios,
 6076                    task_context.unwrap_or_default(),
 6077                );
 6078
 6079                // Don't show the menu if there are no actions available
 6080                if actions.is_empty() {
 6081                    cx.notify();
 6082                    return Task::ready(Ok(()));
 6083                }
 6084
 6085                *editor.context_menu.borrow_mut() =
 6086                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6087                        buffer,
 6088                        actions,
 6089                        selected_item: Default::default(),
 6090                        scroll_handle: UniformListScrollHandle::default(),
 6091                        deployed_from,
 6092                    }));
 6093                cx.notify();
 6094                if spawn_straight_away
 6095                    && let Some(task) = editor.confirm_code_action(
 6096                        &ConfirmCodeAction { item_ix: Some(0) },
 6097                        window,
 6098                        cx,
 6099                    )
 6100                {
 6101                    return task;
 6102                }
 6103
 6104                Task::ready(Ok(()))
 6105            })
 6106        })
 6107        .detach_and_log_err(cx);
 6108    }
 6109
 6110    fn debug_scenarios(
 6111        &mut self,
 6112        resolved_tasks: &Option<ResolvedTasks>,
 6113        buffer: &Entity<Buffer>,
 6114        cx: &mut App,
 6115    ) -> Task<Vec<task::DebugScenario>> {
 6116        maybe!({
 6117            let project = self.project()?;
 6118            let dap_store = project.read(cx).dap_store();
 6119            let mut scenarios = vec![];
 6120            let resolved_tasks = resolved_tasks.as_ref()?;
 6121            let buffer = buffer.read(cx);
 6122            let language = buffer.language()?;
 6123            let file = buffer.file();
 6124            let debug_adapter = language_settings(language.name().into(), file, cx)
 6125                .debuggers
 6126                .first()
 6127                .map(SharedString::from)
 6128                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6129
 6130            dap_store.update(cx, |dap_store, cx| {
 6131                for (_, task) in &resolved_tasks.templates {
 6132                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6133                        task.original_task().clone(),
 6134                        debug_adapter.clone().into(),
 6135                        task.display_label().to_owned().into(),
 6136                        cx,
 6137                    );
 6138                    scenarios.push(maybe_scenario);
 6139                }
 6140            });
 6141            Some(cx.background_spawn(async move {
 6142                futures::future::join_all(scenarios)
 6143                    .await
 6144                    .into_iter()
 6145                    .flatten()
 6146                    .collect::<Vec<_>>()
 6147            }))
 6148        })
 6149        .unwrap_or_else(|| Task::ready(vec![]))
 6150    }
 6151
 6152    fn code_actions(
 6153        &mut self,
 6154        buffer_row: u32,
 6155        window: &mut Window,
 6156        cx: &mut Context<Self>,
 6157    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6158        let mut task = self.code_actions_task.take();
 6159        cx.spawn_in(window, async move |editor, cx| {
 6160            while let Some(prev_task) = task {
 6161                prev_task.await.log_err();
 6162                task = editor
 6163                    .update(cx, |this, _| this.code_actions_task.take())
 6164                    .ok()?;
 6165            }
 6166
 6167            editor
 6168                .update(cx, |editor, cx| {
 6169                    editor
 6170                        .available_code_actions
 6171                        .clone()
 6172                        .and_then(|(location, code_actions)| {
 6173                            let snapshot = location.buffer.read(cx).snapshot();
 6174                            let point_range = location.range.to_point(&snapshot);
 6175                            let point_range = point_range.start.row..=point_range.end.row;
 6176                            if point_range.contains(&buffer_row) {
 6177                                Some(code_actions)
 6178                            } else {
 6179                                None
 6180                            }
 6181                        })
 6182                })
 6183                .ok()
 6184                .flatten()
 6185        })
 6186    }
 6187
 6188    pub fn confirm_code_action(
 6189        &mut self,
 6190        action: &ConfirmCodeAction,
 6191        window: &mut Window,
 6192        cx: &mut Context<Self>,
 6193    ) -> Option<Task<Result<()>>> {
 6194        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6195
 6196        let actions_menu =
 6197            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6198                menu
 6199            } else {
 6200                return None;
 6201            };
 6202
 6203        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6204        let action = actions_menu.actions.get(action_ix)?;
 6205        let title = action.label();
 6206        let buffer = actions_menu.buffer;
 6207        let workspace = self.workspace()?;
 6208
 6209        match action {
 6210            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6211                workspace.update(cx, |workspace, cx| {
 6212                    workspace.schedule_resolved_task(
 6213                        task_source_kind,
 6214                        resolved_task,
 6215                        false,
 6216                        window,
 6217                        cx,
 6218                    );
 6219
 6220                    Some(Task::ready(Ok(())))
 6221                })
 6222            }
 6223            CodeActionsItem::CodeAction {
 6224                excerpt_id,
 6225                action,
 6226                provider,
 6227            } => {
 6228                let apply_code_action =
 6229                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6230                let workspace = workspace.downgrade();
 6231                Some(cx.spawn_in(window, async move |editor, cx| {
 6232                    let project_transaction = apply_code_action.await?;
 6233                    Self::open_project_transaction(
 6234                        &editor,
 6235                        workspace,
 6236                        project_transaction,
 6237                        title,
 6238                        cx,
 6239                    )
 6240                    .await
 6241                }))
 6242            }
 6243            CodeActionsItem::DebugScenario(scenario) => {
 6244                let context = actions_menu.actions.context;
 6245
 6246                workspace.update(cx, |workspace, cx| {
 6247                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6248                    workspace.start_debug_session(
 6249                        scenario,
 6250                        context,
 6251                        Some(buffer),
 6252                        None,
 6253                        window,
 6254                        cx,
 6255                    );
 6256                });
 6257                Some(Task::ready(Ok(())))
 6258            }
 6259        }
 6260    }
 6261
 6262    pub async fn open_project_transaction(
 6263        editor: &WeakEntity<Editor>,
 6264        workspace: WeakEntity<Workspace>,
 6265        transaction: ProjectTransaction,
 6266        title: String,
 6267        cx: &mut AsyncWindowContext,
 6268    ) -> Result<()> {
 6269        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6270        cx.update(|_, cx| {
 6271            entries.sort_unstable_by_key(|(buffer, _)| {
 6272                buffer.read(cx).file().map(|f| f.path().clone())
 6273            });
 6274        })?;
 6275        if entries.is_empty() {
 6276            return Ok(());
 6277        }
 6278
 6279        // If the project transaction's edits are all contained within this editor, then
 6280        // avoid opening a new editor to display them.
 6281
 6282        if let [(buffer, transaction)] = &*entries {
 6283            let excerpt = editor.update(cx, |editor, cx| {
 6284                editor
 6285                    .buffer()
 6286                    .read(cx)
 6287                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6288            })?;
 6289            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6290                && excerpted_buffer == *buffer
 6291            {
 6292                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6293                    let excerpt_range = excerpt_range.to_offset(buffer);
 6294                    buffer
 6295                        .edited_ranges_for_transaction::<usize>(transaction)
 6296                        .all(|range| {
 6297                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6298                        })
 6299                })?;
 6300
 6301                if all_edits_within_excerpt {
 6302                    return Ok(());
 6303                }
 6304            }
 6305        }
 6306
 6307        let mut ranges_to_highlight = Vec::new();
 6308        let excerpt_buffer = cx.new(|cx| {
 6309            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6310            for (buffer_handle, transaction) in &entries {
 6311                let edited_ranges = buffer_handle
 6312                    .read(cx)
 6313                    .edited_ranges_for_transaction::<Point>(transaction)
 6314                    .collect::<Vec<_>>();
 6315                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6316                    PathKey::for_buffer(buffer_handle, cx),
 6317                    buffer_handle.clone(),
 6318                    edited_ranges,
 6319                    multibuffer_context_lines(cx),
 6320                    cx,
 6321                );
 6322
 6323                ranges_to_highlight.extend(ranges);
 6324            }
 6325            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6326            multibuffer
 6327        })?;
 6328
 6329        workspace.update_in(cx, |workspace, window, cx| {
 6330            let project = workspace.project().clone();
 6331            let editor =
 6332                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6333            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6334            editor.update(cx, |editor, cx| {
 6335                editor.highlight_background::<Self>(
 6336                    &ranges_to_highlight,
 6337                    |theme| theme.colors().editor_highlighted_line_background,
 6338                    cx,
 6339                );
 6340            });
 6341        })?;
 6342
 6343        Ok(())
 6344    }
 6345
 6346    pub fn clear_code_action_providers(&mut self) {
 6347        self.code_action_providers.clear();
 6348        self.available_code_actions.take();
 6349    }
 6350
 6351    pub fn add_code_action_provider(
 6352        &mut self,
 6353        provider: Rc<dyn CodeActionProvider>,
 6354        window: &mut Window,
 6355        cx: &mut Context<Self>,
 6356    ) {
 6357        if self
 6358            .code_action_providers
 6359            .iter()
 6360            .any(|existing_provider| existing_provider.id() == provider.id())
 6361        {
 6362            return;
 6363        }
 6364
 6365        self.code_action_providers.push(provider);
 6366        self.refresh_code_actions(window, cx);
 6367    }
 6368
 6369    pub fn remove_code_action_provider(
 6370        &mut self,
 6371        id: Arc<str>,
 6372        window: &mut Window,
 6373        cx: &mut Context<Self>,
 6374    ) {
 6375        self.code_action_providers
 6376            .retain(|provider| provider.id() != id);
 6377        self.refresh_code_actions(window, cx);
 6378    }
 6379
 6380    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6381        !self.code_action_providers.is_empty()
 6382            && EditorSettings::get_global(cx).toolbar.code_actions
 6383    }
 6384
 6385    pub fn has_available_code_actions(&self) -> bool {
 6386        self.available_code_actions
 6387            .as_ref()
 6388            .is_some_and(|(_, actions)| !actions.is_empty())
 6389    }
 6390
 6391    fn render_inline_code_actions(
 6392        &self,
 6393        icon_size: ui::IconSize,
 6394        display_row: DisplayRow,
 6395        is_active: bool,
 6396        cx: &mut Context<Self>,
 6397    ) -> AnyElement {
 6398        let show_tooltip = !self.context_menu_visible();
 6399        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6400            .icon_size(icon_size)
 6401            .shape(ui::IconButtonShape::Square)
 6402            .icon_color(ui::Color::Hidden)
 6403            .toggle_state(is_active)
 6404            .when(show_tooltip, |this| {
 6405                this.tooltip({
 6406                    let focus_handle = self.focus_handle.clone();
 6407                    move |_window, cx| {
 6408                        Tooltip::for_action_in(
 6409                            "Toggle Code Actions",
 6410                            &ToggleCodeActions {
 6411                                deployed_from: None,
 6412                                quick_launch: false,
 6413                            },
 6414                            &focus_handle,
 6415                            cx,
 6416                        )
 6417                    }
 6418                })
 6419            })
 6420            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6421                window.focus(&editor.focus_handle(cx));
 6422                editor.toggle_code_actions(
 6423                    &crate::actions::ToggleCodeActions {
 6424                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6425                            display_row,
 6426                        )),
 6427                        quick_launch: false,
 6428                    },
 6429                    window,
 6430                    cx,
 6431                );
 6432            }))
 6433            .into_any_element()
 6434    }
 6435
 6436    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6437        &self.context_menu
 6438    }
 6439
 6440    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6441        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6442            cx.background_executor()
 6443                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6444                .await;
 6445
 6446            let (start_buffer, start, _, end, newest_selection) = this
 6447                .update(cx, |this, cx| {
 6448                    let newest_selection = this.selections.newest_anchor().clone();
 6449                    if newest_selection.head().diff_base_anchor.is_some() {
 6450                        return None;
 6451                    }
 6452                    let display_snapshot = this.display_snapshot(cx);
 6453                    let newest_selection_adjusted =
 6454                        this.selections.newest_adjusted(&display_snapshot);
 6455                    let buffer = this.buffer.read(cx);
 6456
 6457                    let (start_buffer, start) =
 6458                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6459                    let (end_buffer, end) =
 6460                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6461
 6462                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6463                })?
 6464                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6465                .context(
 6466                    "Expected selection to lie in a single buffer when refreshing code actions",
 6467                )?;
 6468            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6469                let providers = this.code_action_providers.clone();
 6470                let tasks = this
 6471                    .code_action_providers
 6472                    .iter()
 6473                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6474                    .collect::<Vec<_>>();
 6475                (providers, tasks)
 6476            })?;
 6477
 6478            let mut actions = Vec::new();
 6479            for (provider, provider_actions) in
 6480                providers.into_iter().zip(future::join_all(tasks).await)
 6481            {
 6482                if let Some(provider_actions) = provider_actions.log_err() {
 6483                    actions.extend(provider_actions.into_iter().map(|action| {
 6484                        AvailableCodeAction {
 6485                            excerpt_id: newest_selection.start.excerpt_id,
 6486                            action,
 6487                            provider: provider.clone(),
 6488                        }
 6489                    }));
 6490                }
 6491            }
 6492
 6493            this.update(cx, |this, cx| {
 6494                this.available_code_actions = if actions.is_empty() {
 6495                    None
 6496                } else {
 6497                    Some((
 6498                        Location {
 6499                            buffer: start_buffer,
 6500                            range: start..end,
 6501                        },
 6502                        actions.into(),
 6503                    ))
 6504                };
 6505                cx.notify();
 6506            })
 6507        }));
 6508    }
 6509
 6510    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6511        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6512            self.show_git_blame_inline = false;
 6513
 6514            self.show_git_blame_inline_delay_task =
 6515                Some(cx.spawn_in(window, async move |this, cx| {
 6516                    cx.background_executor().timer(delay).await;
 6517
 6518                    this.update(cx, |this, cx| {
 6519                        this.show_git_blame_inline = true;
 6520                        cx.notify();
 6521                    })
 6522                    .log_err();
 6523                }));
 6524        }
 6525    }
 6526
 6527    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6528        let snapshot = self.snapshot(window, cx);
 6529        let cursor = self
 6530            .selections
 6531            .newest::<Point>(&snapshot.display_snapshot)
 6532            .head();
 6533        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6534        else {
 6535            return;
 6536        };
 6537
 6538        let Some(blame) = self.blame.as_ref() else {
 6539            return;
 6540        };
 6541
 6542        let row_info = RowInfo {
 6543            buffer_id: Some(buffer.remote_id()),
 6544            buffer_row: Some(point.row),
 6545            ..Default::default()
 6546        };
 6547        let Some((buffer, blame_entry)) = blame
 6548            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6549            .flatten()
 6550        else {
 6551            return;
 6552        };
 6553
 6554        let anchor = self.selections.newest_anchor().head();
 6555        let position = self.to_pixel_point(anchor, &snapshot, window);
 6556        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6557            self.show_blame_popover(
 6558                buffer,
 6559                &blame_entry,
 6560                position + last_bounds.origin,
 6561                true,
 6562                cx,
 6563            );
 6564        };
 6565    }
 6566
 6567    fn show_blame_popover(
 6568        &mut self,
 6569        buffer: BufferId,
 6570        blame_entry: &BlameEntry,
 6571        position: gpui::Point<Pixels>,
 6572        ignore_timeout: bool,
 6573        cx: &mut Context<Self>,
 6574    ) {
 6575        if let Some(state) = &mut self.inline_blame_popover {
 6576            state.hide_task.take();
 6577        } else {
 6578            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6579            let blame_entry = blame_entry.clone();
 6580            let show_task = cx.spawn(async move |editor, cx| {
 6581                if !ignore_timeout {
 6582                    cx.background_executor()
 6583                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6584                        .await;
 6585                }
 6586                editor
 6587                    .update(cx, |editor, cx| {
 6588                        editor.inline_blame_popover_show_task.take();
 6589                        let Some(blame) = editor.blame.as_ref() else {
 6590                            return;
 6591                        };
 6592                        let blame = blame.read(cx);
 6593                        let details = blame.details_for_entry(buffer, &blame_entry);
 6594                        let markdown = cx.new(|cx| {
 6595                            Markdown::new(
 6596                                details
 6597                                    .as_ref()
 6598                                    .map(|message| message.message.clone())
 6599                                    .unwrap_or_default(),
 6600                                None,
 6601                                None,
 6602                                cx,
 6603                            )
 6604                        });
 6605                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6606                            position,
 6607                            hide_task: None,
 6608                            popover_bounds: None,
 6609                            popover_state: InlineBlamePopoverState {
 6610                                scroll_handle: ScrollHandle::new(),
 6611                                commit_message: details,
 6612                                markdown,
 6613                            },
 6614                            keyboard_grace: ignore_timeout,
 6615                        });
 6616                        cx.notify();
 6617                    })
 6618                    .ok();
 6619            });
 6620            self.inline_blame_popover_show_task = Some(show_task);
 6621        }
 6622    }
 6623
 6624    fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6625        self.inline_blame_popover_show_task.take();
 6626        if let Some(state) = &mut self.inline_blame_popover {
 6627            let hide_task = cx.spawn(async move |editor, cx| {
 6628                if !ignore_timeout {
 6629                    cx.background_executor()
 6630                        .timer(std::time::Duration::from_millis(100))
 6631                        .await;
 6632                }
 6633                editor
 6634                    .update(cx, |editor, cx| {
 6635                        editor.inline_blame_popover.take();
 6636                        cx.notify();
 6637                    })
 6638                    .ok();
 6639            });
 6640            state.hide_task = Some(hide_task);
 6641            true
 6642        } else {
 6643            false
 6644        }
 6645    }
 6646
 6647    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 6648        if self.pending_rename.is_some() {
 6649            return None;
 6650        }
 6651
 6652        let provider = self.semantics_provider.clone()?;
 6653        let buffer = self.buffer.read(cx);
 6654        let newest_selection = self.selections.newest_anchor().clone();
 6655        let cursor_position = newest_selection.head();
 6656        let (cursor_buffer, cursor_buffer_position) =
 6657            buffer.text_anchor_for_position(cursor_position, cx)?;
 6658        let (tail_buffer, tail_buffer_position) =
 6659            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 6660        if cursor_buffer != tail_buffer {
 6661            return None;
 6662        }
 6663
 6664        let snapshot = cursor_buffer.read(cx).snapshot();
 6665        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 6666        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 6667        if start_word_range != end_word_range {
 6668            self.document_highlights_task.take();
 6669            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 6670            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 6671            return None;
 6672        }
 6673
 6674        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 6675        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 6676            cx.background_executor()
 6677                .timer(Duration::from_millis(debounce))
 6678                .await;
 6679
 6680            let highlights = if let Some(highlights) = cx
 6681                .update(|cx| {
 6682                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 6683                })
 6684                .ok()
 6685                .flatten()
 6686            {
 6687                highlights.await.log_err()
 6688            } else {
 6689                None
 6690            };
 6691
 6692            if let Some(highlights) = highlights {
 6693                this.update(cx, |this, cx| {
 6694                    if this.pending_rename.is_some() {
 6695                        return;
 6696                    }
 6697
 6698                    let buffer = this.buffer.read(cx);
 6699                    if buffer
 6700                        .text_anchor_for_position(cursor_position, cx)
 6701                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 6702                    {
 6703                        return;
 6704                    }
 6705
 6706                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 6707                    let mut write_ranges = Vec::new();
 6708                    let mut read_ranges = Vec::new();
 6709                    for highlight in highlights {
 6710                        let buffer_id = cursor_buffer.read(cx).remote_id();
 6711                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 6712                        {
 6713                            let start = highlight
 6714                                .range
 6715                                .start
 6716                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 6717                            let end = highlight
 6718                                .range
 6719                                .end
 6720                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 6721                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 6722                                continue;
 6723                            }
 6724
 6725                            let range =
 6726                                Anchor::range_in_buffer(excerpt_id, buffer_id, *start..*end);
 6727                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 6728                                write_ranges.push(range);
 6729                            } else {
 6730                                read_ranges.push(range);
 6731                            }
 6732                        }
 6733                    }
 6734
 6735                    this.highlight_background::<DocumentHighlightRead>(
 6736                        &read_ranges,
 6737                        |theme| theme.colors().editor_document_highlight_read_background,
 6738                        cx,
 6739                    );
 6740                    this.highlight_background::<DocumentHighlightWrite>(
 6741                        &write_ranges,
 6742                        |theme| theme.colors().editor_document_highlight_write_background,
 6743                        cx,
 6744                    );
 6745                    cx.notify();
 6746                })
 6747                .log_err();
 6748            }
 6749        }));
 6750        None
 6751    }
 6752
 6753    fn prepare_highlight_query_from_selection(
 6754        &mut self,
 6755        window: &Window,
 6756        cx: &mut Context<Editor>,
 6757    ) -> Option<(String, Range<Anchor>)> {
 6758        if matches!(self.mode, EditorMode::SingleLine) {
 6759            return None;
 6760        }
 6761        if !EditorSettings::get_global(cx).selection_highlight {
 6762            return None;
 6763        }
 6764        if self.selections.count() != 1 || self.selections.line_mode() {
 6765            return None;
 6766        }
 6767        let snapshot = self.snapshot(window, cx);
 6768        let selection = self.selections.newest::<Point>(&snapshot);
 6769        // If the selection spans multiple rows OR it is empty
 6770        if selection.start.row != selection.end.row
 6771            || selection.start.column == selection.end.column
 6772        {
 6773            return None;
 6774        }
 6775        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 6776        let query = snapshot
 6777            .buffer_snapshot()
 6778            .text_for_range(selection_anchor_range.clone())
 6779            .collect::<String>();
 6780        if query.trim().is_empty() {
 6781            return None;
 6782        }
 6783        Some((query, selection_anchor_range))
 6784    }
 6785
 6786    fn update_selection_occurrence_highlights(
 6787        &mut self,
 6788        query_text: String,
 6789        query_range: Range<Anchor>,
 6790        multi_buffer_range_to_query: Range<Point>,
 6791        use_debounce: bool,
 6792        window: &mut Window,
 6793        cx: &mut Context<Editor>,
 6794    ) -> Task<()> {
 6795        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6796        cx.spawn_in(window, async move |editor, cx| {
 6797            if use_debounce {
 6798                cx.background_executor()
 6799                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 6800                    .await;
 6801            }
 6802            let match_task = cx.background_spawn(async move {
 6803                let buffer_ranges = multi_buffer_snapshot
 6804                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 6805                    .into_iter()
 6806                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 6807                let mut match_ranges = Vec::new();
 6808                let Ok(regex) = project::search::SearchQuery::text(
 6809                    query_text.clone(),
 6810                    false,
 6811                    false,
 6812                    false,
 6813                    Default::default(),
 6814                    Default::default(),
 6815                    false,
 6816                    None,
 6817                ) else {
 6818                    return Vec::default();
 6819                };
 6820                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 6821                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 6822                    match_ranges.extend(
 6823                        regex
 6824                            .search(buffer_snapshot, Some(search_range.clone()))
 6825                            .await
 6826                            .into_iter()
 6827                            .filter_map(|match_range| {
 6828                                let match_start = buffer_snapshot
 6829                                    .anchor_after(search_range.start + match_range.start);
 6830                                let match_end = buffer_snapshot
 6831                                    .anchor_before(search_range.start + match_range.end);
 6832                                let match_anchor_range = Anchor::range_in_buffer(
 6833                                    excerpt_id,
 6834                                    buffer_snapshot.remote_id(),
 6835                                    match_start..match_end,
 6836                                );
 6837                                (match_anchor_range != query_range).then_some(match_anchor_range)
 6838                            }),
 6839                    );
 6840                }
 6841                match_ranges
 6842            });
 6843            let match_ranges = match_task.await;
 6844            editor
 6845                .update_in(cx, |editor, _, cx| {
 6846                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 6847                    if !match_ranges.is_empty() {
 6848                        editor.highlight_background::<SelectedTextHighlight>(
 6849                            &match_ranges,
 6850                            |theme| theme.colors().editor_document_highlight_bracket_background,
 6851                            cx,
 6852                        )
 6853                    }
 6854                })
 6855                .log_err();
 6856        })
 6857    }
 6858
 6859    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 6860        struct NewlineFold;
 6861        let type_id = std::any::TypeId::of::<NewlineFold>();
 6862        if !self.mode.is_single_line() {
 6863            return;
 6864        }
 6865        let snapshot = self.snapshot(window, cx);
 6866        if snapshot.buffer_snapshot().max_point().row == 0 {
 6867            return;
 6868        }
 6869        let task = cx.background_spawn(async move {
 6870            let new_newlines = snapshot
 6871                .buffer_chars_at(0)
 6872                .filter_map(|(c, i)| {
 6873                    if c == '\n' {
 6874                        Some(
 6875                            snapshot.buffer_snapshot().anchor_after(i)
 6876                                ..snapshot.buffer_snapshot().anchor_before(i + 1),
 6877                        )
 6878                    } else {
 6879                        None
 6880                    }
 6881                })
 6882                .collect::<Vec<_>>();
 6883            let existing_newlines = snapshot
 6884                .folds_in_range(0..snapshot.buffer_snapshot().len())
 6885                .filter_map(|fold| {
 6886                    if fold.placeholder.type_tag == Some(type_id) {
 6887                        Some(fold.range.start..fold.range.end)
 6888                    } else {
 6889                        None
 6890                    }
 6891                })
 6892                .collect::<Vec<_>>();
 6893
 6894            (new_newlines, existing_newlines)
 6895        });
 6896        self.folding_newlines = cx.spawn(async move |this, cx| {
 6897            let (new_newlines, existing_newlines) = task.await;
 6898            if new_newlines == existing_newlines {
 6899                return;
 6900            }
 6901            let placeholder = FoldPlaceholder {
 6902                render: Arc::new(move |_, _, cx| {
 6903                    div()
 6904                        .bg(cx.theme().status().hint_background)
 6905                        .border_b_1()
 6906                        .size_full()
 6907                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 6908                        .border_color(cx.theme().status().hint)
 6909                        .child("\\n")
 6910                        .into_any()
 6911                }),
 6912                constrain_width: false,
 6913                merge_adjacent: false,
 6914                type_tag: Some(type_id),
 6915            };
 6916            let creases = new_newlines
 6917                .into_iter()
 6918                .map(|range| Crease::simple(range, placeholder.clone()))
 6919                .collect();
 6920            this.update(cx, |this, cx| {
 6921                this.display_map.update(cx, |display_map, cx| {
 6922                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 6923                    display_map.fold(creases, cx);
 6924                });
 6925            })
 6926            .ok();
 6927        });
 6928    }
 6929
 6930    fn refresh_selected_text_highlights(
 6931        &mut self,
 6932        on_buffer_edit: bool,
 6933        window: &mut Window,
 6934        cx: &mut Context<Editor>,
 6935    ) {
 6936        let Some((query_text, query_range)) =
 6937            self.prepare_highlight_query_from_selection(window, cx)
 6938        else {
 6939            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 6940            self.quick_selection_highlight_task.take();
 6941            self.debounced_selection_highlight_task.take();
 6942            return;
 6943        };
 6944        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 6945        if on_buffer_edit
 6946            || self
 6947                .quick_selection_highlight_task
 6948                .as_ref()
 6949                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 6950        {
 6951            let multi_buffer_visible_start = self
 6952                .scroll_manager
 6953                .anchor()
 6954                .anchor
 6955                .to_point(&multi_buffer_snapshot);
 6956            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 6957                multi_buffer_visible_start
 6958                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 6959                Bias::Left,
 6960            );
 6961            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 6962            self.quick_selection_highlight_task = Some((
 6963                query_range.clone(),
 6964                self.update_selection_occurrence_highlights(
 6965                    query_text.clone(),
 6966                    query_range.clone(),
 6967                    multi_buffer_visible_range,
 6968                    false,
 6969                    window,
 6970                    cx,
 6971                ),
 6972            ));
 6973        }
 6974        if on_buffer_edit
 6975            || self
 6976                .debounced_selection_highlight_task
 6977                .as_ref()
 6978                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 6979        {
 6980            let multi_buffer_start = multi_buffer_snapshot
 6981                .anchor_before(0)
 6982                .to_point(&multi_buffer_snapshot);
 6983            let multi_buffer_end = multi_buffer_snapshot
 6984                .anchor_after(multi_buffer_snapshot.len())
 6985                .to_point(&multi_buffer_snapshot);
 6986            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 6987            self.debounced_selection_highlight_task = Some((
 6988                query_range.clone(),
 6989                self.update_selection_occurrence_highlights(
 6990                    query_text,
 6991                    query_range,
 6992                    multi_buffer_full_range,
 6993                    true,
 6994                    window,
 6995                    cx,
 6996                ),
 6997            ));
 6998        }
 6999    }
 7000
 7001    pub fn refresh_edit_prediction(
 7002        &mut self,
 7003        debounce: bool,
 7004        user_requested: bool,
 7005        window: &mut Window,
 7006        cx: &mut Context<Self>,
 7007    ) -> Option<()> {
 7008        if DisableAiSettings::get_global(cx).disable_ai {
 7009            return None;
 7010        }
 7011
 7012        let provider = self.edit_prediction_provider()?;
 7013        let cursor = self.selections.newest_anchor().head();
 7014        let (buffer, cursor_buffer_position) =
 7015            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7016
 7017        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7018            self.discard_edit_prediction(false, cx);
 7019            return None;
 7020        }
 7021
 7022        self.update_visible_edit_prediction(window, cx);
 7023
 7024        if !user_requested
 7025            && (!self.should_show_edit_predictions()
 7026                || !self.is_focused(window)
 7027                || buffer.read(cx).is_empty())
 7028        {
 7029            self.discard_edit_prediction(false, cx);
 7030            return None;
 7031        }
 7032
 7033        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7034        Some(())
 7035    }
 7036
 7037    fn show_edit_predictions_in_menu(&self) -> bool {
 7038        match self.edit_prediction_settings {
 7039            EditPredictionSettings::Disabled => false,
 7040            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7041        }
 7042    }
 7043
 7044    pub fn edit_predictions_enabled(&self) -> bool {
 7045        match self.edit_prediction_settings {
 7046            EditPredictionSettings::Disabled => false,
 7047            EditPredictionSettings::Enabled { .. } => true,
 7048        }
 7049    }
 7050
 7051    fn edit_prediction_requires_modifier(&self) -> bool {
 7052        match self.edit_prediction_settings {
 7053            EditPredictionSettings::Disabled => false,
 7054            EditPredictionSettings::Enabled {
 7055                preview_requires_modifier,
 7056                ..
 7057            } => preview_requires_modifier,
 7058        }
 7059    }
 7060
 7061    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7062        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7063            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7064            self.discard_edit_prediction(false, cx);
 7065        } else {
 7066            let selection = self.selections.newest_anchor();
 7067            let cursor = selection.head();
 7068
 7069            if let Some((buffer, cursor_buffer_position)) =
 7070                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7071            {
 7072                self.edit_prediction_settings =
 7073                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7074            }
 7075        }
 7076    }
 7077
 7078    fn edit_prediction_settings_at_position(
 7079        &self,
 7080        buffer: &Entity<Buffer>,
 7081        buffer_position: language::Anchor,
 7082        cx: &App,
 7083    ) -> EditPredictionSettings {
 7084        if !self.mode.is_full()
 7085            || !self.show_edit_predictions_override.unwrap_or(true)
 7086            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7087        {
 7088            return EditPredictionSettings::Disabled;
 7089        }
 7090
 7091        let buffer = buffer.read(cx);
 7092
 7093        let file = buffer.file();
 7094
 7095        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7096            return EditPredictionSettings::Disabled;
 7097        };
 7098
 7099        let by_provider = matches!(
 7100            self.menu_edit_predictions_policy,
 7101            MenuEditPredictionsPolicy::ByProvider
 7102        );
 7103
 7104        let show_in_menu = by_provider
 7105            && self
 7106                .edit_prediction_provider
 7107                .as_ref()
 7108                .is_some_and(|provider| provider.provider.show_completions_in_menu());
 7109
 7110        let preview_requires_modifier =
 7111            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7112
 7113        EditPredictionSettings::Enabled {
 7114            show_in_menu,
 7115            preview_requires_modifier,
 7116        }
 7117    }
 7118
 7119    fn should_show_edit_predictions(&self) -> bool {
 7120        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7121    }
 7122
 7123    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7124        matches!(
 7125            self.edit_prediction_preview,
 7126            EditPredictionPreview::Active { .. }
 7127        )
 7128    }
 7129
 7130    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7131        let cursor = self.selections.newest_anchor().head();
 7132        if let Some((buffer, cursor_position)) =
 7133            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7134        {
 7135            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7136        } else {
 7137            false
 7138        }
 7139    }
 7140
 7141    pub fn supports_minimap(&self, cx: &App) -> bool {
 7142        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7143    }
 7144
 7145    fn edit_predictions_enabled_in_buffer(
 7146        &self,
 7147        buffer: &Entity<Buffer>,
 7148        buffer_position: language::Anchor,
 7149        cx: &App,
 7150    ) -> bool {
 7151        maybe!({
 7152            if self.read_only(cx) {
 7153                return Some(false);
 7154            }
 7155            let provider = self.edit_prediction_provider()?;
 7156            if !provider.is_enabled(buffer, buffer_position, cx) {
 7157                return Some(false);
 7158            }
 7159            let buffer = buffer.read(cx);
 7160            let Some(file) = buffer.file() else {
 7161                return Some(true);
 7162            };
 7163            let settings = all_language_settings(Some(file), cx);
 7164            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7165        })
 7166        .unwrap_or(false)
 7167    }
 7168
 7169    fn cycle_edit_prediction(
 7170        &mut self,
 7171        direction: Direction,
 7172        window: &mut Window,
 7173        cx: &mut Context<Self>,
 7174    ) -> Option<()> {
 7175        let provider = self.edit_prediction_provider()?;
 7176        let cursor = self.selections.newest_anchor().head();
 7177        let (buffer, cursor_buffer_position) =
 7178            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7179        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7180            return None;
 7181        }
 7182
 7183        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7184        self.update_visible_edit_prediction(window, cx);
 7185
 7186        Some(())
 7187    }
 7188
 7189    pub fn show_edit_prediction(
 7190        &mut self,
 7191        _: &ShowEditPrediction,
 7192        window: &mut Window,
 7193        cx: &mut Context<Self>,
 7194    ) {
 7195        if !self.has_active_edit_prediction() {
 7196            self.refresh_edit_prediction(false, true, window, cx);
 7197            return;
 7198        }
 7199
 7200        self.update_visible_edit_prediction(window, cx);
 7201    }
 7202
 7203    pub fn display_cursor_names(
 7204        &mut self,
 7205        _: &DisplayCursorNames,
 7206        window: &mut Window,
 7207        cx: &mut Context<Self>,
 7208    ) {
 7209        self.show_cursor_names(window, cx);
 7210    }
 7211
 7212    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7213        self.show_cursor_names = true;
 7214        cx.notify();
 7215        cx.spawn_in(window, async move |this, cx| {
 7216            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7217            this.update(cx, |this, cx| {
 7218                this.show_cursor_names = false;
 7219                cx.notify()
 7220            })
 7221            .ok()
 7222        })
 7223        .detach();
 7224    }
 7225
 7226    pub fn next_edit_prediction(
 7227        &mut self,
 7228        _: &NextEditPrediction,
 7229        window: &mut Window,
 7230        cx: &mut Context<Self>,
 7231    ) {
 7232        if self.has_active_edit_prediction() {
 7233            self.cycle_edit_prediction(Direction::Next, window, cx);
 7234        } else {
 7235            let is_copilot_disabled = self
 7236                .refresh_edit_prediction(false, true, window, cx)
 7237                .is_none();
 7238            if is_copilot_disabled {
 7239                cx.propagate();
 7240            }
 7241        }
 7242    }
 7243
 7244    pub fn previous_edit_prediction(
 7245        &mut self,
 7246        _: &PreviousEditPrediction,
 7247        window: &mut Window,
 7248        cx: &mut Context<Self>,
 7249    ) {
 7250        if self.has_active_edit_prediction() {
 7251            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7252        } else {
 7253            let is_copilot_disabled = self
 7254                .refresh_edit_prediction(false, true, window, cx)
 7255                .is_none();
 7256            if is_copilot_disabled {
 7257                cx.propagate();
 7258            }
 7259        }
 7260    }
 7261
 7262    pub fn accept_edit_prediction(
 7263        &mut self,
 7264        _: &AcceptEditPrediction,
 7265        window: &mut Window,
 7266        cx: &mut Context<Self>,
 7267    ) {
 7268        if self.show_edit_predictions_in_menu() {
 7269            self.hide_context_menu(window, cx);
 7270        }
 7271
 7272        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7273            return;
 7274        };
 7275
 7276        match &active_edit_prediction.completion {
 7277            EditPrediction::MoveWithin { target, .. } => {
 7278                let target = *target;
 7279
 7280                if let Some(position_map) = &self.last_position_map {
 7281                    if position_map
 7282                        .visible_row_range
 7283                        .contains(&target.to_display_point(&position_map.snapshot).row())
 7284                        || !self.edit_prediction_requires_modifier()
 7285                    {
 7286                        self.unfold_ranges(&[target..target], true, false, cx);
 7287                        // Note that this is also done in vim's handler of the Tab action.
 7288                        self.change_selections(
 7289                            SelectionEffects::scroll(Autoscroll::newest()),
 7290                            window,
 7291                            cx,
 7292                            |selections| {
 7293                                selections.select_anchor_ranges([target..target]);
 7294                            },
 7295                        );
 7296                        self.clear_row_highlights::<EditPredictionPreview>();
 7297
 7298                        self.edit_prediction_preview
 7299                            .set_previous_scroll_position(None);
 7300                    } else {
 7301                        self.edit_prediction_preview
 7302                            .set_previous_scroll_position(Some(
 7303                                position_map.snapshot.scroll_anchor,
 7304                            ));
 7305
 7306                        self.highlight_rows::<EditPredictionPreview>(
 7307                            target..target,
 7308                            cx.theme().colors().editor_highlighted_line_background,
 7309                            RowHighlightOptions {
 7310                                autoscroll: true,
 7311                                ..Default::default()
 7312                            },
 7313                            cx,
 7314                        );
 7315                        self.request_autoscroll(Autoscroll::fit(), cx);
 7316                    }
 7317                }
 7318            }
 7319            EditPrediction::MoveOutside { snapshot, target } => {
 7320                if let Some(workspace) = self.workspace() {
 7321                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7322                        .detach_and_log_err(cx);
 7323                }
 7324            }
 7325            EditPrediction::Edit { edits, .. } => {
 7326                self.report_edit_prediction_event(
 7327                    active_edit_prediction.completion_id.clone(),
 7328                    true,
 7329                    cx,
 7330                );
 7331
 7332                if let Some(provider) = self.edit_prediction_provider() {
 7333                    provider.accept(cx);
 7334                }
 7335
 7336                // Store the transaction ID and selections before applying the edit
 7337                let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7338
 7339                let snapshot = self.buffer.read(cx).snapshot(cx);
 7340                let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7341
 7342                self.buffer.update(cx, |buffer, cx| {
 7343                    buffer.edit(edits.iter().cloned(), None, cx)
 7344                });
 7345
 7346                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7347                    s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7348                });
 7349
 7350                let selections = self.selections.disjoint_anchors_arc();
 7351                if let Some(transaction_id_now) = self.buffer.read(cx).last_transaction_id(cx) {
 7352                    let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
 7353                    if has_new_transaction {
 7354                        self.selection_history
 7355                            .insert_transaction(transaction_id_now, selections);
 7356                    }
 7357                }
 7358
 7359                self.update_visible_edit_prediction(window, cx);
 7360                if self.active_edit_prediction.is_none() {
 7361                    self.refresh_edit_prediction(true, true, window, cx);
 7362                }
 7363
 7364                cx.notify();
 7365            }
 7366        }
 7367
 7368        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7369    }
 7370
 7371    pub fn accept_partial_edit_prediction(
 7372        &mut self,
 7373        _: &AcceptPartialEditPrediction,
 7374        window: &mut Window,
 7375        cx: &mut Context<Self>,
 7376    ) {
 7377        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7378            return;
 7379        };
 7380        if self.selections.count() != 1 {
 7381            return;
 7382        }
 7383
 7384        match &active_edit_prediction.completion {
 7385            EditPrediction::MoveWithin { target, .. } => {
 7386                let target = *target;
 7387                self.change_selections(
 7388                    SelectionEffects::scroll(Autoscroll::newest()),
 7389                    window,
 7390                    cx,
 7391                    |selections| {
 7392                        selections.select_anchor_ranges([target..target]);
 7393                    },
 7394                );
 7395            }
 7396            EditPrediction::MoveOutside { snapshot, target } => {
 7397                if let Some(workspace) = self.workspace() {
 7398                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7399                        .detach_and_log_err(cx);
 7400                }
 7401            }
 7402            EditPrediction::Edit { edits, .. } => {
 7403                self.report_edit_prediction_event(
 7404                    active_edit_prediction.completion_id.clone(),
 7405                    true,
 7406                    cx,
 7407                );
 7408
 7409                // Find an insertion that starts at the cursor position.
 7410                let snapshot = self.buffer.read(cx).snapshot(cx);
 7411                let cursor_offset = self
 7412                    .selections
 7413                    .newest::<usize>(&self.display_snapshot(cx))
 7414                    .head();
 7415                let insertion = edits.iter().find_map(|(range, text)| {
 7416                    let range = range.to_offset(&snapshot);
 7417                    if range.is_empty() && range.start == cursor_offset {
 7418                        Some(text)
 7419                    } else {
 7420                        None
 7421                    }
 7422                });
 7423
 7424                if let Some(text) = insertion {
 7425                    let mut partial_completion = text
 7426                        .chars()
 7427                        .by_ref()
 7428                        .take_while(|c| c.is_alphabetic())
 7429                        .collect::<String>();
 7430                    if partial_completion.is_empty() {
 7431                        partial_completion = text
 7432                            .chars()
 7433                            .by_ref()
 7434                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7435                            .collect::<String>();
 7436                    }
 7437
 7438                    cx.emit(EditorEvent::InputHandled {
 7439                        utf16_range_to_replace: None,
 7440                        text: partial_completion.clone().into(),
 7441                    });
 7442
 7443                    self.insert_with_autoindent_mode(&partial_completion, None, window, cx);
 7444
 7445                    self.refresh_edit_prediction(true, true, window, cx);
 7446                    cx.notify();
 7447                } else {
 7448                    self.accept_edit_prediction(&Default::default(), window, cx);
 7449                }
 7450            }
 7451        }
 7452    }
 7453
 7454    fn discard_edit_prediction(
 7455        &mut self,
 7456        should_report_edit_prediction_event: bool,
 7457        cx: &mut Context<Self>,
 7458    ) -> bool {
 7459        if should_report_edit_prediction_event {
 7460            let completion_id = self
 7461                .active_edit_prediction
 7462                .as_ref()
 7463                .and_then(|active_completion| active_completion.completion_id.clone());
 7464
 7465            self.report_edit_prediction_event(completion_id, false, cx);
 7466        }
 7467
 7468        if let Some(provider) = self.edit_prediction_provider() {
 7469            provider.discard(cx);
 7470        }
 7471
 7472        self.take_active_edit_prediction(cx)
 7473    }
 7474
 7475    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7476        let Some(provider) = self.edit_prediction_provider() else {
 7477            return;
 7478        };
 7479
 7480        let Some((_, buffer, _)) = self
 7481            .buffer
 7482            .read(cx)
 7483            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7484        else {
 7485            return;
 7486        };
 7487
 7488        let extension = buffer
 7489            .read(cx)
 7490            .file()
 7491            .and_then(|file| Some(file.path().extension()?.to_string()));
 7492
 7493        let event_type = match accepted {
 7494            true => "Edit Prediction Accepted",
 7495            false => "Edit Prediction Discarded",
 7496        };
 7497        telemetry::event!(
 7498            event_type,
 7499            provider = provider.name(),
 7500            prediction_id = id,
 7501            suggestion_accepted = accepted,
 7502            file_extension = extension,
 7503        );
 7504    }
 7505
 7506    fn open_editor_at_anchor(
 7507        snapshot: &language::BufferSnapshot,
 7508        target: language::Anchor,
 7509        workspace: &Entity<Workspace>,
 7510        window: &mut Window,
 7511        cx: &mut App,
 7512    ) -> Task<Result<()>> {
 7513        workspace.update(cx, |workspace, cx| {
 7514            let path = snapshot.file().map(|file| file.full_path(cx));
 7515            let Some(path) =
 7516                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7517            else {
 7518                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7519            };
 7520            let target = text::ToPoint::to_point(&target, snapshot);
 7521            let item = workspace.open_path(path, None, true, window, cx);
 7522            window.spawn(cx, async move |cx| {
 7523                let Some(editor) = item.await?.downcast::<Editor>() else {
 7524                    return Ok(());
 7525                };
 7526                editor
 7527                    .update_in(cx, |editor, window, cx| {
 7528                        editor.go_to_singleton_buffer_point(target, window, cx);
 7529                    })
 7530                    .ok();
 7531                anyhow::Ok(())
 7532            })
 7533        })
 7534    }
 7535
 7536    pub fn has_active_edit_prediction(&self) -> bool {
 7537        self.active_edit_prediction.is_some()
 7538    }
 7539
 7540    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7541        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7542            return false;
 7543        };
 7544
 7545        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7546        self.clear_highlights::<EditPredictionHighlight>(cx);
 7547        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7548        true
 7549    }
 7550
 7551    /// Returns true when we're displaying the edit prediction popover below the cursor
 7552    /// like we are not previewing and the LSP autocomplete menu is visible
 7553    /// or we are in `when_holding_modifier` mode.
 7554    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7555        if self.edit_prediction_preview_is_active()
 7556            || !self.show_edit_predictions_in_menu()
 7557            || !self.edit_predictions_enabled()
 7558        {
 7559            return false;
 7560        }
 7561
 7562        if self.has_visible_completions_menu() {
 7563            return true;
 7564        }
 7565
 7566        has_completion && self.edit_prediction_requires_modifier()
 7567    }
 7568
 7569    fn handle_modifiers_changed(
 7570        &mut self,
 7571        modifiers: Modifiers,
 7572        position_map: &PositionMap,
 7573        window: &mut Window,
 7574        cx: &mut Context<Self>,
 7575    ) {
 7576        if self.show_edit_predictions_in_menu() {
 7577            self.update_edit_prediction_preview(&modifiers, window, cx);
 7578        }
 7579
 7580        self.update_selection_mode(&modifiers, position_map, window, cx);
 7581
 7582        let mouse_position = window.mouse_position();
 7583        if !position_map.text_hitbox.is_hovered(window) {
 7584            return;
 7585        }
 7586
 7587        self.update_hovered_link(
 7588            position_map.point_for_position(mouse_position),
 7589            &position_map.snapshot,
 7590            modifiers,
 7591            window,
 7592            cx,
 7593        )
 7594    }
 7595
 7596    fn multi_cursor_modifier(invert: bool, modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7597        let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
 7598        if invert {
 7599            match multi_cursor_setting {
 7600                MultiCursorModifier::Alt => modifiers.alt,
 7601                MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 7602            }
 7603        } else {
 7604            match multi_cursor_setting {
 7605                MultiCursorModifier::Alt => modifiers.secondary(),
 7606                MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7607            }
 7608        }
 7609    }
 7610
 7611    fn columnar_selection_mode(
 7612        modifiers: &Modifiers,
 7613        cx: &mut Context<Self>,
 7614    ) -> Option<ColumnarMode> {
 7615        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 7616            if Self::multi_cursor_modifier(false, modifiers, cx) {
 7617                Some(ColumnarMode::FromMouse)
 7618            } else if Self::multi_cursor_modifier(true, modifiers, cx) {
 7619                Some(ColumnarMode::FromSelection)
 7620            } else {
 7621                None
 7622            }
 7623        } else {
 7624            None
 7625        }
 7626    }
 7627
 7628    fn update_selection_mode(
 7629        &mut self,
 7630        modifiers: &Modifiers,
 7631        position_map: &PositionMap,
 7632        window: &mut Window,
 7633        cx: &mut Context<Self>,
 7634    ) {
 7635        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 7636            return;
 7637        };
 7638        if self.selections.pending_anchor().is_none() {
 7639            return;
 7640        }
 7641
 7642        let mouse_position = window.mouse_position();
 7643        let point_for_position = position_map.point_for_position(mouse_position);
 7644        let position = point_for_position.previous_valid;
 7645
 7646        self.select(
 7647            SelectPhase::BeginColumnar {
 7648                position,
 7649                reset: false,
 7650                mode,
 7651                goal_column: point_for_position.exact_unclipped.column(),
 7652            },
 7653            window,
 7654            cx,
 7655        );
 7656    }
 7657
 7658    fn update_edit_prediction_preview(
 7659        &mut self,
 7660        modifiers: &Modifiers,
 7661        window: &mut Window,
 7662        cx: &mut Context<Self>,
 7663    ) {
 7664        let mut modifiers_held = false;
 7665        if let Some(accept_keystroke) = self
 7666            .accept_edit_prediction_keybind(false, window, cx)
 7667            .keystroke()
 7668        {
 7669            modifiers_held = modifiers_held
 7670                || (accept_keystroke.modifiers() == modifiers
 7671                    && accept_keystroke.modifiers().modified());
 7672        };
 7673        if let Some(accept_partial_keystroke) = self
 7674            .accept_edit_prediction_keybind(true, window, cx)
 7675            .keystroke()
 7676        {
 7677            modifiers_held = modifiers_held
 7678                || (accept_partial_keystroke.modifiers() == modifiers
 7679                    && accept_partial_keystroke.modifiers().modified());
 7680        }
 7681
 7682        if modifiers_held {
 7683            if matches!(
 7684                self.edit_prediction_preview,
 7685                EditPredictionPreview::Inactive { .. }
 7686            ) {
 7687                self.edit_prediction_preview = EditPredictionPreview::Active {
 7688                    previous_scroll_position: None,
 7689                    since: Instant::now(),
 7690                };
 7691
 7692                self.update_visible_edit_prediction(window, cx);
 7693                cx.notify();
 7694            }
 7695        } else if let EditPredictionPreview::Active {
 7696            previous_scroll_position,
 7697            since,
 7698        } = self.edit_prediction_preview
 7699        {
 7700            if let (Some(previous_scroll_position), Some(position_map)) =
 7701                (previous_scroll_position, self.last_position_map.as_ref())
 7702            {
 7703                self.set_scroll_position(
 7704                    previous_scroll_position
 7705                        .scroll_position(&position_map.snapshot.display_snapshot),
 7706                    window,
 7707                    cx,
 7708                );
 7709            }
 7710
 7711            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 7712                released_too_fast: since.elapsed() < Duration::from_millis(200),
 7713            };
 7714            self.clear_row_highlights::<EditPredictionPreview>();
 7715            self.update_visible_edit_prediction(window, cx);
 7716            cx.notify();
 7717        }
 7718    }
 7719
 7720    fn update_visible_edit_prediction(
 7721        &mut self,
 7722        _window: &mut Window,
 7723        cx: &mut Context<Self>,
 7724    ) -> Option<()> {
 7725        if DisableAiSettings::get_global(cx).disable_ai {
 7726            return None;
 7727        }
 7728
 7729        if self.ime_transaction.is_some() {
 7730            self.discard_edit_prediction(false, cx);
 7731            return None;
 7732        }
 7733
 7734        let selection = self.selections.newest_anchor();
 7735        let cursor = selection.head();
 7736        let multibuffer = self.buffer.read(cx).snapshot(cx);
 7737        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 7738        let excerpt_id = cursor.excerpt_id;
 7739
 7740        let show_in_menu = self.show_edit_predictions_in_menu();
 7741        let completions_menu_has_precedence = !show_in_menu
 7742            && (self.context_menu.borrow().is_some()
 7743                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 7744
 7745        if completions_menu_has_precedence
 7746            || !offset_selection.is_empty()
 7747            || self
 7748                .active_edit_prediction
 7749                .as_ref()
 7750                .is_some_and(|completion| {
 7751                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 7752                        return false;
 7753                    };
 7754                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 7755                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 7756                    !invalidation_range.contains(&offset_selection.head())
 7757                })
 7758        {
 7759            self.discard_edit_prediction(false, cx);
 7760            return None;
 7761        }
 7762
 7763        self.take_active_edit_prediction(cx);
 7764        let Some(provider) = self.edit_prediction_provider() else {
 7765            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7766            return None;
 7767        };
 7768
 7769        let (buffer, cursor_buffer_position) =
 7770            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7771
 7772        self.edit_prediction_settings =
 7773            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7774
 7775        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 7776
 7777        if self.edit_prediction_indent_conflict {
 7778            let cursor_point = cursor.to_point(&multibuffer);
 7779
 7780            let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx);
 7781
 7782            if let Some((_, indent)) = indents.iter().next()
 7783                && indent.len == cursor_point.column
 7784            {
 7785                self.edit_prediction_indent_conflict = false;
 7786            }
 7787        }
 7788
 7789        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 7790
 7791        let (completion_id, edits, edit_preview) = match edit_prediction {
 7792            edit_prediction::EditPrediction::Local {
 7793                id,
 7794                edits,
 7795                edit_preview,
 7796            } => (id, edits, edit_preview),
 7797            edit_prediction::EditPrediction::Jump {
 7798                id,
 7799                snapshot,
 7800                target,
 7801            } => {
 7802                self.stale_edit_prediction_in_menu = None;
 7803                self.active_edit_prediction = Some(EditPredictionState {
 7804                    inlay_ids: vec![],
 7805                    completion: EditPrediction::MoveOutside { snapshot, target },
 7806                    completion_id: id,
 7807                    invalidation_range: None,
 7808                });
 7809                cx.notify();
 7810                return Some(());
 7811            }
 7812        };
 7813
 7814        let edits = edits
 7815            .into_iter()
 7816            .flat_map(|(range, new_text)| {
 7817                Some((
 7818                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 7819                    new_text,
 7820                ))
 7821            })
 7822            .collect::<Vec<_>>();
 7823        if edits.is_empty() {
 7824            return None;
 7825        }
 7826
 7827        let first_edit_start = edits.first().unwrap().0.start;
 7828        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 7829        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 7830
 7831        let last_edit_end = edits.last().unwrap().0.end;
 7832        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 7833        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 7834
 7835        let cursor_row = cursor.to_point(&multibuffer).row;
 7836
 7837        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 7838
 7839        let mut inlay_ids = Vec::new();
 7840        let invalidation_row_range;
 7841        let move_invalidation_row_range = if cursor_row < edit_start_row {
 7842            Some(cursor_row..edit_end_row)
 7843        } else if cursor_row > edit_end_row {
 7844            Some(edit_start_row..cursor_row)
 7845        } else {
 7846            None
 7847        };
 7848        let supports_jump = self
 7849            .edit_prediction_provider
 7850            .as_ref()
 7851            .map(|provider| provider.provider.supports_jump_to_edit())
 7852            .unwrap_or(true);
 7853
 7854        let is_move = supports_jump
 7855            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 7856        let completion = if is_move {
 7857            invalidation_row_range =
 7858                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 7859            let target = first_edit_start;
 7860            EditPrediction::MoveWithin { target, snapshot }
 7861        } else {
 7862            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 7863                && !self.edit_predictions_hidden_for_vim_mode;
 7864
 7865            if show_completions_in_buffer {
 7866                if edits
 7867                    .iter()
 7868                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 7869                {
 7870                    let mut inlays = Vec::new();
 7871                    for (range, new_text) in &edits {
 7872                        let inlay = Inlay::edit_prediction(
 7873                            post_inc(&mut self.next_inlay_id),
 7874                            range.start,
 7875                            new_text.as_str(),
 7876                        );
 7877                        inlay_ids.push(inlay.id);
 7878                        inlays.push(inlay);
 7879                    }
 7880
 7881                    self.splice_inlays(&[], inlays, cx);
 7882                } else {
 7883                    let background_color = cx.theme().status().deleted_background;
 7884                    self.highlight_text::<EditPredictionHighlight>(
 7885                        edits.iter().map(|(range, _)| range.clone()).collect(),
 7886                        HighlightStyle {
 7887                            background_color: Some(background_color),
 7888                            ..Default::default()
 7889                        },
 7890                        cx,
 7891                    );
 7892                }
 7893            }
 7894
 7895            invalidation_row_range = edit_start_row..edit_end_row;
 7896
 7897            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 7898                if provider.show_tab_accept_marker() {
 7899                    EditDisplayMode::TabAccept
 7900                } else {
 7901                    EditDisplayMode::Inline
 7902                }
 7903            } else {
 7904                EditDisplayMode::DiffPopover
 7905            };
 7906
 7907            EditPrediction::Edit {
 7908                edits,
 7909                edit_preview,
 7910                display_mode,
 7911                snapshot,
 7912            }
 7913        };
 7914
 7915        let invalidation_range = multibuffer
 7916            .anchor_before(Point::new(invalidation_row_range.start, 0))
 7917            ..multibuffer.anchor_after(Point::new(
 7918                invalidation_row_range.end,
 7919                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 7920            ));
 7921
 7922        self.stale_edit_prediction_in_menu = None;
 7923        self.active_edit_prediction = Some(EditPredictionState {
 7924            inlay_ids,
 7925            completion,
 7926            completion_id,
 7927            invalidation_range: Some(invalidation_range),
 7928        });
 7929
 7930        cx.notify();
 7931
 7932        Some(())
 7933    }
 7934
 7935    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionProviderHandle>> {
 7936        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 7937    }
 7938
 7939    fn clear_tasks(&mut self) {
 7940        self.tasks.clear()
 7941    }
 7942
 7943    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 7944        if self.tasks.insert(key, value).is_some() {
 7945            // This case should hopefully be rare, but just in case...
 7946            log::error!(
 7947                "multiple different run targets found on a single line, only the last target will be rendered"
 7948            )
 7949        }
 7950    }
 7951
 7952    /// Get all display points of breakpoints that will be rendered within editor
 7953    ///
 7954    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 7955    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 7956    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 7957    fn active_breakpoints(
 7958        &self,
 7959        range: Range<DisplayRow>,
 7960        window: &mut Window,
 7961        cx: &mut Context<Self>,
 7962    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 7963        let mut breakpoint_display_points = HashMap::default();
 7964
 7965        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 7966            return breakpoint_display_points;
 7967        };
 7968
 7969        let snapshot = self.snapshot(window, cx);
 7970
 7971        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 7972        let Some(project) = self.project() else {
 7973            return breakpoint_display_points;
 7974        };
 7975
 7976        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 7977            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 7978
 7979        for (buffer_snapshot, range, excerpt_id) in
 7980            multi_buffer_snapshot.range_to_buffer_ranges(range)
 7981        {
 7982            let Some(buffer) = project
 7983                .read(cx)
 7984                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 7985            else {
 7986                continue;
 7987            };
 7988            let breakpoints = breakpoint_store.read(cx).breakpoints(
 7989                &buffer,
 7990                Some(
 7991                    buffer_snapshot.anchor_before(range.start)
 7992                        ..buffer_snapshot.anchor_after(range.end),
 7993                ),
 7994                buffer_snapshot,
 7995                cx,
 7996            );
 7997            for (breakpoint, state) in breakpoints {
 7998                let multi_buffer_anchor =
 7999                    Anchor::in_buffer(excerpt_id, buffer_snapshot.remote_id(), breakpoint.position);
 8000                let position = multi_buffer_anchor
 8001                    .to_point(&multi_buffer_snapshot)
 8002                    .to_display_point(&snapshot);
 8003
 8004                breakpoint_display_points.insert(
 8005                    position.row(),
 8006                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8007                );
 8008            }
 8009        }
 8010
 8011        breakpoint_display_points
 8012    }
 8013
 8014    fn breakpoint_context_menu(
 8015        &self,
 8016        anchor: Anchor,
 8017        window: &mut Window,
 8018        cx: &mut Context<Self>,
 8019    ) -> Entity<ui::ContextMenu> {
 8020        let weak_editor = cx.weak_entity();
 8021        let focus_handle = self.focus_handle(cx);
 8022
 8023        let row = self
 8024            .buffer
 8025            .read(cx)
 8026            .snapshot(cx)
 8027            .summary_for_anchor::<Point>(&anchor)
 8028            .row;
 8029
 8030        let breakpoint = self
 8031            .breakpoint_at_row(row, window, cx)
 8032            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8033
 8034        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8035            "Edit Log Breakpoint"
 8036        } else {
 8037            "Set Log Breakpoint"
 8038        };
 8039
 8040        let condition_breakpoint_msg = if breakpoint
 8041            .as_ref()
 8042            .is_some_and(|bp| bp.1.condition.is_some())
 8043        {
 8044            "Edit Condition Breakpoint"
 8045        } else {
 8046            "Set Condition Breakpoint"
 8047        };
 8048
 8049        let hit_condition_breakpoint_msg = if breakpoint
 8050            .as_ref()
 8051            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8052        {
 8053            "Edit Hit Condition Breakpoint"
 8054        } else {
 8055            "Set Hit Condition Breakpoint"
 8056        };
 8057
 8058        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8059            "Unset Breakpoint"
 8060        } else {
 8061            "Set Breakpoint"
 8062        };
 8063
 8064        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8065
 8066        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8067            BreakpointState::Enabled => Some("Disable"),
 8068            BreakpointState::Disabled => Some("Enable"),
 8069        });
 8070
 8071        let (anchor, breakpoint) =
 8072            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8073
 8074        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8075            menu.on_blur_subscription(Subscription::new(|| {}))
 8076                .context(focus_handle)
 8077                .when(run_to_cursor, |this| {
 8078                    let weak_editor = weak_editor.clone();
 8079                    this.entry("Run to cursor", None, move |window, cx| {
 8080                        weak_editor
 8081                            .update(cx, |editor, cx| {
 8082                                editor.change_selections(
 8083                                    SelectionEffects::no_scroll(),
 8084                                    window,
 8085                                    cx,
 8086                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8087                                );
 8088                            })
 8089                            .ok();
 8090
 8091                        window.dispatch_action(Box::new(RunToCursor), cx);
 8092                    })
 8093                    .separator()
 8094                })
 8095                .when_some(toggle_state_msg, |this, msg| {
 8096                    this.entry(msg, None, {
 8097                        let weak_editor = weak_editor.clone();
 8098                        let breakpoint = breakpoint.clone();
 8099                        move |_window, cx| {
 8100                            weak_editor
 8101                                .update(cx, |this, cx| {
 8102                                    this.edit_breakpoint_at_anchor(
 8103                                        anchor,
 8104                                        breakpoint.as_ref().clone(),
 8105                                        BreakpointEditAction::InvertState,
 8106                                        cx,
 8107                                    );
 8108                                })
 8109                                .log_err();
 8110                        }
 8111                    })
 8112                })
 8113                .entry(set_breakpoint_msg, None, {
 8114                    let weak_editor = weak_editor.clone();
 8115                    let breakpoint = breakpoint.clone();
 8116                    move |_window, cx| {
 8117                        weak_editor
 8118                            .update(cx, |this, cx| {
 8119                                this.edit_breakpoint_at_anchor(
 8120                                    anchor,
 8121                                    breakpoint.as_ref().clone(),
 8122                                    BreakpointEditAction::Toggle,
 8123                                    cx,
 8124                                );
 8125                            })
 8126                            .log_err();
 8127                    }
 8128                })
 8129                .entry(log_breakpoint_msg, None, {
 8130                    let breakpoint = breakpoint.clone();
 8131                    let weak_editor = weak_editor.clone();
 8132                    move |window, cx| {
 8133                        weak_editor
 8134                            .update(cx, |this, cx| {
 8135                                this.add_edit_breakpoint_block(
 8136                                    anchor,
 8137                                    breakpoint.as_ref(),
 8138                                    BreakpointPromptEditAction::Log,
 8139                                    window,
 8140                                    cx,
 8141                                );
 8142                            })
 8143                            .log_err();
 8144                    }
 8145                })
 8146                .entry(condition_breakpoint_msg, None, {
 8147                    let breakpoint = breakpoint.clone();
 8148                    let weak_editor = weak_editor.clone();
 8149                    move |window, cx| {
 8150                        weak_editor
 8151                            .update(cx, |this, cx| {
 8152                                this.add_edit_breakpoint_block(
 8153                                    anchor,
 8154                                    breakpoint.as_ref(),
 8155                                    BreakpointPromptEditAction::Condition,
 8156                                    window,
 8157                                    cx,
 8158                                );
 8159                            })
 8160                            .log_err();
 8161                    }
 8162                })
 8163                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8164                    weak_editor
 8165                        .update(cx, |this, cx| {
 8166                            this.add_edit_breakpoint_block(
 8167                                anchor,
 8168                                breakpoint.as_ref(),
 8169                                BreakpointPromptEditAction::HitCondition,
 8170                                window,
 8171                                cx,
 8172                            );
 8173                        })
 8174                        .log_err();
 8175                })
 8176        })
 8177    }
 8178
 8179    fn render_breakpoint(
 8180        &self,
 8181        position: Anchor,
 8182        row: DisplayRow,
 8183        breakpoint: &Breakpoint,
 8184        state: Option<BreakpointSessionState>,
 8185        cx: &mut Context<Self>,
 8186    ) -> IconButton {
 8187        let is_rejected = state.is_some_and(|s| !s.verified);
 8188        // Is it a breakpoint that shows up when hovering over gutter?
 8189        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8190            (false, false),
 8191            |PhantomBreakpointIndicator {
 8192                 is_active,
 8193                 display_row,
 8194                 collides_with_existing_breakpoint,
 8195             }| {
 8196                (
 8197                    is_active && display_row == row,
 8198                    collides_with_existing_breakpoint,
 8199                )
 8200            },
 8201        );
 8202
 8203        let (color, icon) = {
 8204            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8205                (false, false) => ui::IconName::DebugBreakpoint,
 8206                (true, false) => ui::IconName::DebugLogBreakpoint,
 8207                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8208                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8209            };
 8210
 8211            let color = if is_phantom {
 8212                Color::Hint
 8213            } else if is_rejected {
 8214                Color::Disabled
 8215            } else {
 8216                Color::Debugger
 8217            };
 8218
 8219            (color, icon)
 8220        };
 8221
 8222        let breakpoint = Arc::from(breakpoint.clone());
 8223
 8224        let alt_as_text = gpui::Keystroke {
 8225            modifiers: Modifiers::secondary_key(),
 8226            ..Default::default()
 8227        };
 8228        let primary_action_text = if breakpoint.is_disabled() {
 8229            "Enable breakpoint"
 8230        } else if is_phantom && !collides_with_existing {
 8231            "Set breakpoint"
 8232        } else {
 8233            "Unset breakpoint"
 8234        };
 8235        let focus_handle = self.focus_handle.clone();
 8236
 8237        let meta = if is_rejected {
 8238            SharedString::from("No executable code is associated with this line.")
 8239        } else if collides_with_existing && !breakpoint.is_disabled() {
 8240            SharedString::from(format!(
 8241                "{alt_as_text}-click to disable,\nright-click for more options."
 8242            ))
 8243        } else {
 8244            SharedString::from("Right-click for more options.")
 8245        };
 8246        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8247            .icon_size(IconSize::XSmall)
 8248            .size(ui::ButtonSize::None)
 8249            .when(is_rejected, |this| {
 8250                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8251            })
 8252            .icon_color(color)
 8253            .style(ButtonStyle::Transparent)
 8254            .on_click(cx.listener({
 8255                move |editor, event: &ClickEvent, window, cx| {
 8256                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8257                        BreakpointEditAction::InvertState
 8258                    } else {
 8259                        BreakpointEditAction::Toggle
 8260                    };
 8261
 8262                    window.focus(&editor.focus_handle(cx));
 8263                    editor.edit_breakpoint_at_anchor(
 8264                        position,
 8265                        breakpoint.as_ref().clone(),
 8266                        edit_action,
 8267                        cx,
 8268                    );
 8269                }
 8270            }))
 8271            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8272                editor.set_breakpoint_context_menu(
 8273                    row,
 8274                    Some(position),
 8275                    event.position(),
 8276                    window,
 8277                    cx,
 8278                );
 8279            }))
 8280            .tooltip(move |_window, cx| {
 8281                Tooltip::with_meta_in(
 8282                    primary_action_text,
 8283                    Some(&ToggleBreakpoint),
 8284                    meta.clone(),
 8285                    &focus_handle,
 8286                    cx,
 8287                )
 8288            })
 8289    }
 8290
 8291    fn build_tasks_context(
 8292        project: &Entity<Project>,
 8293        buffer: &Entity<Buffer>,
 8294        buffer_row: u32,
 8295        tasks: &Arc<RunnableTasks>,
 8296        cx: &mut Context<Self>,
 8297    ) -> Task<Option<task::TaskContext>> {
 8298        let position = Point::new(buffer_row, tasks.column);
 8299        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8300        let location = Location {
 8301            buffer: buffer.clone(),
 8302            range: range_start..range_start,
 8303        };
 8304        // Fill in the environmental variables from the tree-sitter captures
 8305        let mut captured_task_variables = TaskVariables::default();
 8306        for (capture_name, value) in tasks.extra_variables.clone() {
 8307            captured_task_variables.insert(
 8308                task::VariableName::Custom(capture_name.into()),
 8309                value.clone(),
 8310            );
 8311        }
 8312        project.update(cx, |project, cx| {
 8313            project.task_store().update(cx, |task_store, cx| {
 8314                task_store.task_context_for_location(captured_task_variables, location, cx)
 8315            })
 8316        })
 8317    }
 8318
 8319    pub fn spawn_nearest_task(
 8320        &mut self,
 8321        action: &SpawnNearestTask,
 8322        window: &mut Window,
 8323        cx: &mut Context<Self>,
 8324    ) {
 8325        let Some((workspace, _)) = self.workspace.clone() else {
 8326            return;
 8327        };
 8328        let Some(project) = self.project.clone() else {
 8329            return;
 8330        };
 8331
 8332        // Try to find a closest, enclosing node using tree-sitter that has a task
 8333        let Some((buffer, buffer_row, tasks)) = self
 8334            .find_enclosing_node_task(cx)
 8335            // Or find the task that's closest in row-distance.
 8336            .or_else(|| self.find_closest_task(cx))
 8337        else {
 8338            return;
 8339        };
 8340
 8341        let reveal_strategy = action.reveal;
 8342        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8343        cx.spawn_in(window, async move |_, cx| {
 8344            let context = task_context.await?;
 8345            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8346
 8347            let resolved = &mut resolved_task.resolved;
 8348            resolved.reveal = reveal_strategy;
 8349
 8350            workspace
 8351                .update_in(cx, |workspace, window, cx| {
 8352                    workspace.schedule_resolved_task(
 8353                        task_source_kind,
 8354                        resolved_task,
 8355                        false,
 8356                        window,
 8357                        cx,
 8358                    );
 8359                })
 8360                .ok()
 8361        })
 8362        .detach();
 8363    }
 8364
 8365    fn find_closest_task(
 8366        &mut self,
 8367        cx: &mut Context<Self>,
 8368    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8369        let cursor_row = self
 8370            .selections
 8371            .newest_adjusted(&self.display_snapshot(cx))
 8372            .head()
 8373            .row;
 8374
 8375        let ((buffer_id, row), tasks) = self
 8376            .tasks
 8377            .iter()
 8378            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8379
 8380        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8381        let tasks = Arc::new(tasks.to_owned());
 8382        Some((buffer, *row, tasks))
 8383    }
 8384
 8385    fn find_enclosing_node_task(
 8386        &mut self,
 8387        cx: &mut Context<Self>,
 8388    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8389        let snapshot = self.buffer.read(cx).snapshot(cx);
 8390        let offset = self
 8391            .selections
 8392            .newest::<usize>(&self.display_snapshot(cx))
 8393            .head();
 8394        let excerpt = snapshot.excerpt_containing(offset..offset)?;
 8395        let buffer_id = excerpt.buffer().remote_id();
 8396
 8397        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8398        let mut cursor = layer.node().walk();
 8399
 8400        while cursor.goto_first_child_for_byte(offset).is_some() {
 8401            if cursor.node().end_byte() == offset {
 8402                cursor.goto_next_sibling();
 8403            }
 8404        }
 8405
 8406        // Ascend to the smallest ancestor that contains the range and has a task.
 8407        loop {
 8408            let node = cursor.node();
 8409            let node_range = node.byte_range();
 8410            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8411
 8412            // Check if this node contains our offset
 8413            if node_range.start <= offset && node_range.end >= offset {
 8414                // If it contains offset, check for task
 8415                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8416                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8417                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8418                }
 8419            }
 8420
 8421            if !cursor.goto_parent() {
 8422                break;
 8423            }
 8424        }
 8425        None
 8426    }
 8427
 8428    fn render_run_indicator(
 8429        &self,
 8430        _style: &EditorStyle,
 8431        is_active: bool,
 8432        row: DisplayRow,
 8433        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8434        cx: &mut Context<Self>,
 8435    ) -> IconButton {
 8436        let color = Color::Muted;
 8437        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8438
 8439        IconButton::new(
 8440            ("run_indicator", row.0 as usize),
 8441            ui::IconName::PlayOutlined,
 8442        )
 8443        .shape(ui::IconButtonShape::Square)
 8444        .icon_size(IconSize::XSmall)
 8445        .icon_color(color)
 8446        .toggle_state(is_active)
 8447        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8448            let quick_launch = match e {
 8449                ClickEvent::Keyboard(_) => true,
 8450                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8451            };
 8452
 8453            window.focus(&editor.focus_handle(cx));
 8454            editor.toggle_code_actions(
 8455                &ToggleCodeActions {
 8456                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8457                    quick_launch,
 8458                },
 8459                window,
 8460                cx,
 8461            );
 8462        }))
 8463        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8464            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8465        }))
 8466    }
 8467
 8468    pub fn context_menu_visible(&self) -> bool {
 8469        !self.edit_prediction_preview_is_active()
 8470            && self
 8471                .context_menu
 8472                .borrow()
 8473                .as_ref()
 8474                .is_some_and(|menu| menu.visible())
 8475    }
 8476
 8477    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8478        self.context_menu
 8479            .borrow()
 8480            .as_ref()
 8481            .map(|menu| menu.origin())
 8482    }
 8483
 8484    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8485        self.context_menu_options = Some(options);
 8486    }
 8487
 8488    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8489    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8490
 8491    fn render_edit_prediction_popover(
 8492        &mut self,
 8493        text_bounds: &Bounds<Pixels>,
 8494        content_origin: gpui::Point<Pixels>,
 8495        right_margin: Pixels,
 8496        editor_snapshot: &EditorSnapshot,
 8497        visible_row_range: Range<DisplayRow>,
 8498        scroll_top: ScrollOffset,
 8499        scroll_bottom: ScrollOffset,
 8500        line_layouts: &[LineWithInvisibles],
 8501        line_height: Pixels,
 8502        scroll_position: gpui::Point<ScrollOffset>,
 8503        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8504        newest_selection_head: Option<DisplayPoint>,
 8505        editor_width: Pixels,
 8506        style: &EditorStyle,
 8507        window: &mut Window,
 8508        cx: &mut App,
 8509    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8510        if self.mode().is_minimap() {
 8511            return None;
 8512        }
 8513        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8514
 8515        if self.edit_prediction_visible_in_cursor_popover(true) {
 8516            return None;
 8517        }
 8518
 8519        match &active_edit_prediction.completion {
 8520            EditPrediction::MoveWithin { target, .. } => {
 8521                let target_display_point = target.to_display_point(editor_snapshot);
 8522
 8523                if self.edit_prediction_requires_modifier() {
 8524                    if !self.edit_prediction_preview_is_active() {
 8525                        return None;
 8526                    }
 8527
 8528                    self.render_edit_prediction_modifier_jump_popover(
 8529                        text_bounds,
 8530                        content_origin,
 8531                        visible_row_range,
 8532                        line_layouts,
 8533                        line_height,
 8534                        scroll_pixel_position,
 8535                        newest_selection_head,
 8536                        target_display_point,
 8537                        window,
 8538                        cx,
 8539                    )
 8540                } else {
 8541                    self.render_edit_prediction_eager_jump_popover(
 8542                        text_bounds,
 8543                        content_origin,
 8544                        editor_snapshot,
 8545                        visible_row_range,
 8546                        scroll_top,
 8547                        scroll_bottom,
 8548                        line_height,
 8549                        scroll_pixel_position,
 8550                        target_display_point,
 8551                        editor_width,
 8552                        window,
 8553                        cx,
 8554                    )
 8555                }
 8556            }
 8557            EditPrediction::Edit {
 8558                display_mode: EditDisplayMode::Inline,
 8559                ..
 8560            } => None,
 8561            EditPrediction::Edit {
 8562                display_mode: EditDisplayMode::TabAccept,
 8563                edits,
 8564                ..
 8565            } => {
 8566                let range = &edits.first()?.0;
 8567                let target_display_point = range.end.to_display_point(editor_snapshot);
 8568
 8569                self.render_edit_prediction_end_of_line_popover(
 8570                    "Accept",
 8571                    editor_snapshot,
 8572                    visible_row_range,
 8573                    target_display_point,
 8574                    line_height,
 8575                    scroll_pixel_position,
 8576                    content_origin,
 8577                    editor_width,
 8578                    window,
 8579                    cx,
 8580                )
 8581            }
 8582            EditPrediction::Edit {
 8583                edits,
 8584                edit_preview,
 8585                display_mode: EditDisplayMode::DiffPopover,
 8586                snapshot,
 8587            } => self.render_edit_prediction_diff_popover(
 8588                text_bounds,
 8589                content_origin,
 8590                right_margin,
 8591                editor_snapshot,
 8592                visible_row_range,
 8593                line_layouts,
 8594                line_height,
 8595                scroll_position,
 8596                scroll_pixel_position,
 8597                newest_selection_head,
 8598                editor_width,
 8599                style,
 8600                edits,
 8601                edit_preview,
 8602                snapshot,
 8603                window,
 8604                cx,
 8605            ),
 8606            EditPrediction::MoveOutside { snapshot, .. } => {
 8607                let file_name = snapshot
 8608                    .file()
 8609                    .map(|file| file.file_name(cx))
 8610                    .unwrap_or("untitled");
 8611                let mut element = self
 8612                    .render_edit_prediction_line_popover(
 8613                        format!("Jump to {file_name}"),
 8614                        Some(IconName::ZedPredict),
 8615                        window,
 8616                        cx,
 8617                    )
 8618                    .into_any();
 8619
 8620                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8621                let origin_x = text_bounds.size.width / 2. - size.width / 2.;
 8622                let origin_y = text_bounds.size.height - size.height - px(30.);
 8623                let origin = text_bounds.origin + gpui::Point::new(origin_x, origin_y);
 8624                element.prepaint_at(origin, window, cx);
 8625
 8626                Some((element, origin))
 8627            }
 8628        }
 8629    }
 8630
 8631    fn render_edit_prediction_modifier_jump_popover(
 8632        &mut self,
 8633        text_bounds: &Bounds<Pixels>,
 8634        content_origin: gpui::Point<Pixels>,
 8635        visible_row_range: Range<DisplayRow>,
 8636        line_layouts: &[LineWithInvisibles],
 8637        line_height: Pixels,
 8638        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8639        newest_selection_head: Option<DisplayPoint>,
 8640        target_display_point: DisplayPoint,
 8641        window: &mut Window,
 8642        cx: &mut App,
 8643    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8644        let scrolled_content_origin =
 8645            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 8646
 8647        const SCROLL_PADDING_Y: Pixels = px(12.);
 8648
 8649        if target_display_point.row() < visible_row_range.start {
 8650            return self.render_edit_prediction_scroll_popover(
 8651                |_| SCROLL_PADDING_Y,
 8652                IconName::ArrowUp,
 8653                visible_row_range,
 8654                line_layouts,
 8655                newest_selection_head,
 8656                scrolled_content_origin,
 8657                window,
 8658                cx,
 8659            );
 8660        } else if target_display_point.row() >= visible_row_range.end {
 8661            return self.render_edit_prediction_scroll_popover(
 8662                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 8663                IconName::ArrowDown,
 8664                visible_row_range,
 8665                line_layouts,
 8666                newest_selection_head,
 8667                scrolled_content_origin,
 8668                window,
 8669                cx,
 8670            );
 8671        }
 8672
 8673        const POLE_WIDTH: Pixels = px(2.);
 8674
 8675        let line_layout =
 8676            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 8677        let target_column = target_display_point.column() as usize;
 8678
 8679        let target_x = line_layout.x_for_index(target_column);
 8680        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 8681            - scroll_pixel_position.y;
 8682
 8683        let flag_on_right = target_x < text_bounds.size.width / 2.;
 8684
 8685        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 8686        border_color.l += 0.001;
 8687
 8688        let mut element = v_flex()
 8689            .items_end()
 8690            .when(flag_on_right, |el| el.items_start())
 8691            .child(if flag_on_right {
 8692                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8693                    .rounded_bl(px(0.))
 8694                    .rounded_tl(px(0.))
 8695                    .border_l_2()
 8696                    .border_color(border_color)
 8697            } else {
 8698                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 8699                    .rounded_br(px(0.))
 8700                    .rounded_tr(px(0.))
 8701                    .border_r_2()
 8702                    .border_color(border_color)
 8703            })
 8704            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 8705            .into_any();
 8706
 8707        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8708
 8709        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 8710            - point(
 8711                if flag_on_right {
 8712                    POLE_WIDTH
 8713                } else {
 8714                    size.width - POLE_WIDTH
 8715                },
 8716                size.height - line_height,
 8717            );
 8718
 8719        origin.x = origin.x.max(content_origin.x);
 8720
 8721        element.prepaint_at(origin, window, cx);
 8722
 8723        Some((element, origin))
 8724    }
 8725
 8726    fn render_edit_prediction_scroll_popover(
 8727        &mut self,
 8728        to_y: impl Fn(Size<Pixels>) -> Pixels,
 8729        scroll_icon: IconName,
 8730        visible_row_range: Range<DisplayRow>,
 8731        line_layouts: &[LineWithInvisibles],
 8732        newest_selection_head: Option<DisplayPoint>,
 8733        scrolled_content_origin: gpui::Point<Pixels>,
 8734        window: &mut Window,
 8735        cx: &mut App,
 8736    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8737        let mut element = self
 8738            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 8739            .into_any();
 8740
 8741        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8742
 8743        let cursor = newest_selection_head?;
 8744        let cursor_row_layout =
 8745            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 8746        let cursor_column = cursor.column() as usize;
 8747
 8748        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 8749
 8750        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 8751
 8752        element.prepaint_at(origin, window, cx);
 8753        Some((element, origin))
 8754    }
 8755
 8756    fn render_edit_prediction_eager_jump_popover(
 8757        &mut self,
 8758        text_bounds: &Bounds<Pixels>,
 8759        content_origin: gpui::Point<Pixels>,
 8760        editor_snapshot: &EditorSnapshot,
 8761        visible_row_range: Range<DisplayRow>,
 8762        scroll_top: ScrollOffset,
 8763        scroll_bottom: ScrollOffset,
 8764        line_height: Pixels,
 8765        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8766        target_display_point: DisplayPoint,
 8767        editor_width: Pixels,
 8768        window: &mut Window,
 8769        cx: &mut App,
 8770    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8771        if target_display_point.row().as_f64() < scroll_top {
 8772            let mut element = self
 8773                .render_edit_prediction_line_popover(
 8774                    "Jump to Edit",
 8775                    Some(IconName::ArrowUp),
 8776                    window,
 8777                    cx,
 8778                )
 8779                .into_any();
 8780
 8781            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8782            let offset = point(
 8783                (text_bounds.size.width - size.width) / 2.,
 8784                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8785            );
 8786
 8787            let origin = text_bounds.origin + offset;
 8788            element.prepaint_at(origin, window, cx);
 8789            Some((element, origin))
 8790        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 8791            let mut element = self
 8792                .render_edit_prediction_line_popover(
 8793                    "Jump to Edit",
 8794                    Some(IconName::ArrowDown),
 8795                    window,
 8796                    cx,
 8797                )
 8798                .into_any();
 8799
 8800            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8801            let offset = point(
 8802                (text_bounds.size.width - size.width) / 2.,
 8803                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 8804            );
 8805
 8806            let origin = text_bounds.origin + offset;
 8807            element.prepaint_at(origin, window, cx);
 8808            Some((element, origin))
 8809        } else {
 8810            self.render_edit_prediction_end_of_line_popover(
 8811                "Jump to Edit",
 8812                editor_snapshot,
 8813                visible_row_range,
 8814                target_display_point,
 8815                line_height,
 8816                scroll_pixel_position,
 8817                content_origin,
 8818                editor_width,
 8819                window,
 8820                cx,
 8821            )
 8822        }
 8823    }
 8824
 8825    fn render_edit_prediction_end_of_line_popover(
 8826        self: &mut Editor,
 8827        label: &'static str,
 8828        editor_snapshot: &EditorSnapshot,
 8829        visible_row_range: Range<DisplayRow>,
 8830        target_display_point: DisplayPoint,
 8831        line_height: Pixels,
 8832        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8833        content_origin: gpui::Point<Pixels>,
 8834        editor_width: Pixels,
 8835        window: &mut Window,
 8836        cx: &mut App,
 8837    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8838        let target_line_end = DisplayPoint::new(
 8839            target_display_point.row(),
 8840            editor_snapshot.line_len(target_display_point.row()),
 8841        );
 8842
 8843        let mut element = self
 8844            .render_edit_prediction_line_popover(label, None, window, cx)
 8845            .into_any();
 8846
 8847        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8848
 8849        let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 8850
 8851        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 8852        let mut origin = start_point
 8853            + line_origin
 8854            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 8855        origin.x = origin.x.max(content_origin.x);
 8856
 8857        let max_x = content_origin.x + editor_width - size.width;
 8858
 8859        if origin.x > max_x {
 8860            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 8861
 8862            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 8863                origin.y += offset;
 8864                IconName::ArrowUp
 8865            } else {
 8866                origin.y -= offset;
 8867                IconName::ArrowDown
 8868            };
 8869
 8870            element = self
 8871                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 8872                .into_any();
 8873
 8874            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 8875
 8876            origin.x = content_origin.x + editor_width - size.width - px(2.);
 8877        }
 8878
 8879        element.prepaint_at(origin, window, cx);
 8880        Some((element, origin))
 8881    }
 8882
 8883    fn render_edit_prediction_diff_popover(
 8884        self: &Editor,
 8885        text_bounds: &Bounds<Pixels>,
 8886        content_origin: gpui::Point<Pixels>,
 8887        right_margin: Pixels,
 8888        editor_snapshot: &EditorSnapshot,
 8889        visible_row_range: Range<DisplayRow>,
 8890        line_layouts: &[LineWithInvisibles],
 8891        line_height: Pixels,
 8892        scroll_position: gpui::Point<ScrollOffset>,
 8893        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8894        newest_selection_head: Option<DisplayPoint>,
 8895        editor_width: Pixels,
 8896        style: &EditorStyle,
 8897        edits: &Vec<(Range<Anchor>, String)>,
 8898        edit_preview: &Option<language::EditPreview>,
 8899        snapshot: &language::BufferSnapshot,
 8900        window: &mut Window,
 8901        cx: &mut App,
 8902    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8903        let edit_start = edits
 8904            .first()
 8905            .unwrap()
 8906            .0
 8907            .start
 8908            .to_display_point(editor_snapshot);
 8909        let edit_end = edits
 8910            .last()
 8911            .unwrap()
 8912            .0
 8913            .end
 8914            .to_display_point(editor_snapshot);
 8915
 8916        let is_visible = visible_row_range.contains(&edit_start.row())
 8917            || visible_row_range.contains(&edit_end.row());
 8918        if !is_visible {
 8919            return None;
 8920        }
 8921
 8922        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 8923            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 8924        } else {
 8925            // Fallback for providers without edit_preview
 8926            crate::edit_prediction_fallback_text(edits, cx)
 8927        };
 8928
 8929        let styled_text = highlighted_edits.to_styled_text(&style.text);
 8930        let line_count = highlighted_edits.text.lines().count();
 8931
 8932        const BORDER_WIDTH: Pixels = px(1.);
 8933
 8934        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 8935        let has_keybind = keybind.is_some();
 8936
 8937        let mut element = h_flex()
 8938            .items_start()
 8939            .child(
 8940                h_flex()
 8941                    .bg(cx.theme().colors().editor_background)
 8942                    .border(BORDER_WIDTH)
 8943                    .shadow_xs()
 8944                    .border_color(cx.theme().colors().border)
 8945                    .rounded_l_lg()
 8946                    .when(line_count > 1, |el| el.rounded_br_lg())
 8947                    .pr_1()
 8948                    .child(styled_text),
 8949            )
 8950            .child(
 8951                h_flex()
 8952                    .h(line_height + BORDER_WIDTH * 2.)
 8953                    .px_1p5()
 8954                    .gap_1()
 8955                    // Workaround: For some reason, there's a gap if we don't do this
 8956                    .ml(-BORDER_WIDTH)
 8957                    .shadow(vec![gpui::BoxShadow {
 8958                        color: gpui::black().opacity(0.05),
 8959                        offset: point(px(1.), px(1.)),
 8960                        blur_radius: px(2.),
 8961                        spread_radius: px(0.),
 8962                    }])
 8963                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 8964                    .border(BORDER_WIDTH)
 8965                    .border_color(cx.theme().colors().border)
 8966                    .rounded_r_lg()
 8967                    .id("edit_prediction_diff_popover_keybind")
 8968                    .when(!has_keybind, |el| {
 8969                        let status_colors = cx.theme().status();
 8970
 8971                        el.bg(status_colors.error_background)
 8972                            .border_color(status_colors.error.opacity(0.6))
 8973                            .child(Icon::new(IconName::Info).color(Color::Error))
 8974                            .cursor_default()
 8975                            .hoverable_tooltip(move |_window, cx| {
 8976                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 8977                            })
 8978                    })
 8979                    .children(keybind),
 8980            )
 8981            .into_any();
 8982
 8983        let longest_row =
 8984            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 8985        let longest_line_width = if visible_row_range.contains(&longest_row) {
 8986            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 8987        } else {
 8988            layout_line(
 8989                longest_row,
 8990                editor_snapshot,
 8991                style,
 8992                editor_width,
 8993                |_| false,
 8994                window,
 8995                cx,
 8996            )
 8997            .width
 8998        };
 8999
 9000        let viewport_bounds =
 9001            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9002                right: -right_margin,
 9003                ..Default::default()
 9004            });
 9005
 9006        let x_after_longest = Pixels::from(
 9007            ScrollPixelOffset::from(
 9008                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9009            ) - scroll_pixel_position.x,
 9010        );
 9011
 9012        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9013
 9014        // Fully visible if it can be displayed within the window (allow overlapping other
 9015        // panes). However, this is only allowed if the popover starts within text_bounds.
 9016        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9017            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9018
 9019        let mut origin = if can_position_to_the_right {
 9020            point(
 9021                x_after_longest,
 9022                text_bounds.origin.y
 9023                    + Pixels::from(
 9024                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9025                            - scroll_pixel_position.y,
 9026                    ),
 9027            )
 9028        } else {
 9029            let cursor_row = newest_selection_head.map(|head| head.row());
 9030            let above_edit = edit_start
 9031                .row()
 9032                .0
 9033                .checked_sub(line_count as u32)
 9034                .map(DisplayRow);
 9035            let below_edit = Some(edit_end.row() + 1);
 9036            let above_cursor =
 9037                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9038            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9039
 9040            // Place the edit popover adjacent to the edit if there is a location
 9041            // available that is onscreen and does not obscure the cursor. Otherwise,
 9042            // place it adjacent to the cursor.
 9043            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9044                .into_iter()
 9045                .flatten()
 9046                .find(|&start_row| {
 9047                    let end_row = start_row + line_count as u32;
 9048                    visible_row_range.contains(&start_row)
 9049                        && visible_row_range.contains(&end_row)
 9050                        && cursor_row
 9051                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9052                })?;
 9053
 9054            content_origin
 9055                + point(
 9056                    Pixels::from(-scroll_pixel_position.x),
 9057                    Pixels::from(
 9058                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9059                    ),
 9060                )
 9061        };
 9062
 9063        origin.x -= BORDER_WIDTH;
 9064
 9065        window.defer_draw(element, origin, 1);
 9066
 9067        // Do not return an element, since it will already be drawn due to defer_draw.
 9068        None
 9069    }
 9070
 9071    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9072        px(30.)
 9073    }
 9074
 9075    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9076        if self.read_only(cx) {
 9077            cx.theme().players().read_only()
 9078        } else {
 9079            self.style.as_ref().unwrap().local_player
 9080        }
 9081    }
 9082
 9083    fn render_edit_prediction_accept_keybind(
 9084        &self,
 9085        window: &mut Window,
 9086        cx: &mut App,
 9087    ) -> Option<AnyElement> {
 9088        let accept_binding = self.accept_edit_prediction_keybind(false, window, cx);
 9089        let accept_keystroke = accept_binding.keystroke()?;
 9090
 9091        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9092
 9093        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9094            Color::Accent
 9095        } else {
 9096            Color::Muted
 9097        };
 9098
 9099        h_flex()
 9100            .px_0p5()
 9101            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9102            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9103            .text_size(TextSize::XSmall.rems(cx))
 9104            .child(h_flex().children(ui::render_modifiers(
 9105                accept_keystroke.modifiers(),
 9106                PlatformStyle::platform(),
 9107                Some(modifiers_color),
 9108                Some(IconSize::XSmall.rems().into()),
 9109                true,
 9110            )))
 9111            .when(is_platform_style_mac, |parent| {
 9112                parent.child(accept_keystroke.key().to_string())
 9113            })
 9114            .when(!is_platform_style_mac, |parent| {
 9115                parent.child(
 9116                    Key::new(
 9117                        util::capitalize(accept_keystroke.key()),
 9118                        Some(Color::Default),
 9119                    )
 9120                    .size(Some(IconSize::XSmall.rems().into())),
 9121                )
 9122            })
 9123            .into_any()
 9124            .into()
 9125    }
 9126
 9127    fn render_edit_prediction_line_popover(
 9128        &self,
 9129        label: impl Into<SharedString>,
 9130        icon: Option<IconName>,
 9131        window: &mut Window,
 9132        cx: &mut App,
 9133    ) -> Stateful<Div> {
 9134        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9135
 9136        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9137        let has_keybind = keybind.is_some();
 9138
 9139        h_flex()
 9140            .id("ep-line-popover")
 9141            .py_0p5()
 9142            .pl_1()
 9143            .pr(padding_right)
 9144            .gap_1()
 9145            .rounded_md()
 9146            .border_1()
 9147            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9148            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9149            .shadow_xs()
 9150            .when(!has_keybind, |el| {
 9151                let status_colors = cx.theme().status();
 9152
 9153                el.bg(status_colors.error_background)
 9154                    .border_color(status_colors.error.opacity(0.6))
 9155                    .pl_2()
 9156                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9157                    .cursor_default()
 9158                    .hoverable_tooltip(move |_window, cx| {
 9159                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9160                    })
 9161            })
 9162            .children(keybind)
 9163            .child(
 9164                Label::new(label)
 9165                    .size(LabelSize::Small)
 9166                    .when(!has_keybind, |el| {
 9167                        el.color(cx.theme().status().error.into()).strikethrough()
 9168                    }),
 9169            )
 9170            .when(!has_keybind, |el| {
 9171                el.child(
 9172                    h_flex().ml_1().child(
 9173                        Icon::new(IconName::Info)
 9174                            .size(IconSize::Small)
 9175                            .color(cx.theme().status().error.into()),
 9176                    ),
 9177                )
 9178            })
 9179            .when_some(icon, |element, icon| {
 9180                element.child(
 9181                    div()
 9182                        .mt(px(1.5))
 9183                        .child(Icon::new(icon).size(IconSize::Small)),
 9184                )
 9185            })
 9186    }
 9187
 9188    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9189        let accent_color = cx.theme().colors().text_accent;
 9190        let editor_bg_color = cx.theme().colors().editor_background;
 9191        editor_bg_color.blend(accent_color.opacity(0.1))
 9192    }
 9193
 9194    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9195        let accent_color = cx.theme().colors().text_accent;
 9196        let editor_bg_color = cx.theme().colors().editor_background;
 9197        editor_bg_color.blend(accent_color.opacity(0.6))
 9198    }
 9199    fn get_prediction_provider_icon_name(
 9200        provider: &Option<RegisteredEditPredictionProvider>,
 9201    ) -> IconName {
 9202        match provider {
 9203            Some(provider) => match provider.provider.name() {
 9204                "copilot" => IconName::Copilot,
 9205                "supermaven" => IconName::Supermaven,
 9206                _ => IconName::ZedPredict,
 9207            },
 9208            None => IconName::ZedPredict,
 9209        }
 9210    }
 9211
 9212    fn render_edit_prediction_cursor_popover(
 9213        &self,
 9214        min_width: Pixels,
 9215        max_width: Pixels,
 9216        cursor_point: Point,
 9217        style: &EditorStyle,
 9218        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9219        _window: &Window,
 9220        cx: &mut Context<Editor>,
 9221    ) -> Option<AnyElement> {
 9222        let provider = self.edit_prediction_provider.as_ref()?;
 9223        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9224
 9225        let is_refreshing = provider.provider.is_refreshing(cx);
 9226
 9227        fn pending_completion_container(icon: IconName) -> Div {
 9228            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9229        }
 9230
 9231        let completion = match &self.active_edit_prediction {
 9232            Some(prediction) => {
 9233                if !self.has_visible_completions_menu() {
 9234                    const RADIUS: Pixels = px(6.);
 9235                    const BORDER_WIDTH: Pixels = px(1.);
 9236
 9237                    return Some(
 9238                        h_flex()
 9239                            .elevation_2(cx)
 9240                            .border(BORDER_WIDTH)
 9241                            .border_color(cx.theme().colors().border)
 9242                            .when(accept_keystroke.is_none(), |el| {
 9243                                el.border_color(cx.theme().status().error)
 9244                            })
 9245                            .rounded(RADIUS)
 9246                            .rounded_tl(px(0.))
 9247                            .overflow_hidden()
 9248                            .child(div().px_1p5().child(match &prediction.completion {
 9249                                EditPrediction::MoveWithin { target, snapshot } => {
 9250                                    use text::ToPoint as _;
 9251                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9252                                    {
 9253                                        Icon::new(IconName::ZedPredictDown)
 9254                                    } else {
 9255                                        Icon::new(IconName::ZedPredictUp)
 9256                                    }
 9257                                }
 9258                                EditPrediction::MoveOutside { .. } => {
 9259                                    // TODO [zeta2] custom icon for external jump?
 9260                                    Icon::new(provider_icon)
 9261                                }
 9262                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9263                            }))
 9264                            .child(
 9265                                h_flex()
 9266                                    .gap_1()
 9267                                    .py_1()
 9268                                    .px_2()
 9269                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9270                                    .border_l_1()
 9271                                    .border_color(cx.theme().colors().border)
 9272                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9273                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9274                                        el.child(
 9275                                            Label::new("Hold")
 9276                                                .size(LabelSize::Small)
 9277                                                .when(accept_keystroke.is_none(), |el| {
 9278                                                    el.strikethrough()
 9279                                                })
 9280                                                .line_height_style(LineHeightStyle::UiLabel),
 9281                                        )
 9282                                    })
 9283                                    .id("edit_prediction_cursor_popover_keybind")
 9284                                    .when(accept_keystroke.is_none(), |el| {
 9285                                        let status_colors = cx.theme().status();
 9286
 9287                                        el.bg(status_colors.error_background)
 9288                                            .border_color(status_colors.error.opacity(0.6))
 9289                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9290                                            .cursor_default()
 9291                                            .hoverable_tooltip(move |_window, cx| {
 9292                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9293                                                    .into()
 9294                                            })
 9295                                    })
 9296                                    .when_some(
 9297                                        accept_keystroke.as_ref(),
 9298                                        |el, accept_keystroke| {
 9299                                            el.child(h_flex().children(ui::render_modifiers(
 9300                                                accept_keystroke.modifiers(),
 9301                                                PlatformStyle::platform(),
 9302                                                Some(Color::Default),
 9303                                                Some(IconSize::XSmall.rems().into()),
 9304                                                false,
 9305                                            )))
 9306                                        },
 9307                                    ),
 9308                            )
 9309                            .into_any(),
 9310                    );
 9311                }
 9312
 9313                self.render_edit_prediction_cursor_popover_preview(
 9314                    prediction,
 9315                    cursor_point,
 9316                    style,
 9317                    cx,
 9318                )?
 9319            }
 9320
 9321            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9322                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9323                    stale_completion,
 9324                    cursor_point,
 9325                    style,
 9326                    cx,
 9327                )?,
 9328
 9329                None => pending_completion_container(provider_icon)
 9330                    .child(Label::new("...").size(LabelSize::Small)),
 9331            },
 9332
 9333            None => pending_completion_container(provider_icon)
 9334                .child(Label::new("...").size(LabelSize::Small)),
 9335        };
 9336
 9337        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9338            completion
 9339                .with_animation(
 9340                    "loading-completion",
 9341                    Animation::new(Duration::from_secs(2))
 9342                        .repeat()
 9343                        .with_easing(pulsating_between(0.4, 0.8)),
 9344                    |label, delta| label.opacity(delta),
 9345                )
 9346                .into_any_element()
 9347        } else {
 9348            completion.into_any_element()
 9349        };
 9350
 9351        let has_completion = self.active_edit_prediction.is_some();
 9352
 9353        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9354        Some(
 9355            h_flex()
 9356                .min_w(min_width)
 9357                .max_w(max_width)
 9358                .flex_1()
 9359                .elevation_2(cx)
 9360                .border_color(cx.theme().colors().border)
 9361                .child(
 9362                    div()
 9363                        .flex_1()
 9364                        .py_1()
 9365                        .px_2()
 9366                        .overflow_hidden()
 9367                        .child(completion),
 9368                )
 9369                .when_some(accept_keystroke, |el, accept_keystroke| {
 9370                    if !accept_keystroke.modifiers().modified() {
 9371                        return el;
 9372                    }
 9373
 9374                    el.child(
 9375                        h_flex()
 9376                            .h_full()
 9377                            .border_l_1()
 9378                            .rounded_r_lg()
 9379                            .border_color(cx.theme().colors().border)
 9380                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9381                            .gap_1()
 9382                            .py_1()
 9383                            .px_2()
 9384                            .child(
 9385                                h_flex()
 9386                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9387                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9388                                    .child(h_flex().children(ui::render_modifiers(
 9389                                        accept_keystroke.modifiers(),
 9390                                        PlatformStyle::platform(),
 9391                                        Some(if !has_completion {
 9392                                            Color::Muted
 9393                                        } else {
 9394                                            Color::Default
 9395                                        }),
 9396                                        None,
 9397                                        false,
 9398                                    ))),
 9399                            )
 9400                            .child(Label::new("Preview").into_any_element())
 9401                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9402                    )
 9403                })
 9404                .into_any(),
 9405        )
 9406    }
 9407
 9408    fn render_edit_prediction_cursor_popover_preview(
 9409        &self,
 9410        completion: &EditPredictionState,
 9411        cursor_point: Point,
 9412        style: &EditorStyle,
 9413        cx: &mut Context<Editor>,
 9414    ) -> Option<Div> {
 9415        use text::ToPoint as _;
 9416
 9417        fn render_relative_row_jump(
 9418            prefix: impl Into<String>,
 9419            current_row: u32,
 9420            target_row: u32,
 9421        ) -> Div {
 9422            let (row_diff, arrow) = if target_row < current_row {
 9423                (current_row - target_row, IconName::ArrowUp)
 9424            } else {
 9425                (target_row - current_row, IconName::ArrowDown)
 9426            };
 9427
 9428            h_flex()
 9429                .child(
 9430                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9431                        .color(Color::Muted)
 9432                        .size(LabelSize::Small),
 9433                )
 9434                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9435        }
 9436
 9437        let supports_jump = self
 9438            .edit_prediction_provider
 9439            .as_ref()
 9440            .map(|provider| provider.provider.supports_jump_to_edit())
 9441            .unwrap_or(true);
 9442
 9443        match &completion.completion {
 9444            EditPrediction::MoveWithin {
 9445                target, snapshot, ..
 9446            } => {
 9447                if !supports_jump {
 9448                    return None;
 9449                }
 9450
 9451                Some(
 9452                    h_flex()
 9453                        .px_2()
 9454                        .gap_2()
 9455                        .flex_1()
 9456                        .child(
 9457                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9458                                Icon::new(IconName::ZedPredictDown)
 9459                            } else {
 9460                                Icon::new(IconName::ZedPredictUp)
 9461                            },
 9462                        )
 9463                        .child(Label::new("Jump to Edit")),
 9464                )
 9465            }
 9466            EditPrediction::MoveOutside { snapshot, .. } => {
 9467                let file_name = snapshot
 9468                    .file()
 9469                    .map(|file| file.file_name(cx))
 9470                    .unwrap_or("untitled");
 9471                Some(
 9472                    h_flex()
 9473                        .px_2()
 9474                        .gap_2()
 9475                        .flex_1()
 9476                        .child(Icon::new(IconName::ZedPredict))
 9477                        .child(Label::new(format!("Jump to {file_name}"))),
 9478                )
 9479            }
 9480            EditPrediction::Edit {
 9481                edits,
 9482                edit_preview,
 9483                snapshot,
 9484                display_mode: _,
 9485            } => {
 9486                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9487
 9488                let (highlighted_edits, has_more_lines) =
 9489                    if let Some(edit_preview) = edit_preview.as_ref() {
 9490                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9491                            .first_line_preview()
 9492                    } else {
 9493                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9494                    };
 9495
 9496                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9497                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9498
 9499                let preview = h_flex()
 9500                    .gap_1()
 9501                    .min_w_16()
 9502                    .child(styled_text)
 9503                    .when(has_more_lines, |parent| parent.child(""));
 9504
 9505                let left = if supports_jump && first_edit_row != cursor_point.row {
 9506                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9507                        .into_any_element()
 9508                } else {
 9509                    let icon_name =
 9510                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9511                    Icon::new(icon_name).into_any_element()
 9512                };
 9513
 9514                Some(
 9515                    h_flex()
 9516                        .h_full()
 9517                        .flex_1()
 9518                        .gap_2()
 9519                        .pr_1()
 9520                        .overflow_x_hidden()
 9521                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9522                        .child(left)
 9523                        .child(preview),
 9524                )
 9525            }
 9526        }
 9527    }
 9528
 9529    pub fn render_context_menu(
 9530        &self,
 9531        style: &EditorStyle,
 9532        max_height_in_lines: u32,
 9533        window: &mut Window,
 9534        cx: &mut Context<Editor>,
 9535    ) -> Option<AnyElement> {
 9536        let menu = self.context_menu.borrow();
 9537        let menu = menu.as_ref()?;
 9538        if !menu.visible() {
 9539            return None;
 9540        };
 9541        Some(menu.render(style, max_height_in_lines, window, cx))
 9542    }
 9543
 9544    fn render_context_menu_aside(
 9545        &mut self,
 9546        max_size: Size<Pixels>,
 9547        window: &mut Window,
 9548        cx: &mut Context<Editor>,
 9549    ) -> Option<AnyElement> {
 9550        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
 9551            if menu.visible() {
 9552                menu.render_aside(max_size, window, cx)
 9553            } else {
 9554                None
 9555            }
 9556        })
 9557    }
 9558
 9559    fn hide_context_menu(
 9560        &mut self,
 9561        window: &mut Window,
 9562        cx: &mut Context<Self>,
 9563    ) -> Option<CodeContextMenu> {
 9564        cx.notify();
 9565        self.completion_tasks.clear();
 9566        let context_menu = self.context_menu.borrow_mut().take();
 9567        self.stale_edit_prediction_in_menu.take();
 9568        self.update_visible_edit_prediction(window, cx);
 9569        if let Some(CodeContextMenu::Completions(_)) = &context_menu
 9570            && let Some(completion_provider) = &self.completion_provider
 9571        {
 9572            completion_provider.selection_changed(None, window, cx);
 9573        }
 9574        context_menu
 9575    }
 9576
 9577    fn show_snippet_choices(
 9578        &mut self,
 9579        choices: &Vec<String>,
 9580        selection: Range<Anchor>,
 9581        cx: &mut Context<Self>,
 9582    ) {
 9583        let Some((_, buffer, _)) = self
 9584            .buffer()
 9585            .read(cx)
 9586            .excerpt_containing(selection.start, cx)
 9587        else {
 9588            return;
 9589        };
 9590        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
 9591        else {
 9592            return;
 9593        };
 9594        if buffer != end_buffer {
 9595            log::error!("expected anchor range to have matching buffer IDs");
 9596            return;
 9597        }
 9598
 9599        let id = post_inc(&mut self.next_completion_id);
 9600        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 9601        *self.context_menu.borrow_mut() = Some(CodeContextMenu::Completions(
 9602            CompletionsMenu::new_snippet_choices(
 9603                id,
 9604                true,
 9605                choices,
 9606                selection,
 9607                buffer,
 9608                snippet_sort_order,
 9609            ),
 9610        ));
 9611    }
 9612
 9613    pub fn insert_snippet(
 9614        &mut self,
 9615        insertion_ranges: &[Range<usize>],
 9616        snippet: Snippet,
 9617        window: &mut Window,
 9618        cx: &mut Context<Self>,
 9619    ) -> Result<()> {
 9620        struct Tabstop<T> {
 9621            is_end_tabstop: bool,
 9622            ranges: Vec<Range<T>>,
 9623            choices: Option<Vec<String>>,
 9624        }
 9625
 9626        let tabstops = self.buffer.update(cx, |buffer, cx| {
 9627            let snippet_text: Arc<str> = snippet.text.clone().into();
 9628            let edits = insertion_ranges
 9629                .iter()
 9630                .cloned()
 9631                .map(|range| (range, snippet_text.clone()));
 9632            let autoindent_mode = AutoindentMode::Block {
 9633                original_indent_columns: Vec::new(),
 9634            };
 9635            buffer.edit(edits, Some(autoindent_mode), cx);
 9636
 9637            let snapshot = &*buffer.read(cx);
 9638            let snippet = &snippet;
 9639            snippet
 9640                .tabstops
 9641                .iter()
 9642                .map(|tabstop| {
 9643                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
 9644                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
 9645                    });
 9646                    let mut tabstop_ranges = tabstop
 9647                        .ranges
 9648                        .iter()
 9649                        .flat_map(|tabstop_range| {
 9650                            let mut delta = 0_isize;
 9651                            insertion_ranges.iter().map(move |insertion_range| {
 9652                                let insertion_start = insertion_range.start as isize + delta;
 9653                                delta +=
 9654                                    snippet.text.len() as isize - insertion_range.len() as isize;
 9655
 9656                                let start = ((insertion_start + tabstop_range.start) as usize)
 9657                                    .min(snapshot.len());
 9658                                let end = ((insertion_start + tabstop_range.end) as usize)
 9659                                    .min(snapshot.len());
 9660                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
 9661                            })
 9662                        })
 9663                        .collect::<Vec<_>>();
 9664                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
 9665
 9666                    Tabstop {
 9667                        is_end_tabstop,
 9668                        ranges: tabstop_ranges,
 9669                        choices: tabstop.choices.clone(),
 9670                    }
 9671                })
 9672                .collect::<Vec<_>>()
 9673        });
 9674        if let Some(tabstop) = tabstops.first() {
 9675            self.change_selections(Default::default(), window, cx, |s| {
 9676                // Reverse order so that the first range is the newest created selection.
 9677                // Completions will use it and autoscroll will prioritize it.
 9678                s.select_ranges(tabstop.ranges.iter().rev().cloned());
 9679            });
 9680
 9681            if let Some(choices) = &tabstop.choices
 9682                && let Some(selection) = tabstop.ranges.first()
 9683            {
 9684                self.show_snippet_choices(choices, selection.clone(), cx)
 9685            }
 9686
 9687            // If we're already at the last tabstop and it's at the end of the snippet,
 9688            // we're done, we don't need to keep the state around.
 9689            if !tabstop.is_end_tabstop {
 9690                let choices = tabstops
 9691                    .iter()
 9692                    .map(|tabstop| tabstop.choices.clone())
 9693                    .collect();
 9694
 9695                let ranges = tabstops
 9696                    .into_iter()
 9697                    .map(|tabstop| tabstop.ranges)
 9698                    .collect::<Vec<_>>();
 9699
 9700                self.snippet_stack.push(SnippetState {
 9701                    active_index: 0,
 9702                    ranges,
 9703                    choices,
 9704                });
 9705            }
 9706
 9707            // Check whether the just-entered snippet ends with an auto-closable bracket.
 9708            if self.autoclose_regions.is_empty() {
 9709                let snapshot = self.buffer.read(cx).snapshot(cx);
 9710                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
 9711                    let selection_head = selection.head();
 9712                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
 9713                        continue;
 9714                    };
 9715
 9716                    let mut bracket_pair = None;
 9717                    let max_lookup_length = scope
 9718                        .brackets()
 9719                        .map(|(pair, _)| {
 9720                            pair.start
 9721                                .as_str()
 9722                                .chars()
 9723                                .count()
 9724                                .max(pair.end.as_str().chars().count())
 9725                        })
 9726                        .max();
 9727                    if let Some(max_lookup_length) = max_lookup_length {
 9728                        let next_text = snapshot
 9729                            .chars_at(selection_head)
 9730                            .take(max_lookup_length)
 9731                            .collect::<String>();
 9732                        let prev_text = snapshot
 9733                            .reversed_chars_at(selection_head)
 9734                            .take(max_lookup_length)
 9735                            .collect::<String>();
 9736
 9737                        for (pair, enabled) in scope.brackets() {
 9738                            if enabled
 9739                                && pair.close
 9740                                && prev_text.starts_with(pair.start.as_str())
 9741                                && next_text.starts_with(pair.end.as_str())
 9742                            {
 9743                                bracket_pair = Some(pair.clone());
 9744                                break;
 9745                            }
 9746                        }
 9747                    }
 9748
 9749                    if let Some(pair) = bracket_pair {
 9750                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
 9751                        let autoclose_enabled =
 9752                            self.use_autoclose && snapshot_settings.use_autoclose;
 9753                        if autoclose_enabled {
 9754                            let start = snapshot.anchor_after(selection_head);
 9755                            let end = snapshot.anchor_after(selection_head);
 9756                            self.autoclose_regions.push(AutocloseRegion {
 9757                                selection_id: selection.id,
 9758                                range: start..end,
 9759                                pair,
 9760                            });
 9761                        }
 9762                    }
 9763                }
 9764            }
 9765        }
 9766        Ok(())
 9767    }
 9768
 9769    pub fn move_to_next_snippet_tabstop(
 9770        &mut self,
 9771        window: &mut Window,
 9772        cx: &mut Context<Self>,
 9773    ) -> bool {
 9774        self.move_to_snippet_tabstop(Bias::Right, window, cx)
 9775    }
 9776
 9777    pub fn move_to_prev_snippet_tabstop(
 9778        &mut self,
 9779        window: &mut Window,
 9780        cx: &mut Context<Self>,
 9781    ) -> bool {
 9782        self.move_to_snippet_tabstop(Bias::Left, window, cx)
 9783    }
 9784
 9785    pub fn move_to_snippet_tabstop(
 9786        &mut self,
 9787        bias: Bias,
 9788        window: &mut Window,
 9789        cx: &mut Context<Self>,
 9790    ) -> bool {
 9791        if let Some(mut snippet) = self.snippet_stack.pop() {
 9792            match bias {
 9793                Bias::Left => {
 9794                    if snippet.active_index > 0 {
 9795                        snippet.active_index -= 1;
 9796                    } else {
 9797                        self.snippet_stack.push(snippet);
 9798                        return false;
 9799                    }
 9800                }
 9801                Bias::Right => {
 9802                    if snippet.active_index + 1 < snippet.ranges.len() {
 9803                        snippet.active_index += 1;
 9804                    } else {
 9805                        self.snippet_stack.push(snippet);
 9806                        return false;
 9807                    }
 9808                }
 9809            }
 9810            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
 9811                self.change_selections(Default::default(), window, cx, |s| {
 9812                    // Reverse order so that the first range is the newest created selection.
 9813                    // Completions will use it and autoscroll will prioritize it.
 9814                    s.select_ranges(current_ranges.iter().rev().cloned())
 9815                });
 9816
 9817                if let Some(choices) = &snippet.choices[snippet.active_index]
 9818                    && let Some(selection) = current_ranges.first()
 9819                {
 9820                    self.show_snippet_choices(choices, selection.clone(), cx);
 9821                }
 9822
 9823                // If snippet state is not at the last tabstop, push it back on the stack
 9824                if snippet.active_index + 1 < snippet.ranges.len() {
 9825                    self.snippet_stack.push(snippet);
 9826                }
 9827                return true;
 9828            }
 9829        }
 9830
 9831        false
 9832    }
 9833
 9834    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 9835        self.transact(window, cx, |this, window, cx| {
 9836            this.select_all(&SelectAll, window, cx);
 9837            this.insert("", window, cx);
 9838        });
 9839    }
 9840
 9841    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
 9842        if self.read_only(cx) {
 9843            return;
 9844        }
 9845        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9846        self.transact(window, cx, |this, window, cx| {
 9847            this.select_autoclose_pair(window, cx);
 9848
 9849            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 9850
 9851            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
 9852            if !this.linked_edit_ranges.is_empty() {
 9853                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
 9854                let snapshot = this.buffer.read(cx).snapshot(cx);
 9855
 9856                for selection in selections.iter() {
 9857                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
 9858                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
 9859                    if selection_start.buffer_id != selection_end.buffer_id {
 9860                        continue;
 9861                    }
 9862                    if let Some(ranges) =
 9863                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
 9864                    {
 9865                        for (buffer, entries) in ranges {
 9866                            linked_ranges.entry(buffer).or_default().extend(entries);
 9867                        }
 9868                    }
 9869                }
 9870            }
 9871
 9872            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
 9873            for selection in &mut selections {
 9874                if selection.is_empty() {
 9875                    let old_head = selection.head();
 9876                    let mut new_head =
 9877                        movement::left(&display_map, old_head.to_display_point(&display_map))
 9878                            .to_point(&display_map);
 9879                    if let Some((buffer, line_buffer_range)) = display_map
 9880                        .buffer_snapshot()
 9881                        .buffer_line_for_row(MultiBufferRow(old_head.row))
 9882                    {
 9883                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
 9884                        let indent_len = match indent_size.kind {
 9885                            IndentKind::Space => {
 9886                                buffer.settings_at(line_buffer_range.start, cx).tab_size
 9887                            }
 9888                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
 9889                        };
 9890                        if old_head.column <= indent_size.len && old_head.column > 0 {
 9891                            let indent_len = indent_len.get();
 9892                            new_head = cmp::min(
 9893                                new_head,
 9894                                MultiBufferPoint::new(
 9895                                    old_head.row,
 9896                                    ((old_head.column - 1) / indent_len) * indent_len,
 9897                                ),
 9898                            );
 9899                        }
 9900                    }
 9901
 9902                    selection.set_head(new_head, SelectionGoal::None);
 9903                }
 9904            }
 9905
 9906            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
 9907            this.insert("", window, cx);
 9908            let empty_str: Arc<str> = Arc::from("");
 9909            for (buffer, edits) in linked_ranges {
 9910                let snapshot = buffer.read(cx).snapshot();
 9911                use text::ToPoint as TP;
 9912
 9913                let edits = edits
 9914                    .into_iter()
 9915                    .map(|range| {
 9916                        let end_point = TP::to_point(&range.end, &snapshot);
 9917                        let mut start_point = TP::to_point(&range.start, &snapshot);
 9918
 9919                        if end_point == start_point {
 9920                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
 9921                                .saturating_sub(1);
 9922                            start_point =
 9923                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
 9924                        };
 9925
 9926                        (start_point..end_point, empty_str.clone())
 9927                    })
 9928                    .sorted_by_key(|(range, _)| range.start)
 9929                    .collect::<Vec<_>>();
 9930                buffer.update(cx, |this, cx| {
 9931                    this.edit(edits, None, cx);
 9932                })
 9933            }
 9934            this.refresh_edit_prediction(true, false, window, cx);
 9935            refresh_linked_ranges(this, window, cx);
 9936        });
 9937    }
 9938
 9939    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
 9940        if self.read_only(cx) {
 9941            return;
 9942        }
 9943        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9944        self.transact(window, cx, |this, window, cx| {
 9945            this.change_selections(Default::default(), window, cx, |s| {
 9946                s.move_with(|map, selection| {
 9947                    if selection.is_empty() {
 9948                        let cursor = movement::right(map, selection.head());
 9949                        selection.end = cursor;
 9950                        selection.reversed = true;
 9951                        selection.goal = SelectionGoal::None;
 9952                    }
 9953                })
 9954            });
 9955            this.insert("", window, cx);
 9956            this.refresh_edit_prediction(true, false, window, cx);
 9957        });
 9958    }
 9959
 9960    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
 9961        if self.mode.is_single_line() {
 9962            cx.propagate();
 9963            return;
 9964        }
 9965
 9966        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9967        if self.move_to_prev_snippet_tabstop(window, cx) {
 9968            return;
 9969        }
 9970        self.outdent(&Outdent, window, cx);
 9971    }
 9972
 9973    pub fn next_snippet_tabstop(
 9974        &mut self,
 9975        _: &NextSnippetTabstop,
 9976        window: &mut Window,
 9977        cx: &mut Context<Self>,
 9978    ) {
 9979        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
 9980            return;
 9981        }
 9982
 9983        if self.move_to_next_snippet_tabstop(window, cx) {
 9984            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 9985            return;
 9986        }
 9987    }
 9988
 9989    pub fn previous_snippet_tabstop(
 9990        &mut self,
 9991        _: &PreviousSnippetTabstop,
 9992        window: &mut Window,
 9993        cx: &mut Context<Self>,
 9994    ) {
 9995        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
 9996            return;
 9997        }
 9998
 9999        if self.move_to_prev_snippet_tabstop(window, cx) {
10000            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10001            return;
10002        }
10003    }
10004
10005    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10006        if self.mode.is_single_line() {
10007            cx.propagate();
10008            return;
10009        }
10010
10011        if self.move_to_next_snippet_tabstop(window, cx) {
10012            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10013            return;
10014        }
10015        if self.read_only(cx) {
10016            return;
10017        }
10018        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10019        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10020        let buffer = self.buffer.read(cx);
10021        let snapshot = buffer.snapshot(cx);
10022        let rows_iter = selections.iter().map(|s| s.head().row);
10023        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10024
10025        let has_some_cursor_in_whitespace = selections
10026            .iter()
10027            .filter(|selection| selection.is_empty())
10028            .any(|selection| {
10029                let cursor = selection.head();
10030                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10031                cursor.column < current_indent.len
10032            });
10033
10034        let mut edits = Vec::new();
10035        let mut prev_edited_row = 0;
10036        let mut row_delta = 0;
10037        for selection in &mut selections {
10038            if selection.start.row != prev_edited_row {
10039                row_delta = 0;
10040            }
10041            prev_edited_row = selection.end.row;
10042
10043            // If the selection is non-empty, then increase the indentation of the selected lines.
10044            if !selection.is_empty() {
10045                row_delta =
10046                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10047                continue;
10048            }
10049
10050            let cursor = selection.head();
10051            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10052            if let Some(suggested_indent) =
10053                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10054            {
10055                // Don't do anything if already at suggested indent
10056                // and there is any other cursor which is not
10057                if has_some_cursor_in_whitespace
10058                    && cursor.column == current_indent.len
10059                    && current_indent.len == suggested_indent.len
10060                {
10061                    continue;
10062                }
10063
10064                // Adjust line and move cursor to suggested indent
10065                // if cursor is not at suggested indent
10066                if cursor.column < suggested_indent.len
10067                    && cursor.column <= current_indent.len
10068                    && current_indent.len <= suggested_indent.len
10069                {
10070                    selection.start = Point::new(cursor.row, suggested_indent.len);
10071                    selection.end = selection.start;
10072                    if row_delta == 0 {
10073                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10074                            cursor.row,
10075                            current_indent,
10076                            suggested_indent,
10077                        ));
10078                        row_delta = suggested_indent.len - current_indent.len;
10079                    }
10080                    continue;
10081                }
10082
10083                // If current indent is more than suggested indent
10084                // only move cursor to current indent and skip indent
10085                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10086                    selection.start = Point::new(cursor.row, current_indent.len);
10087                    selection.end = selection.start;
10088                    continue;
10089                }
10090            }
10091
10092            // Otherwise, insert a hard or soft tab.
10093            let settings = buffer.language_settings_at(cursor, cx);
10094            let tab_size = if settings.hard_tabs {
10095                IndentSize::tab()
10096            } else {
10097                let tab_size = settings.tab_size.get();
10098                let indent_remainder = snapshot
10099                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10100                    .flat_map(str::chars)
10101                    .fold(row_delta % tab_size, |counter: u32, c| {
10102                        if c == '\t' {
10103                            0
10104                        } else {
10105                            (counter + 1) % tab_size
10106                        }
10107                    });
10108
10109                let chars_to_next_tab_stop = tab_size - indent_remainder;
10110                IndentSize::spaces(chars_to_next_tab_stop)
10111            };
10112            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10113            selection.end = selection.start;
10114            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10115            row_delta += tab_size.len;
10116        }
10117
10118        self.transact(window, cx, |this, window, cx| {
10119            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10120            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10121            this.refresh_edit_prediction(true, false, window, cx);
10122        });
10123    }
10124
10125    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10126        if self.read_only(cx) {
10127            return;
10128        }
10129        if self.mode.is_single_line() {
10130            cx.propagate();
10131            return;
10132        }
10133
10134        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10135        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10136        let mut prev_edited_row = 0;
10137        let mut row_delta = 0;
10138        let mut edits = Vec::new();
10139        let buffer = self.buffer.read(cx);
10140        let snapshot = buffer.snapshot(cx);
10141        for selection in &mut selections {
10142            if selection.start.row != prev_edited_row {
10143                row_delta = 0;
10144            }
10145            prev_edited_row = selection.end.row;
10146
10147            row_delta =
10148                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10149        }
10150
10151        self.transact(window, cx, |this, window, cx| {
10152            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10153            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10154        });
10155    }
10156
10157    fn indent_selection(
10158        buffer: &MultiBuffer,
10159        snapshot: &MultiBufferSnapshot,
10160        selection: &mut Selection<Point>,
10161        edits: &mut Vec<(Range<Point>, String)>,
10162        delta_for_start_row: u32,
10163        cx: &App,
10164    ) -> u32 {
10165        let settings = buffer.language_settings_at(selection.start, cx);
10166        let tab_size = settings.tab_size.get();
10167        let indent_kind = if settings.hard_tabs {
10168            IndentKind::Tab
10169        } else {
10170            IndentKind::Space
10171        };
10172        let mut start_row = selection.start.row;
10173        let mut end_row = selection.end.row + 1;
10174
10175        // If a selection ends at the beginning of a line, don't indent
10176        // that last line.
10177        if selection.end.column == 0 && selection.end.row > selection.start.row {
10178            end_row -= 1;
10179        }
10180
10181        // Avoid re-indenting a row that has already been indented by a
10182        // previous selection, but still update this selection's column
10183        // to reflect that indentation.
10184        if delta_for_start_row > 0 {
10185            start_row += 1;
10186            selection.start.column += delta_for_start_row;
10187            if selection.end.row == selection.start.row {
10188                selection.end.column += delta_for_start_row;
10189            }
10190        }
10191
10192        let mut delta_for_end_row = 0;
10193        let has_multiple_rows = start_row + 1 != end_row;
10194        for row in start_row..end_row {
10195            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10196            let indent_delta = match (current_indent.kind, indent_kind) {
10197                (IndentKind::Space, IndentKind::Space) => {
10198                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10199                    IndentSize::spaces(columns_to_next_tab_stop)
10200                }
10201                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10202                (_, IndentKind::Tab) => IndentSize::tab(),
10203            };
10204
10205            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10206                0
10207            } else {
10208                selection.start.column
10209            };
10210            let row_start = Point::new(row, start);
10211            edits.push((
10212                row_start..row_start,
10213                indent_delta.chars().collect::<String>(),
10214            ));
10215
10216            // Update this selection's endpoints to reflect the indentation.
10217            if row == selection.start.row {
10218                selection.start.column += indent_delta.len;
10219            }
10220            if row == selection.end.row {
10221                selection.end.column += indent_delta.len;
10222                delta_for_end_row = indent_delta.len;
10223            }
10224        }
10225
10226        if selection.start.row == selection.end.row {
10227            delta_for_start_row + delta_for_end_row
10228        } else {
10229            delta_for_end_row
10230        }
10231    }
10232
10233    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10234        if self.read_only(cx) {
10235            return;
10236        }
10237        if self.mode.is_single_line() {
10238            cx.propagate();
10239            return;
10240        }
10241
10242        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10243        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10244        let selections = self.selections.all::<Point>(&display_map);
10245        let mut deletion_ranges = Vec::new();
10246        let mut last_outdent = None;
10247        {
10248            let buffer = self.buffer.read(cx);
10249            let snapshot = buffer.snapshot(cx);
10250            for selection in &selections {
10251                let settings = buffer.language_settings_at(selection.start, cx);
10252                let tab_size = settings.tab_size.get();
10253                let mut rows = selection.spanned_rows(false, &display_map);
10254
10255                // Avoid re-outdenting a row that has already been outdented by a
10256                // previous selection.
10257                if let Some(last_row) = last_outdent
10258                    && last_row == rows.start
10259                {
10260                    rows.start = rows.start.next_row();
10261                }
10262                let has_multiple_rows = rows.len() > 1;
10263                for row in rows.iter_rows() {
10264                    let indent_size = snapshot.indent_size_for_line(row);
10265                    if indent_size.len > 0 {
10266                        let deletion_len = match indent_size.kind {
10267                            IndentKind::Space => {
10268                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10269                                if columns_to_prev_tab_stop == 0 {
10270                                    tab_size
10271                                } else {
10272                                    columns_to_prev_tab_stop
10273                                }
10274                            }
10275                            IndentKind::Tab => 1,
10276                        };
10277                        let start = if has_multiple_rows
10278                            || deletion_len > selection.start.column
10279                            || indent_size.len < selection.start.column
10280                        {
10281                            0
10282                        } else {
10283                            selection.start.column - deletion_len
10284                        };
10285                        deletion_ranges.push(
10286                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10287                        );
10288                        last_outdent = Some(row);
10289                    }
10290                }
10291            }
10292        }
10293
10294        self.transact(window, cx, |this, window, cx| {
10295            this.buffer.update(cx, |buffer, cx| {
10296                let empty_str: Arc<str> = Arc::default();
10297                buffer.edit(
10298                    deletion_ranges
10299                        .into_iter()
10300                        .map(|range| (range, empty_str.clone())),
10301                    None,
10302                    cx,
10303                );
10304            });
10305            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10306            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10307        });
10308    }
10309
10310    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10311        if self.read_only(cx) {
10312            return;
10313        }
10314        if self.mode.is_single_line() {
10315            cx.propagate();
10316            return;
10317        }
10318
10319        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10320        let selections = self
10321            .selections
10322            .all::<usize>(&self.display_snapshot(cx))
10323            .into_iter()
10324            .map(|s| s.range());
10325
10326        self.transact(window, cx, |this, window, cx| {
10327            this.buffer.update(cx, |buffer, cx| {
10328                buffer.autoindent_ranges(selections, cx);
10329            });
10330            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
10331            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10332        });
10333    }
10334
10335    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10336        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10337        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10338        let selections = self.selections.all::<Point>(&display_map);
10339
10340        let mut new_cursors = Vec::new();
10341        let mut edit_ranges = Vec::new();
10342        let mut selections = selections.iter().peekable();
10343        while let Some(selection) = selections.next() {
10344            let mut rows = selection.spanned_rows(false, &display_map);
10345
10346            // Accumulate contiguous regions of rows that we want to delete.
10347            while let Some(next_selection) = selections.peek() {
10348                let next_rows = next_selection.spanned_rows(false, &display_map);
10349                if next_rows.start <= rows.end {
10350                    rows.end = next_rows.end;
10351                    selections.next().unwrap();
10352                } else {
10353                    break;
10354                }
10355            }
10356
10357            let buffer = display_map.buffer_snapshot();
10358            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10359            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10360                // If there's a line after the range, delete the \n from the end of the row range
10361                (
10362                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10363                    rows.end,
10364                )
10365            } else {
10366                // If there isn't a line after the range, delete the \n from the line before the
10367                // start of the row range
10368                edit_start = edit_start.saturating_sub(1);
10369                (buffer.len(), rows.start.previous_row())
10370            };
10371
10372            let text_layout_details = self.text_layout_details(window);
10373            let x = display_map.x_for_display_point(
10374                selection.head().to_display_point(&display_map),
10375                &text_layout_details,
10376            );
10377            let row = Point::new(target_row.0, 0)
10378                .to_display_point(&display_map)
10379                .row();
10380            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10381
10382            new_cursors.push((
10383                selection.id,
10384                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10385                SelectionGoal::None,
10386            ));
10387            edit_ranges.push(edit_start..edit_end);
10388        }
10389
10390        self.transact(window, cx, |this, window, cx| {
10391            let buffer = this.buffer.update(cx, |buffer, cx| {
10392                let empty_str: Arc<str> = Arc::default();
10393                buffer.edit(
10394                    edit_ranges
10395                        .into_iter()
10396                        .map(|range| (range, empty_str.clone())),
10397                    None,
10398                    cx,
10399                );
10400                buffer.snapshot(cx)
10401            });
10402            let new_selections = new_cursors
10403                .into_iter()
10404                .map(|(id, cursor, goal)| {
10405                    let cursor = cursor.to_point(&buffer);
10406                    Selection {
10407                        id,
10408                        start: cursor,
10409                        end: cursor,
10410                        reversed: false,
10411                        goal,
10412                    }
10413                })
10414                .collect();
10415
10416            this.change_selections(Default::default(), window, cx, |s| {
10417                s.select(new_selections);
10418            });
10419        });
10420    }
10421
10422    pub fn join_lines_impl(
10423        &mut self,
10424        insert_whitespace: bool,
10425        window: &mut Window,
10426        cx: &mut Context<Self>,
10427    ) {
10428        if self.read_only(cx) {
10429            return;
10430        }
10431        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10432        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10433            let start = MultiBufferRow(selection.start.row);
10434            // Treat single line selections as if they include the next line. Otherwise this action
10435            // would do nothing for single line selections individual cursors.
10436            let end = if selection.start.row == selection.end.row {
10437                MultiBufferRow(selection.start.row + 1)
10438            } else {
10439                MultiBufferRow(selection.end.row)
10440            };
10441
10442            if let Some(last_row_range) = row_ranges.last_mut()
10443                && start <= last_row_range.end
10444            {
10445                last_row_range.end = end;
10446                continue;
10447            }
10448            row_ranges.push(start..end);
10449        }
10450
10451        let snapshot = self.buffer.read(cx).snapshot(cx);
10452        let mut cursor_positions = Vec::new();
10453        for row_range in &row_ranges {
10454            let anchor = snapshot.anchor_before(Point::new(
10455                row_range.end.previous_row().0,
10456                snapshot.line_len(row_range.end.previous_row()),
10457            ));
10458            cursor_positions.push(anchor..anchor);
10459        }
10460
10461        self.transact(window, cx, |this, window, cx| {
10462            for row_range in row_ranges.into_iter().rev() {
10463                for row in row_range.iter_rows().rev() {
10464                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10465                    let next_line_row = row.next_row();
10466                    let indent = snapshot.indent_size_for_line(next_line_row);
10467                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10468
10469                    let replace =
10470                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10471                            " "
10472                        } else {
10473                            ""
10474                        };
10475
10476                    this.buffer.update(cx, |buffer, cx| {
10477                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10478                    });
10479                }
10480            }
10481
10482            this.change_selections(Default::default(), window, cx, |s| {
10483                s.select_anchor_ranges(cursor_positions)
10484            });
10485        });
10486    }
10487
10488    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10489        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10490        self.join_lines_impl(true, window, cx);
10491    }
10492
10493    pub fn sort_lines_case_sensitive(
10494        &mut self,
10495        _: &SortLinesCaseSensitive,
10496        window: &mut Window,
10497        cx: &mut Context<Self>,
10498    ) {
10499        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10500    }
10501
10502    pub fn sort_lines_by_length(
10503        &mut self,
10504        _: &SortLinesByLength,
10505        window: &mut Window,
10506        cx: &mut Context<Self>,
10507    ) {
10508        self.manipulate_immutable_lines(window, cx, |lines| {
10509            lines.sort_by_key(|&line| line.chars().count())
10510        })
10511    }
10512
10513    pub fn sort_lines_case_insensitive(
10514        &mut self,
10515        _: &SortLinesCaseInsensitive,
10516        window: &mut Window,
10517        cx: &mut Context<Self>,
10518    ) {
10519        self.manipulate_immutable_lines(window, cx, |lines| {
10520            lines.sort_by_key(|line| line.to_lowercase())
10521        })
10522    }
10523
10524    pub fn unique_lines_case_insensitive(
10525        &mut self,
10526        _: &UniqueLinesCaseInsensitive,
10527        window: &mut Window,
10528        cx: &mut Context<Self>,
10529    ) {
10530        self.manipulate_immutable_lines(window, cx, |lines| {
10531            let mut seen = HashSet::default();
10532            lines.retain(|line| seen.insert(line.to_lowercase()));
10533        })
10534    }
10535
10536    pub fn unique_lines_case_sensitive(
10537        &mut self,
10538        _: &UniqueLinesCaseSensitive,
10539        window: &mut Window,
10540        cx: &mut Context<Self>,
10541    ) {
10542        self.manipulate_immutable_lines(window, cx, |lines| {
10543            let mut seen = HashSet::default();
10544            lines.retain(|line| seen.insert(*line));
10545        })
10546    }
10547
10548    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
10549        let snapshot = self.buffer.read(cx).snapshot(cx);
10550        for selection in self.selections.disjoint_anchors_arc().iter() {
10551            if snapshot
10552                .language_at(selection.start)
10553                .and_then(|lang| lang.config().wrap_characters.as_ref())
10554                .is_some()
10555            {
10556                return true;
10557            }
10558        }
10559        false
10560    }
10561
10562    fn wrap_selections_in_tag(
10563        &mut self,
10564        _: &WrapSelectionsInTag,
10565        window: &mut Window,
10566        cx: &mut Context<Self>,
10567    ) {
10568        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10569
10570        let snapshot = self.buffer.read(cx).snapshot(cx);
10571
10572        let mut edits = Vec::new();
10573        let mut boundaries = Vec::new();
10574
10575        for selection in self
10576            .selections
10577            .all_adjusted(&self.display_snapshot(cx))
10578            .iter()
10579        {
10580            let Some(wrap_config) = snapshot
10581                .language_at(selection.start)
10582                .and_then(|lang| lang.config().wrap_characters.clone())
10583            else {
10584                continue;
10585            };
10586
10587            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
10588            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
10589
10590            let start_before = snapshot.anchor_before(selection.start);
10591            let end_after = snapshot.anchor_after(selection.end);
10592
10593            edits.push((start_before..start_before, open_tag));
10594            edits.push((end_after..end_after, close_tag));
10595
10596            boundaries.push((
10597                start_before,
10598                end_after,
10599                wrap_config.start_prefix.len(),
10600                wrap_config.end_suffix.len(),
10601            ));
10602        }
10603
10604        if edits.is_empty() {
10605            return;
10606        }
10607
10608        self.transact(window, cx, |this, window, cx| {
10609            let buffer = this.buffer.update(cx, |buffer, cx| {
10610                buffer.edit(edits, None, cx);
10611                buffer.snapshot(cx)
10612            });
10613
10614            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
10615            for (start_before, end_after, start_prefix_len, end_suffix_len) in
10616                boundaries.into_iter()
10617            {
10618                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
10619                let close_offset = end_after.to_offset(&buffer).saturating_sub(end_suffix_len);
10620                new_selections.push(open_offset..open_offset);
10621                new_selections.push(close_offset..close_offset);
10622            }
10623
10624            this.change_selections(Default::default(), window, cx, |s| {
10625                s.select_ranges(new_selections);
10626            });
10627
10628            this.request_autoscroll(Autoscroll::fit(), cx);
10629        });
10630    }
10631
10632    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
10633        let Some(project) = self.project.clone() else {
10634            return;
10635        };
10636        self.reload(project, window, cx)
10637            .detach_and_notify_err(window, cx);
10638    }
10639
10640    pub fn restore_file(
10641        &mut self,
10642        _: &::git::RestoreFile,
10643        window: &mut Window,
10644        cx: &mut Context<Self>,
10645    ) {
10646        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10647        let mut buffer_ids = HashSet::default();
10648        let snapshot = self.buffer().read(cx).snapshot(cx);
10649        for selection in self.selections.all::<usize>(&self.display_snapshot(cx)) {
10650            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
10651        }
10652
10653        let buffer = self.buffer().read(cx);
10654        let ranges = buffer_ids
10655            .into_iter()
10656            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
10657            .collect::<Vec<_>>();
10658
10659        self.restore_hunks_in_ranges(ranges, window, cx);
10660    }
10661
10662    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
10663        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10664        let selections = self
10665            .selections
10666            .all(&self.display_snapshot(cx))
10667            .into_iter()
10668            .map(|s| s.range())
10669            .collect();
10670        self.restore_hunks_in_ranges(selections, window, cx);
10671    }
10672
10673    pub fn restore_hunks_in_ranges(
10674        &mut self,
10675        ranges: Vec<Range<Point>>,
10676        window: &mut Window,
10677        cx: &mut Context<Editor>,
10678    ) {
10679        let mut revert_changes = HashMap::default();
10680        let chunk_by = self
10681            .snapshot(window, cx)
10682            .hunks_for_ranges(ranges)
10683            .into_iter()
10684            .chunk_by(|hunk| hunk.buffer_id);
10685        for (buffer_id, hunks) in &chunk_by {
10686            let hunks = hunks.collect::<Vec<_>>();
10687            for hunk in &hunks {
10688                self.prepare_restore_change(&mut revert_changes, hunk, cx);
10689            }
10690            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
10691        }
10692        drop(chunk_by);
10693        if !revert_changes.is_empty() {
10694            self.transact(window, cx, |editor, window, cx| {
10695                editor.restore(revert_changes, window, cx);
10696            });
10697        }
10698    }
10699
10700    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
10701        if let Some(status) = self
10702            .addons
10703            .iter()
10704            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
10705        {
10706            return Some(status);
10707        }
10708        self.project
10709            .as_ref()?
10710            .read(cx)
10711            .status_for_buffer_id(buffer_id, cx)
10712    }
10713
10714    pub fn open_active_item_in_terminal(
10715        &mut self,
10716        _: &OpenInTerminal,
10717        window: &mut Window,
10718        cx: &mut Context<Self>,
10719    ) {
10720        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
10721            let project_path = buffer.read(cx).project_path(cx)?;
10722            let project = self.project()?.read(cx);
10723            let entry = project.entry_for_path(&project_path, cx)?;
10724            let parent = match &entry.canonical_path {
10725                Some(canonical_path) => canonical_path.to_path_buf(),
10726                None => project.absolute_path(&project_path, cx)?,
10727            }
10728            .parent()?
10729            .to_path_buf();
10730            Some(parent)
10731        }) {
10732            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
10733        }
10734    }
10735
10736    fn set_breakpoint_context_menu(
10737        &mut self,
10738        display_row: DisplayRow,
10739        position: Option<Anchor>,
10740        clicked_point: gpui::Point<Pixels>,
10741        window: &mut Window,
10742        cx: &mut Context<Self>,
10743    ) {
10744        let source = self
10745            .buffer
10746            .read(cx)
10747            .snapshot(cx)
10748            .anchor_before(Point::new(display_row.0, 0u32));
10749
10750        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
10751
10752        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
10753            self,
10754            source,
10755            clicked_point,
10756            context_menu,
10757            window,
10758            cx,
10759        );
10760    }
10761
10762    fn add_edit_breakpoint_block(
10763        &mut self,
10764        anchor: Anchor,
10765        breakpoint: &Breakpoint,
10766        edit_action: BreakpointPromptEditAction,
10767        window: &mut Window,
10768        cx: &mut Context<Self>,
10769    ) {
10770        let weak_editor = cx.weak_entity();
10771        let bp_prompt = cx.new(|cx| {
10772            BreakpointPromptEditor::new(
10773                weak_editor,
10774                anchor,
10775                breakpoint.clone(),
10776                edit_action,
10777                window,
10778                cx,
10779            )
10780        });
10781
10782        let height = bp_prompt.update(cx, |this, cx| {
10783            this.prompt
10784                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
10785        });
10786        let cloned_prompt = bp_prompt.clone();
10787        let blocks = vec![BlockProperties {
10788            style: BlockStyle::Sticky,
10789            placement: BlockPlacement::Above(anchor),
10790            height: Some(height),
10791            render: Arc::new(move |cx| {
10792                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
10793                cloned_prompt.clone().into_any_element()
10794            }),
10795            priority: 0,
10796        }];
10797
10798        let focus_handle = bp_prompt.focus_handle(cx);
10799        window.focus(&focus_handle);
10800
10801        let block_ids = self.insert_blocks(blocks, None, cx);
10802        bp_prompt.update(cx, |prompt, _| {
10803            prompt.add_block_ids(block_ids);
10804        });
10805    }
10806
10807    pub(crate) fn breakpoint_at_row(
10808        &self,
10809        row: u32,
10810        window: &mut Window,
10811        cx: &mut Context<Self>,
10812    ) -> Option<(Anchor, Breakpoint)> {
10813        let snapshot = self.snapshot(window, cx);
10814        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
10815
10816        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10817    }
10818
10819    pub(crate) fn breakpoint_at_anchor(
10820        &self,
10821        breakpoint_position: Anchor,
10822        snapshot: &EditorSnapshot,
10823        cx: &mut Context<Self>,
10824    ) -> Option<(Anchor, Breakpoint)> {
10825        let buffer = self
10826            .buffer
10827            .read(cx)
10828            .buffer_for_anchor(breakpoint_position, cx)?;
10829
10830        let enclosing_excerpt = breakpoint_position.excerpt_id;
10831        let buffer_snapshot = buffer.read(cx).snapshot();
10832
10833        let row = buffer_snapshot
10834            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
10835            .row;
10836
10837        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
10838        let anchor_end = snapshot
10839            .buffer_snapshot()
10840            .anchor_after(Point::new(row, line_len));
10841
10842        self.breakpoint_store
10843            .as_ref()?
10844            .read_with(cx, |breakpoint_store, cx| {
10845                breakpoint_store
10846                    .breakpoints(
10847                        &buffer,
10848                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
10849                        &buffer_snapshot,
10850                        cx,
10851                    )
10852                    .next()
10853                    .and_then(|(bp, _)| {
10854                        let breakpoint_row = buffer_snapshot
10855                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
10856                            .row;
10857
10858                        if breakpoint_row == row {
10859                            snapshot
10860                                .buffer_snapshot()
10861                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
10862                                .map(|position| (position, bp.bp.clone()))
10863                        } else {
10864                            None
10865                        }
10866                    })
10867            })
10868    }
10869
10870    pub fn edit_log_breakpoint(
10871        &mut self,
10872        _: &EditLogBreakpoint,
10873        window: &mut Window,
10874        cx: &mut Context<Self>,
10875    ) {
10876        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10877            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
10878                message: None,
10879                state: BreakpointState::Enabled,
10880                condition: None,
10881                hit_condition: None,
10882            });
10883
10884            self.add_edit_breakpoint_block(
10885                anchor,
10886                &breakpoint,
10887                BreakpointPromptEditAction::Log,
10888                window,
10889                cx,
10890            );
10891        }
10892    }
10893
10894    fn breakpoints_at_cursors(
10895        &self,
10896        window: &mut Window,
10897        cx: &mut Context<Self>,
10898    ) -> Vec<(Anchor, Option<Breakpoint>)> {
10899        let snapshot = self.snapshot(window, cx);
10900        let cursors = self
10901            .selections
10902            .disjoint_anchors_arc()
10903            .iter()
10904            .map(|selection| {
10905                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
10906
10907                let breakpoint_position = self
10908                    .breakpoint_at_row(cursor_position.row, window, cx)
10909                    .map(|bp| bp.0)
10910                    .unwrap_or_else(|| {
10911                        snapshot
10912                            .display_snapshot
10913                            .buffer_snapshot()
10914                            .anchor_after(Point::new(cursor_position.row, 0))
10915                    });
10916
10917                let breakpoint = self
10918                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
10919                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
10920
10921                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
10922            })
10923            // 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.
10924            .collect::<HashMap<Anchor, _>>();
10925
10926        cursors.into_iter().collect()
10927    }
10928
10929    pub fn enable_breakpoint(
10930        &mut self,
10931        _: &crate::actions::EnableBreakpoint,
10932        window: &mut Window,
10933        cx: &mut Context<Self>,
10934    ) {
10935        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10936            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
10937                continue;
10938            };
10939            self.edit_breakpoint_at_anchor(
10940                anchor,
10941                breakpoint,
10942                BreakpointEditAction::InvertState,
10943                cx,
10944            );
10945        }
10946    }
10947
10948    pub fn disable_breakpoint(
10949        &mut self,
10950        _: &crate::actions::DisableBreakpoint,
10951        window: &mut Window,
10952        cx: &mut Context<Self>,
10953    ) {
10954        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10955            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
10956                continue;
10957            };
10958            self.edit_breakpoint_at_anchor(
10959                anchor,
10960                breakpoint,
10961                BreakpointEditAction::InvertState,
10962                cx,
10963            );
10964        }
10965    }
10966
10967    pub fn toggle_breakpoint(
10968        &mut self,
10969        _: &crate::actions::ToggleBreakpoint,
10970        window: &mut Window,
10971        cx: &mut Context<Self>,
10972    ) {
10973        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
10974            if let Some(breakpoint) = breakpoint {
10975                self.edit_breakpoint_at_anchor(
10976                    anchor,
10977                    breakpoint,
10978                    BreakpointEditAction::Toggle,
10979                    cx,
10980                );
10981            } else {
10982                self.edit_breakpoint_at_anchor(
10983                    anchor,
10984                    Breakpoint::new_standard(),
10985                    BreakpointEditAction::Toggle,
10986                    cx,
10987                );
10988            }
10989        }
10990    }
10991
10992    pub fn edit_breakpoint_at_anchor(
10993        &mut self,
10994        breakpoint_position: Anchor,
10995        breakpoint: Breakpoint,
10996        edit_action: BreakpointEditAction,
10997        cx: &mut Context<Self>,
10998    ) {
10999        let Some(breakpoint_store) = &self.breakpoint_store else {
11000            return;
11001        };
11002
11003        let Some(buffer) = self
11004            .buffer
11005            .read(cx)
11006            .buffer_for_anchor(breakpoint_position, cx)
11007        else {
11008            return;
11009        };
11010
11011        breakpoint_store.update(cx, |breakpoint_store, cx| {
11012            breakpoint_store.toggle_breakpoint(
11013                buffer,
11014                BreakpointWithPosition {
11015                    position: breakpoint_position.text_anchor,
11016                    bp: breakpoint,
11017                },
11018                edit_action,
11019                cx,
11020            );
11021        });
11022
11023        cx.notify();
11024    }
11025
11026    #[cfg(any(test, feature = "test-support"))]
11027    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11028        self.breakpoint_store.clone()
11029    }
11030
11031    pub fn prepare_restore_change(
11032        &self,
11033        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11034        hunk: &MultiBufferDiffHunk,
11035        cx: &mut App,
11036    ) -> Option<()> {
11037        if hunk.is_created_file() {
11038            return None;
11039        }
11040        let buffer = self.buffer.read(cx);
11041        let diff = buffer.diff_for(hunk.buffer_id)?;
11042        let buffer = buffer.buffer(hunk.buffer_id)?;
11043        let buffer = buffer.read(cx);
11044        let original_text = diff
11045            .read(cx)
11046            .base_text()
11047            .as_rope()
11048            .slice(hunk.diff_base_byte_range.clone());
11049        let buffer_snapshot = buffer.snapshot();
11050        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11051        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11052            probe
11053                .0
11054                .start
11055                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11056                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11057        }) {
11058            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11059            Some(())
11060        } else {
11061            None
11062        }
11063    }
11064
11065    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11066        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11067    }
11068
11069    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11070        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11071    }
11072
11073    fn manipulate_lines<M>(
11074        &mut self,
11075        window: &mut Window,
11076        cx: &mut Context<Self>,
11077        mut manipulate: M,
11078    ) where
11079        M: FnMut(&str) -> LineManipulationResult,
11080    {
11081        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11082
11083        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11084        let buffer = self.buffer.read(cx).snapshot(cx);
11085
11086        let mut edits = Vec::new();
11087
11088        let selections = self.selections.all::<Point>(&display_map);
11089        let mut selections = selections.iter().peekable();
11090        let mut contiguous_row_selections = Vec::new();
11091        let mut new_selections = Vec::new();
11092        let mut added_lines = 0;
11093        let mut removed_lines = 0;
11094
11095        while let Some(selection) = selections.next() {
11096            let (start_row, end_row) = consume_contiguous_rows(
11097                &mut contiguous_row_selections,
11098                selection,
11099                &display_map,
11100                &mut selections,
11101            );
11102
11103            let start_point = Point::new(start_row.0, 0);
11104            let end_point = Point::new(
11105                end_row.previous_row().0,
11106                buffer.line_len(end_row.previous_row()),
11107            );
11108            let text = buffer
11109                .text_for_range(start_point..end_point)
11110                .collect::<String>();
11111
11112            let LineManipulationResult {
11113                new_text,
11114                line_count_before,
11115                line_count_after,
11116            } = manipulate(&text);
11117
11118            edits.push((start_point..end_point, new_text));
11119
11120            // Selections must change based on added and removed line count
11121            let start_row =
11122                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11123            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11124            new_selections.push(Selection {
11125                id: selection.id,
11126                start: start_row,
11127                end: end_row,
11128                goal: SelectionGoal::None,
11129                reversed: selection.reversed,
11130            });
11131
11132            if line_count_after > line_count_before {
11133                added_lines += line_count_after - line_count_before;
11134            } else if line_count_before > line_count_after {
11135                removed_lines += line_count_before - line_count_after;
11136            }
11137        }
11138
11139        self.transact(window, cx, |this, window, cx| {
11140            let buffer = this.buffer.update(cx, |buffer, cx| {
11141                buffer.edit(edits, None, cx);
11142                buffer.snapshot(cx)
11143            });
11144
11145            // Recalculate offsets on newly edited buffer
11146            let new_selections = new_selections
11147                .iter()
11148                .map(|s| {
11149                    let start_point = Point::new(s.start.0, 0);
11150                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11151                    Selection {
11152                        id: s.id,
11153                        start: buffer.point_to_offset(start_point),
11154                        end: buffer.point_to_offset(end_point),
11155                        goal: s.goal,
11156                        reversed: s.reversed,
11157                    }
11158                })
11159                .collect();
11160
11161            this.change_selections(Default::default(), window, cx, |s| {
11162                s.select(new_selections);
11163            });
11164
11165            this.request_autoscroll(Autoscroll::fit(), cx);
11166        });
11167    }
11168
11169    fn manipulate_immutable_lines<Fn>(
11170        &mut self,
11171        window: &mut Window,
11172        cx: &mut Context<Self>,
11173        mut callback: Fn,
11174    ) where
11175        Fn: FnMut(&mut Vec<&str>),
11176    {
11177        self.manipulate_lines(window, cx, |text| {
11178            let mut lines: Vec<&str> = text.split('\n').collect();
11179            let line_count_before = lines.len();
11180
11181            callback(&mut lines);
11182
11183            LineManipulationResult {
11184                new_text: lines.join("\n"),
11185                line_count_before,
11186                line_count_after: lines.len(),
11187            }
11188        });
11189    }
11190
11191    fn manipulate_mutable_lines<Fn>(
11192        &mut self,
11193        window: &mut Window,
11194        cx: &mut Context<Self>,
11195        mut callback: Fn,
11196    ) where
11197        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11198    {
11199        self.manipulate_lines(window, cx, |text| {
11200            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11201            let line_count_before = lines.len();
11202
11203            callback(&mut lines);
11204
11205            LineManipulationResult {
11206                new_text: lines.join("\n"),
11207                line_count_before,
11208                line_count_after: lines.len(),
11209            }
11210        });
11211    }
11212
11213    pub fn convert_indentation_to_spaces(
11214        &mut self,
11215        _: &ConvertIndentationToSpaces,
11216        window: &mut Window,
11217        cx: &mut Context<Self>,
11218    ) {
11219        let settings = self.buffer.read(cx).language_settings(cx);
11220        let tab_size = settings.tab_size.get() as usize;
11221
11222        self.manipulate_mutable_lines(window, cx, |lines| {
11223            // Allocates a reasonably sized scratch buffer once for the whole loop
11224            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11225            // Avoids recomputing spaces that could be inserted many times
11226            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11227                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11228                .collect();
11229
11230            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11231                let mut chars = line.as_ref().chars();
11232                let mut col = 0;
11233                let mut changed = false;
11234
11235                for ch in chars.by_ref() {
11236                    match ch {
11237                        ' ' => {
11238                            reindented_line.push(' ');
11239                            col += 1;
11240                        }
11241                        '\t' => {
11242                            // \t are converted to spaces depending on the current column
11243                            let spaces_len = tab_size - (col % tab_size);
11244                            reindented_line.extend(&space_cache[spaces_len - 1]);
11245                            col += spaces_len;
11246                            changed = true;
11247                        }
11248                        _ => {
11249                            // If we dont append before break, the character is consumed
11250                            reindented_line.push(ch);
11251                            break;
11252                        }
11253                    }
11254                }
11255
11256                if !changed {
11257                    reindented_line.clear();
11258                    continue;
11259                }
11260                // Append the rest of the line and replace old reference with new one
11261                reindented_line.extend(chars);
11262                *line = Cow::Owned(reindented_line.clone());
11263                reindented_line.clear();
11264            }
11265        });
11266    }
11267
11268    pub fn convert_indentation_to_tabs(
11269        &mut self,
11270        _: &ConvertIndentationToTabs,
11271        window: &mut Window,
11272        cx: &mut Context<Self>,
11273    ) {
11274        let settings = self.buffer.read(cx).language_settings(cx);
11275        let tab_size = settings.tab_size.get() as usize;
11276
11277        self.manipulate_mutable_lines(window, cx, |lines| {
11278            // Allocates a reasonably sized buffer once for the whole loop
11279            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11280            // Avoids recomputing spaces that could be inserted many times
11281            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11282                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11283                .collect();
11284
11285            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11286                let mut chars = line.chars();
11287                let mut spaces_count = 0;
11288                let mut first_non_indent_char = None;
11289                let mut changed = false;
11290
11291                for ch in chars.by_ref() {
11292                    match ch {
11293                        ' ' => {
11294                            // Keep track of spaces. Append \t when we reach tab_size
11295                            spaces_count += 1;
11296                            changed = true;
11297                            if spaces_count == tab_size {
11298                                reindented_line.push('\t');
11299                                spaces_count = 0;
11300                            }
11301                        }
11302                        '\t' => {
11303                            reindented_line.push('\t');
11304                            spaces_count = 0;
11305                        }
11306                        _ => {
11307                            // Dont append it yet, we might have remaining spaces
11308                            first_non_indent_char = Some(ch);
11309                            break;
11310                        }
11311                    }
11312                }
11313
11314                if !changed {
11315                    reindented_line.clear();
11316                    continue;
11317                }
11318                // Remaining spaces that didn't make a full tab stop
11319                if spaces_count > 0 {
11320                    reindented_line.extend(&space_cache[spaces_count - 1]);
11321                }
11322                // If we consume an extra character that was not indentation, add it back
11323                if let Some(extra_char) = first_non_indent_char {
11324                    reindented_line.push(extra_char);
11325                }
11326                // Append the rest of the line and replace old reference with new one
11327                reindented_line.extend(chars);
11328                *line = Cow::Owned(reindented_line.clone());
11329                reindented_line.clear();
11330            }
11331        });
11332    }
11333
11334    pub fn convert_to_upper_case(
11335        &mut self,
11336        _: &ConvertToUpperCase,
11337        window: &mut Window,
11338        cx: &mut Context<Self>,
11339    ) {
11340        self.manipulate_text(window, cx, |text| text.to_uppercase())
11341    }
11342
11343    pub fn convert_to_lower_case(
11344        &mut self,
11345        _: &ConvertToLowerCase,
11346        window: &mut Window,
11347        cx: &mut Context<Self>,
11348    ) {
11349        self.manipulate_text(window, cx, |text| text.to_lowercase())
11350    }
11351
11352    pub fn convert_to_title_case(
11353        &mut self,
11354        _: &ConvertToTitleCase,
11355        window: &mut Window,
11356        cx: &mut Context<Self>,
11357    ) {
11358        self.manipulate_text(window, cx, |text| {
11359            text.split('\n')
11360                .map(|line| line.to_case(Case::Title))
11361                .join("\n")
11362        })
11363    }
11364
11365    pub fn convert_to_snake_case(
11366        &mut self,
11367        _: &ConvertToSnakeCase,
11368        window: &mut Window,
11369        cx: &mut Context<Self>,
11370    ) {
11371        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
11372    }
11373
11374    pub fn convert_to_kebab_case(
11375        &mut self,
11376        _: &ConvertToKebabCase,
11377        window: &mut Window,
11378        cx: &mut Context<Self>,
11379    ) {
11380        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
11381    }
11382
11383    pub fn convert_to_upper_camel_case(
11384        &mut self,
11385        _: &ConvertToUpperCamelCase,
11386        window: &mut Window,
11387        cx: &mut Context<Self>,
11388    ) {
11389        self.manipulate_text(window, cx, |text| {
11390            text.split('\n')
11391                .map(|line| line.to_case(Case::UpperCamel))
11392                .join("\n")
11393        })
11394    }
11395
11396    pub fn convert_to_lower_camel_case(
11397        &mut self,
11398        _: &ConvertToLowerCamelCase,
11399        window: &mut Window,
11400        cx: &mut Context<Self>,
11401    ) {
11402        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
11403    }
11404
11405    pub fn convert_to_opposite_case(
11406        &mut self,
11407        _: &ConvertToOppositeCase,
11408        window: &mut Window,
11409        cx: &mut Context<Self>,
11410    ) {
11411        self.manipulate_text(window, cx, |text| {
11412            text.chars()
11413                .fold(String::with_capacity(text.len()), |mut t, c| {
11414                    if c.is_uppercase() {
11415                        t.extend(c.to_lowercase());
11416                    } else {
11417                        t.extend(c.to_uppercase());
11418                    }
11419                    t
11420                })
11421        })
11422    }
11423
11424    pub fn convert_to_sentence_case(
11425        &mut self,
11426        _: &ConvertToSentenceCase,
11427        window: &mut Window,
11428        cx: &mut Context<Self>,
11429    ) {
11430        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
11431    }
11432
11433    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
11434        self.manipulate_text(window, cx, |text| {
11435            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
11436            if has_upper_case_characters {
11437                text.to_lowercase()
11438            } else {
11439                text.to_uppercase()
11440            }
11441        })
11442    }
11443
11444    pub fn convert_to_rot13(
11445        &mut self,
11446        _: &ConvertToRot13,
11447        window: &mut Window,
11448        cx: &mut Context<Self>,
11449    ) {
11450        self.manipulate_text(window, cx, |text| {
11451            text.chars()
11452                .map(|c| match c {
11453                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
11454                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
11455                    _ => c,
11456                })
11457                .collect()
11458        })
11459    }
11460
11461    pub fn convert_to_rot47(
11462        &mut self,
11463        _: &ConvertToRot47,
11464        window: &mut Window,
11465        cx: &mut Context<Self>,
11466    ) {
11467        self.manipulate_text(window, cx, |text| {
11468            text.chars()
11469                .map(|c| {
11470                    let code_point = c as u32;
11471                    if code_point >= 33 && code_point <= 126 {
11472                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
11473                    }
11474                    c
11475                })
11476                .collect()
11477        })
11478    }
11479
11480    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
11481    where
11482        Fn: FnMut(&str) -> String,
11483    {
11484        let buffer = self.buffer.read(cx).snapshot(cx);
11485
11486        let mut new_selections = Vec::new();
11487        let mut edits = Vec::new();
11488        let mut selection_adjustment = 0i32;
11489
11490        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
11491            let selection_is_empty = selection.is_empty();
11492
11493            let (start, end) = if selection_is_empty {
11494                let (word_range, _) = buffer.surrounding_word(selection.start, None);
11495                (word_range.start, word_range.end)
11496            } else {
11497                (
11498                    buffer.point_to_offset(selection.start),
11499                    buffer.point_to_offset(selection.end),
11500                )
11501            };
11502
11503            let text = buffer.text_for_range(start..end).collect::<String>();
11504            let old_length = text.len() as i32;
11505            let text = callback(&text);
11506
11507            new_selections.push(Selection {
11508                start: (start as i32 - selection_adjustment) as usize,
11509                end: ((start + text.len()) as i32 - selection_adjustment) as usize,
11510                goal: SelectionGoal::None,
11511                id: selection.id,
11512                reversed: selection.reversed,
11513            });
11514
11515            selection_adjustment += old_length - text.len() as i32;
11516
11517            edits.push((start..end, text));
11518        }
11519
11520        self.transact(window, cx, |this, window, cx| {
11521            this.buffer.update(cx, |buffer, cx| {
11522                buffer.edit(edits, None, cx);
11523            });
11524
11525            this.change_selections(Default::default(), window, cx, |s| {
11526                s.select(new_selections);
11527            });
11528
11529            this.request_autoscroll(Autoscroll::fit(), cx);
11530        });
11531    }
11532
11533    pub fn move_selection_on_drop(
11534        &mut self,
11535        selection: &Selection<Anchor>,
11536        target: DisplayPoint,
11537        is_cut: bool,
11538        window: &mut Window,
11539        cx: &mut Context<Self>,
11540    ) {
11541        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11542        let buffer = display_map.buffer_snapshot();
11543        let mut edits = Vec::new();
11544        let insert_point = display_map
11545            .clip_point(target, Bias::Left)
11546            .to_point(&display_map);
11547        let text = buffer
11548            .text_for_range(selection.start..selection.end)
11549            .collect::<String>();
11550        if is_cut {
11551            edits.push(((selection.start..selection.end), String::new()));
11552        }
11553        let insert_anchor = buffer.anchor_before(insert_point);
11554        edits.push(((insert_anchor..insert_anchor), text));
11555        let last_edit_start = insert_anchor.bias_left(buffer);
11556        let last_edit_end = insert_anchor.bias_right(buffer);
11557        self.transact(window, cx, |this, window, cx| {
11558            this.buffer.update(cx, |buffer, cx| {
11559                buffer.edit(edits, None, cx);
11560            });
11561            this.change_selections(Default::default(), window, cx, |s| {
11562                s.select_anchor_ranges([last_edit_start..last_edit_end]);
11563            });
11564        });
11565    }
11566
11567    pub fn clear_selection_drag_state(&mut self) {
11568        self.selection_drag_state = SelectionDragState::None;
11569    }
11570
11571    pub fn duplicate(
11572        &mut self,
11573        upwards: bool,
11574        whole_lines: bool,
11575        window: &mut Window,
11576        cx: &mut Context<Self>,
11577    ) {
11578        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11579
11580        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11581        let buffer = display_map.buffer_snapshot();
11582        let selections = self.selections.all::<Point>(&display_map);
11583
11584        let mut edits = Vec::new();
11585        let mut selections_iter = selections.iter().peekable();
11586        while let Some(selection) = selections_iter.next() {
11587            let mut rows = selection.spanned_rows(false, &display_map);
11588            // duplicate line-wise
11589            if whole_lines || selection.start == selection.end {
11590                // Avoid duplicating the same lines twice.
11591                while let Some(next_selection) = selections_iter.peek() {
11592                    let next_rows = next_selection.spanned_rows(false, &display_map);
11593                    if next_rows.start < rows.end {
11594                        rows.end = next_rows.end;
11595                        selections_iter.next().unwrap();
11596                    } else {
11597                        break;
11598                    }
11599                }
11600
11601                // Copy the text from the selected row region and splice it either at the start
11602                // or end of the region.
11603                let start = Point::new(rows.start.0, 0);
11604                let end = Point::new(
11605                    rows.end.previous_row().0,
11606                    buffer.line_len(rows.end.previous_row()),
11607                );
11608
11609                let mut text = buffer.text_for_range(start..end).collect::<String>();
11610
11611                let insert_location = if upwards {
11612                    // When duplicating upward, we need to insert before the current line.
11613                    // If we're on the last line and it doesn't end with a newline,
11614                    // we need to add a newline before the duplicated content.
11615                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
11616                        && buffer.max_point().column > 0
11617                        && !text.ends_with('\n');
11618
11619                    if needs_leading_newline {
11620                        text.insert(0, '\n');
11621                        end
11622                    } else {
11623                        text.push('\n');
11624                        Point::new(rows.start.0, 0)
11625                    }
11626                } else {
11627                    text.push('\n');
11628                    start
11629                };
11630                edits.push((insert_location..insert_location, text));
11631            } else {
11632                // duplicate character-wise
11633                let start = selection.start;
11634                let end = selection.end;
11635                let text = buffer.text_for_range(start..end).collect::<String>();
11636                edits.push((selection.end..selection.end, text));
11637            }
11638        }
11639
11640        self.transact(window, cx, |this, window, cx| {
11641            this.buffer.update(cx, |buffer, cx| {
11642                buffer.edit(edits, None, cx);
11643            });
11644
11645            // When duplicating upward with whole lines, move the cursor to the duplicated line
11646            if upwards && whole_lines {
11647                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
11648
11649                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11650                    let mut new_ranges = Vec::new();
11651                    let selections = s.all::<Point>(&display_map);
11652                    let mut selections_iter = selections.iter().peekable();
11653
11654                    while let Some(first_selection) = selections_iter.next() {
11655                        // Group contiguous selections together to find the total row span
11656                        let mut group_selections = vec![first_selection];
11657                        let mut rows = first_selection.spanned_rows(false, &display_map);
11658
11659                        while let Some(next_selection) = selections_iter.peek() {
11660                            let next_rows = next_selection.spanned_rows(false, &display_map);
11661                            if next_rows.start < rows.end {
11662                                rows.end = next_rows.end;
11663                                group_selections.push(selections_iter.next().unwrap());
11664                            } else {
11665                                break;
11666                            }
11667                        }
11668
11669                        let row_count = rows.end.0 - rows.start.0;
11670
11671                        // Move all selections in this group up by the total number of duplicated rows
11672                        for selection in group_selections {
11673                            let new_start = Point::new(
11674                                selection.start.row.saturating_sub(row_count),
11675                                selection.start.column,
11676                            );
11677
11678                            let new_end = Point::new(
11679                                selection.end.row.saturating_sub(row_count),
11680                                selection.end.column,
11681                            );
11682
11683                            new_ranges.push(new_start..new_end);
11684                        }
11685                    }
11686
11687                    s.select_ranges(new_ranges);
11688                });
11689            }
11690
11691            this.request_autoscroll(Autoscroll::fit(), cx);
11692        });
11693    }
11694
11695    pub fn duplicate_line_up(
11696        &mut self,
11697        _: &DuplicateLineUp,
11698        window: &mut Window,
11699        cx: &mut Context<Self>,
11700    ) {
11701        self.duplicate(true, true, window, cx);
11702    }
11703
11704    pub fn duplicate_line_down(
11705        &mut self,
11706        _: &DuplicateLineDown,
11707        window: &mut Window,
11708        cx: &mut Context<Self>,
11709    ) {
11710        self.duplicate(false, true, window, cx);
11711    }
11712
11713    pub fn duplicate_selection(
11714        &mut self,
11715        _: &DuplicateSelection,
11716        window: &mut Window,
11717        cx: &mut Context<Self>,
11718    ) {
11719        self.duplicate(false, false, window, cx);
11720    }
11721
11722    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
11723        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11724        if self.mode.is_single_line() {
11725            cx.propagate();
11726            return;
11727        }
11728
11729        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11730        let buffer = self.buffer.read(cx).snapshot(cx);
11731
11732        let mut edits = Vec::new();
11733        let mut unfold_ranges = Vec::new();
11734        let mut refold_creases = Vec::new();
11735
11736        let selections = self.selections.all::<Point>(&display_map);
11737        let mut selections = selections.iter().peekable();
11738        let mut contiguous_row_selections = Vec::new();
11739        let mut new_selections = Vec::new();
11740
11741        while let Some(selection) = selections.next() {
11742            // Find all the selections that span a contiguous row range
11743            let (start_row, end_row) = consume_contiguous_rows(
11744                &mut contiguous_row_selections,
11745                selection,
11746                &display_map,
11747                &mut selections,
11748            );
11749
11750            // Move the text spanned by the row range to be before the line preceding the row range
11751            if start_row.0 > 0 {
11752                let range_to_move = Point::new(
11753                    start_row.previous_row().0,
11754                    buffer.line_len(start_row.previous_row()),
11755                )
11756                    ..Point::new(
11757                        end_row.previous_row().0,
11758                        buffer.line_len(end_row.previous_row()),
11759                    );
11760                let insertion_point = display_map
11761                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
11762                    .0;
11763
11764                // Don't move lines across excerpts
11765                if buffer
11766                    .excerpt_containing(insertion_point..range_to_move.end)
11767                    .is_some()
11768                {
11769                    let text = buffer
11770                        .text_for_range(range_to_move.clone())
11771                        .flat_map(|s| s.chars())
11772                        .skip(1)
11773                        .chain(['\n'])
11774                        .collect::<String>();
11775
11776                    edits.push((
11777                        buffer.anchor_after(range_to_move.start)
11778                            ..buffer.anchor_before(range_to_move.end),
11779                        String::new(),
11780                    ));
11781                    let insertion_anchor = buffer.anchor_after(insertion_point);
11782                    edits.push((insertion_anchor..insertion_anchor, text));
11783
11784                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
11785
11786                    // Move selections up
11787                    new_selections.extend(contiguous_row_selections.drain(..).map(
11788                        |mut selection| {
11789                            selection.start.row -= row_delta;
11790                            selection.end.row -= row_delta;
11791                            selection
11792                        },
11793                    ));
11794
11795                    // Move folds up
11796                    unfold_ranges.push(range_to_move.clone());
11797                    for fold in display_map.folds_in_range(
11798                        buffer.anchor_before(range_to_move.start)
11799                            ..buffer.anchor_after(range_to_move.end),
11800                    ) {
11801                        let mut start = fold.range.start.to_point(&buffer);
11802                        let mut end = fold.range.end.to_point(&buffer);
11803                        start.row -= row_delta;
11804                        end.row -= row_delta;
11805                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11806                    }
11807                }
11808            }
11809
11810            // If we didn't move line(s), preserve the existing selections
11811            new_selections.append(&mut contiguous_row_selections);
11812        }
11813
11814        self.transact(window, cx, |this, window, cx| {
11815            this.unfold_ranges(&unfold_ranges, true, true, cx);
11816            this.buffer.update(cx, |buffer, cx| {
11817                for (range, text) in edits {
11818                    buffer.edit([(range, text)], None, cx);
11819                }
11820            });
11821            this.fold_creases(refold_creases, true, window, cx);
11822            this.change_selections(Default::default(), window, cx, |s| {
11823                s.select(new_selections);
11824            })
11825        });
11826    }
11827
11828    pub fn move_line_down(
11829        &mut self,
11830        _: &MoveLineDown,
11831        window: &mut Window,
11832        cx: &mut Context<Self>,
11833    ) {
11834        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11835        if self.mode.is_single_line() {
11836            cx.propagate();
11837            return;
11838        }
11839
11840        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11841        let buffer = self.buffer.read(cx).snapshot(cx);
11842
11843        let mut edits = Vec::new();
11844        let mut unfold_ranges = Vec::new();
11845        let mut refold_creases = Vec::new();
11846
11847        let selections = self.selections.all::<Point>(&display_map);
11848        let mut selections = selections.iter().peekable();
11849        let mut contiguous_row_selections = Vec::new();
11850        let mut new_selections = Vec::new();
11851
11852        while let Some(selection) = selections.next() {
11853            // Find all the selections that span a contiguous row range
11854            let (start_row, end_row) = consume_contiguous_rows(
11855                &mut contiguous_row_selections,
11856                selection,
11857                &display_map,
11858                &mut selections,
11859            );
11860
11861            // Move the text spanned by the row range to be after the last line of the row range
11862            if end_row.0 <= buffer.max_point().row {
11863                let range_to_move =
11864                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
11865                let insertion_point = display_map
11866                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
11867                    .0;
11868
11869                // Don't move lines across excerpt boundaries
11870                if buffer
11871                    .excerpt_containing(range_to_move.start..insertion_point)
11872                    .is_some()
11873                {
11874                    let mut text = String::from("\n");
11875                    text.extend(buffer.text_for_range(range_to_move.clone()));
11876                    text.pop(); // Drop trailing newline
11877                    edits.push((
11878                        buffer.anchor_after(range_to_move.start)
11879                            ..buffer.anchor_before(range_to_move.end),
11880                        String::new(),
11881                    ));
11882                    let insertion_anchor = buffer.anchor_after(insertion_point);
11883                    edits.push((insertion_anchor..insertion_anchor, text));
11884
11885                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
11886
11887                    // Move selections down
11888                    new_selections.extend(contiguous_row_selections.drain(..).map(
11889                        |mut selection| {
11890                            selection.start.row += row_delta;
11891                            selection.end.row += row_delta;
11892                            selection
11893                        },
11894                    ));
11895
11896                    // Move folds down
11897                    unfold_ranges.push(range_to_move.clone());
11898                    for fold in display_map.folds_in_range(
11899                        buffer.anchor_before(range_to_move.start)
11900                            ..buffer.anchor_after(range_to_move.end),
11901                    ) {
11902                        let mut start = fold.range.start.to_point(&buffer);
11903                        let mut end = fold.range.end.to_point(&buffer);
11904                        start.row += row_delta;
11905                        end.row += row_delta;
11906                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
11907                    }
11908                }
11909            }
11910
11911            // If we didn't move line(s), preserve the existing selections
11912            new_selections.append(&mut contiguous_row_selections);
11913        }
11914
11915        self.transact(window, cx, |this, window, cx| {
11916            this.unfold_ranges(&unfold_ranges, true, true, cx);
11917            this.buffer.update(cx, |buffer, cx| {
11918                for (range, text) in edits {
11919                    buffer.edit([(range, text)], None, cx);
11920                }
11921            });
11922            this.fold_creases(refold_creases, true, window, cx);
11923            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
11924        });
11925    }
11926
11927    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
11928        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11929        let text_layout_details = &self.text_layout_details(window);
11930        self.transact(window, cx, |this, window, cx| {
11931            let edits = this.change_selections(Default::default(), window, cx, |s| {
11932                let mut edits: Vec<(Range<usize>, String)> = Default::default();
11933                s.move_with(|display_map, selection| {
11934                    if !selection.is_empty() {
11935                        return;
11936                    }
11937
11938                    let mut head = selection.head();
11939                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
11940                    if head.column() == display_map.line_len(head.row()) {
11941                        transpose_offset = display_map
11942                            .buffer_snapshot()
11943                            .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11944                    }
11945
11946                    if transpose_offset == 0 {
11947                        return;
11948                    }
11949
11950                    *head.column_mut() += 1;
11951                    head = display_map.clip_point(head, Bias::Right);
11952                    let goal = SelectionGoal::HorizontalPosition(
11953                        display_map
11954                            .x_for_display_point(head, text_layout_details)
11955                            .into(),
11956                    );
11957                    selection.collapse_to(head, goal);
11958
11959                    let transpose_start = display_map
11960                        .buffer_snapshot()
11961                        .clip_offset(transpose_offset.saturating_sub(1), Bias::Left);
11962                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
11963                        let transpose_end = display_map
11964                            .buffer_snapshot()
11965                            .clip_offset(transpose_offset + 1, Bias::Right);
11966                        if let Some(ch) = display_map
11967                            .buffer_snapshot()
11968                            .chars_at(transpose_start)
11969                            .next()
11970                        {
11971                            edits.push((transpose_start..transpose_offset, String::new()));
11972                            edits.push((transpose_end..transpose_end, ch.to_string()));
11973                        }
11974                    }
11975                });
11976                edits
11977            });
11978            this.buffer
11979                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
11980            let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
11981            this.change_selections(Default::default(), window, cx, |s| {
11982                s.select(selections);
11983            });
11984        });
11985    }
11986
11987    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
11988        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11989        if self.mode.is_single_line() {
11990            cx.propagate();
11991            return;
11992        }
11993
11994        self.rewrap_impl(RewrapOptions::default(), cx)
11995    }
11996
11997    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
11998        let buffer = self.buffer.read(cx).snapshot(cx);
11999        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12000
12001        #[derive(Clone, Debug, PartialEq)]
12002        enum CommentFormat {
12003            /// single line comment, with prefix for line
12004            Line(String),
12005            /// single line within a block comment, with prefix for line
12006            BlockLine(String),
12007            /// a single line of a block comment that includes the initial delimiter
12008            BlockCommentWithStart(BlockCommentConfig),
12009            /// a single line of a block comment that includes the ending delimiter
12010            BlockCommentWithEnd(BlockCommentConfig),
12011        }
12012
12013        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12014        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12015            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12016                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12017                .peekable();
12018
12019            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12020                row
12021            } else {
12022                return Vec::new();
12023            };
12024
12025            let language_settings = buffer.language_settings_at(selection.head(), cx);
12026            let language_scope = buffer.language_scope_at(selection.head());
12027
12028            let indent_and_prefix_for_row =
12029                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12030                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12031                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12032                        &language_scope
12033                    {
12034                        let indent_end = Point::new(row, indent.len);
12035                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12036                        let line_text_after_indent = buffer
12037                            .text_for_range(indent_end..line_end)
12038                            .collect::<String>();
12039
12040                        let is_within_comment_override = buffer
12041                            .language_scope_at(indent_end)
12042                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12043                        let comment_delimiters = if is_within_comment_override {
12044                            // we are within a comment syntax node, but we don't
12045                            // yet know what kind of comment: block, doc or line
12046                            match (
12047                                language_scope.documentation_comment(),
12048                                language_scope.block_comment(),
12049                            ) {
12050                                (Some(config), _) | (_, Some(config))
12051                                    if buffer.contains_str_at(indent_end, &config.start) =>
12052                                {
12053                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12054                                }
12055                                (Some(config), _) | (_, Some(config))
12056                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12057                                {
12058                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12059                                }
12060                                (Some(config), _) | (_, Some(config))
12061                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12062                                {
12063                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12064                                }
12065                                (_, _) => language_scope
12066                                    .line_comment_prefixes()
12067                                    .iter()
12068                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12069                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12070                            }
12071                        } else {
12072                            // we not in an overridden comment node, but we may
12073                            // be within a non-overridden line comment node
12074                            language_scope
12075                                .line_comment_prefixes()
12076                                .iter()
12077                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12078                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12079                        };
12080
12081                        let rewrap_prefix = language_scope
12082                            .rewrap_prefixes()
12083                            .iter()
12084                            .find_map(|prefix_regex| {
12085                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12086                                    if mat.start() == 0 {
12087                                        Some(mat.as_str().to_string())
12088                                    } else {
12089                                        None
12090                                    }
12091                                })
12092                            })
12093                            .flatten();
12094                        (comment_delimiters, rewrap_prefix)
12095                    } else {
12096                        (None, None)
12097                    };
12098                    (indent, comment_prefix, rewrap_prefix)
12099                };
12100
12101            let mut ranges = Vec::new();
12102            let from_empty_selection = selection.is_empty();
12103
12104            let mut current_range_start = first_row;
12105            let mut prev_row = first_row;
12106            let (
12107                mut current_range_indent,
12108                mut current_range_comment_delimiters,
12109                mut current_range_rewrap_prefix,
12110            ) = indent_and_prefix_for_row(first_row);
12111
12112            for row in non_blank_rows_iter.skip(1) {
12113                let has_paragraph_break = row > prev_row + 1;
12114
12115                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12116                    indent_and_prefix_for_row(row);
12117
12118                let has_indent_change = row_indent != current_range_indent;
12119                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12120
12121                let has_boundary_change = has_comment_change
12122                    || row_rewrap_prefix.is_some()
12123                    || (has_indent_change && current_range_comment_delimiters.is_some());
12124
12125                if has_paragraph_break || has_boundary_change {
12126                    ranges.push((
12127                        language_settings.clone(),
12128                        Point::new(current_range_start, 0)
12129                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12130                        current_range_indent,
12131                        current_range_comment_delimiters.clone(),
12132                        current_range_rewrap_prefix.clone(),
12133                        from_empty_selection,
12134                    ));
12135                    current_range_start = row;
12136                    current_range_indent = row_indent;
12137                    current_range_comment_delimiters = row_comment_delimiters;
12138                    current_range_rewrap_prefix = row_rewrap_prefix;
12139                }
12140                prev_row = row;
12141            }
12142
12143            ranges.push((
12144                language_settings.clone(),
12145                Point::new(current_range_start, 0)
12146                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12147                current_range_indent,
12148                current_range_comment_delimiters,
12149                current_range_rewrap_prefix,
12150                from_empty_selection,
12151            ));
12152
12153            ranges
12154        });
12155
12156        let mut edits = Vec::new();
12157        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12158
12159        for (
12160            language_settings,
12161            wrap_range,
12162            mut indent_size,
12163            comment_prefix,
12164            rewrap_prefix,
12165            from_empty_selection,
12166        ) in wrap_ranges
12167        {
12168            let mut start_row = wrap_range.start.row;
12169            let mut end_row = wrap_range.end.row;
12170
12171            // Skip selections that overlap with a range that has already been rewrapped.
12172            let selection_range = start_row..end_row;
12173            if rewrapped_row_ranges
12174                .iter()
12175                .any(|range| range.overlaps(&selection_range))
12176            {
12177                continue;
12178            }
12179
12180            let tab_size = language_settings.tab_size;
12181
12182            let (line_prefix, inside_comment) = match &comment_prefix {
12183                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12184                    (Some(prefix.as_str()), true)
12185                }
12186                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12187                    (Some(prefix.as_ref()), true)
12188                }
12189                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12190                    start: _,
12191                    end: _,
12192                    prefix,
12193                    tab_size,
12194                })) => {
12195                    indent_size.len += tab_size;
12196                    (Some(prefix.as_ref()), true)
12197                }
12198                None => (None, false),
12199            };
12200            let indent_prefix = indent_size.chars().collect::<String>();
12201            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12202
12203            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12204                RewrapBehavior::InComments => inside_comment,
12205                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12206                RewrapBehavior::Anywhere => true,
12207            };
12208
12209            let should_rewrap = options.override_language_settings
12210                || allow_rewrap_based_on_language
12211                || self.hard_wrap.is_some();
12212            if !should_rewrap {
12213                continue;
12214            }
12215
12216            if from_empty_selection {
12217                'expand_upwards: while start_row > 0 {
12218                    let prev_row = start_row - 1;
12219                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12220                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12221                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12222                    {
12223                        start_row = prev_row;
12224                    } else {
12225                        break 'expand_upwards;
12226                    }
12227                }
12228
12229                'expand_downwards: while end_row < buffer.max_point().row {
12230                    let next_row = end_row + 1;
12231                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12232                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12233                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12234                    {
12235                        end_row = next_row;
12236                    } else {
12237                        break 'expand_downwards;
12238                    }
12239                }
12240            }
12241
12242            let start = Point::new(start_row, 0);
12243            let start_offset = ToOffset::to_offset(&start, &buffer);
12244            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12245            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12246            let mut first_line_delimiter = None;
12247            let mut last_line_delimiter = None;
12248            let Some(lines_without_prefixes) = selection_text
12249                .lines()
12250                .enumerate()
12251                .map(|(ix, line)| {
12252                    let line_trimmed = line.trim_start();
12253                    if rewrap_prefix.is_some() && ix > 0 {
12254                        Ok(line_trimmed)
12255                    } else if let Some(
12256                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12257                            start,
12258                            prefix,
12259                            end,
12260                            tab_size,
12261                        })
12262                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12263                            start,
12264                            prefix,
12265                            end,
12266                            tab_size,
12267                        }),
12268                    ) = &comment_prefix
12269                    {
12270                        let line_trimmed = line_trimmed
12271                            .strip_prefix(start.as_ref())
12272                            .map(|s| {
12273                                let mut indent_size = indent_size;
12274                                indent_size.len -= tab_size;
12275                                let indent_prefix: String = indent_size.chars().collect();
12276                                first_line_delimiter = Some((indent_prefix, start));
12277                                s.trim_start()
12278                            })
12279                            .unwrap_or(line_trimmed);
12280                        let line_trimmed = line_trimmed
12281                            .strip_suffix(end.as_ref())
12282                            .map(|s| {
12283                                last_line_delimiter = Some(end);
12284                                s.trim_end()
12285                            })
12286                            .unwrap_or(line_trimmed);
12287                        let line_trimmed = line_trimmed
12288                            .strip_prefix(prefix.as_ref())
12289                            .unwrap_or(line_trimmed);
12290                        Ok(line_trimmed)
12291                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12292                        line_trimmed.strip_prefix(prefix).with_context(|| {
12293                            format!("line did not start with prefix {prefix:?}: {line:?}")
12294                        })
12295                    } else {
12296                        line_trimmed
12297                            .strip_prefix(&line_prefix.trim_start())
12298                            .with_context(|| {
12299                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12300                            })
12301                    }
12302                })
12303                .collect::<Result<Vec<_>, _>>()
12304                .log_err()
12305            else {
12306                continue;
12307            };
12308
12309            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12310                buffer
12311                    .language_settings_at(Point::new(start_row, 0), cx)
12312                    .preferred_line_length as usize
12313            });
12314
12315            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12316                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12317            } else {
12318                line_prefix.clone()
12319            };
12320
12321            let wrapped_text = {
12322                let mut wrapped_text = wrap_with_prefix(
12323                    line_prefix,
12324                    subsequent_lines_prefix,
12325                    lines_without_prefixes.join("\n"),
12326                    wrap_column,
12327                    tab_size,
12328                    options.preserve_existing_whitespace,
12329                );
12330
12331                if let Some((indent, delimiter)) = first_line_delimiter {
12332                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12333                }
12334                if let Some(last_line) = last_line_delimiter {
12335                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
12336                }
12337
12338                wrapped_text
12339            };
12340
12341            // TODO: should always use char-based diff while still supporting cursor behavior that
12342            // matches vim.
12343            let mut diff_options = DiffOptions::default();
12344            if options.override_language_settings {
12345                diff_options.max_word_diff_len = 0;
12346                diff_options.max_word_diff_line_count = 0;
12347            } else {
12348                diff_options.max_word_diff_len = usize::MAX;
12349                diff_options.max_word_diff_line_count = usize::MAX;
12350            }
12351
12352            for (old_range, new_text) in
12353                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
12354            {
12355                let edit_start = buffer.anchor_after(start_offset + old_range.start);
12356                let edit_end = buffer.anchor_after(start_offset + old_range.end);
12357                edits.push((edit_start..edit_end, new_text));
12358            }
12359
12360            rewrapped_row_ranges.push(start_row..=end_row);
12361        }
12362
12363        self.buffer
12364            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12365    }
12366
12367    pub fn cut_common(
12368        &mut self,
12369        cut_no_selection_line: bool,
12370        window: &mut Window,
12371        cx: &mut Context<Self>,
12372    ) -> ClipboardItem {
12373        let mut text = String::new();
12374        let buffer = self.buffer.read(cx).snapshot(cx);
12375        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12376        let mut clipboard_selections = Vec::with_capacity(selections.len());
12377        {
12378            let max_point = buffer.max_point();
12379            let mut is_first = true;
12380            for selection in &mut selections {
12381                let is_entire_line =
12382                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
12383                if is_entire_line {
12384                    selection.start = Point::new(selection.start.row, 0);
12385                    if !selection.is_empty() && selection.end.column == 0 {
12386                        selection.end = cmp::min(max_point, selection.end);
12387                    } else {
12388                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
12389                    }
12390                    selection.goal = SelectionGoal::None;
12391                }
12392                if is_first {
12393                    is_first = false;
12394                } else {
12395                    text += "\n";
12396                }
12397                let mut len = 0;
12398                for chunk in buffer.text_for_range(selection.start..selection.end) {
12399                    text.push_str(chunk);
12400                    len += chunk.len();
12401                }
12402                clipboard_selections.push(ClipboardSelection {
12403                    len,
12404                    is_entire_line,
12405                    first_line_indent: buffer
12406                        .indent_size_for_line(MultiBufferRow(selection.start.row))
12407                        .len,
12408                });
12409            }
12410        }
12411
12412        self.transact(window, cx, |this, window, cx| {
12413            this.change_selections(Default::default(), window, cx, |s| {
12414                s.select(selections);
12415            });
12416            this.insert("", window, cx);
12417        });
12418        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
12419    }
12420
12421    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
12422        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12423        let item = self.cut_common(true, window, cx);
12424        cx.write_to_clipboard(item);
12425    }
12426
12427    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
12428        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12429        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12430            s.move_with(|snapshot, sel| {
12431                if sel.is_empty() {
12432                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
12433                }
12434                if sel.is_empty() {
12435                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
12436                }
12437            });
12438        });
12439        let item = self.cut_common(false, window, cx);
12440        cx.set_global(KillRing(item))
12441    }
12442
12443    pub fn kill_ring_yank(
12444        &mut self,
12445        _: &KillRingYank,
12446        window: &mut Window,
12447        cx: &mut Context<Self>,
12448    ) {
12449        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12450        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
12451            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
12452                (kill_ring.text().to_string(), kill_ring.metadata_json())
12453            } else {
12454                return;
12455            }
12456        } else {
12457            return;
12458        };
12459        self.do_paste(&text, metadata, false, window, cx);
12460    }
12461
12462    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
12463        self.do_copy(true, cx);
12464    }
12465
12466    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
12467        self.do_copy(false, cx);
12468    }
12469
12470    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
12471        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12472        let buffer = self.buffer.read(cx).read(cx);
12473        let mut text = String::new();
12474
12475        let mut clipboard_selections = Vec::with_capacity(selections.len());
12476        {
12477            let max_point = buffer.max_point();
12478            let mut is_first = true;
12479            for selection in &selections {
12480                let mut start = selection.start;
12481                let mut end = selection.end;
12482                let is_entire_line = selection.is_empty() || self.selections.line_mode();
12483                let mut add_trailing_newline = false;
12484                if is_entire_line {
12485                    start = Point::new(start.row, 0);
12486                    let next_line_start = Point::new(end.row + 1, 0);
12487                    if next_line_start <= max_point {
12488                        end = next_line_start;
12489                    } else {
12490                        // We're on the last line without a trailing newline.
12491                        // Copy to the end of the line and add a newline afterwards.
12492                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
12493                        add_trailing_newline = true;
12494                    }
12495                }
12496
12497                let mut trimmed_selections = Vec::new();
12498                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
12499                    let row = MultiBufferRow(start.row);
12500                    let first_indent = buffer.indent_size_for_line(row);
12501                    if first_indent.len == 0 || start.column > first_indent.len {
12502                        trimmed_selections.push(start..end);
12503                    } else {
12504                        trimmed_selections.push(
12505                            Point::new(row.0, first_indent.len)
12506                                ..Point::new(row.0, buffer.line_len(row)),
12507                        );
12508                        for row in start.row + 1..=end.row {
12509                            let mut line_len = buffer.line_len(MultiBufferRow(row));
12510                            if row == end.row {
12511                                line_len = end.column;
12512                            }
12513                            if line_len == 0 {
12514                                trimmed_selections
12515                                    .push(Point::new(row, 0)..Point::new(row, line_len));
12516                                continue;
12517                            }
12518                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
12519                            if row_indent_size.len >= first_indent.len {
12520                                trimmed_selections.push(
12521                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
12522                                );
12523                            } else {
12524                                trimmed_selections.clear();
12525                                trimmed_selections.push(start..end);
12526                                break;
12527                            }
12528                        }
12529                    }
12530                } else {
12531                    trimmed_selections.push(start..end);
12532                }
12533
12534                for trimmed_range in trimmed_selections {
12535                    if is_first {
12536                        is_first = false;
12537                    } else {
12538                        text += "\n";
12539                    }
12540                    let mut len = 0;
12541                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
12542                        text.push_str(chunk);
12543                        len += chunk.len();
12544                    }
12545                    if add_trailing_newline {
12546                        text.push('\n');
12547                        len += 1;
12548                    }
12549                    clipboard_selections.push(ClipboardSelection {
12550                        len,
12551                        is_entire_line,
12552                        first_line_indent: buffer
12553                            .indent_size_for_line(MultiBufferRow(trimmed_range.start.row))
12554                            .len,
12555                    });
12556                }
12557            }
12558        }
12559
12560        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
12561            text,
12562            clipboard_selections,
12563        ));
12564    }
12565
12566    pub fn do_paste(
12567        &mut self,
12568        text: &String,
12569        clipboard_selections: Option<Vec<ClipboardSelection>>,
12570        handle_entire_lines: bool,
12571        window: &mut Window,
12572        cx: &mut Context<Self>,
12573    ) {
12574        if self.read_only(cx) {
12575            return;
12576        }
12577
12578        let clipboard_text = Cow::Borrowed(text.as_str());
12579
12580        self.transact(window, cx, |this, window, cx| {
12581            let had_active_edit_prediction = this.has_active_edit_prediction();
12582            let display_map = this.display_snapshot(cx);
12583            let old_selections = this.selections.all::<usize>(&display_map);
12584            let cursor_offset = this.selections.last::<usize>(&display_map).head();
12585
12586            if let Some(mut clipboard_selections) = clipboard_selections {
12587                let all_selections_were_entire_line =
12588                    clipboard_selections.iter().all(|s| s.is_entire_line);
12589                let first_selection_indent_column =
12590                    clipboard_selections.first().map(|s| s.first_line_indent);
12591                if clipboard_selections.len() != old_selections.len() {
12592                    clipboard_selections.drain(..);
12593                }
12594                let mut auto_indent_on_paste = true;
12595
12596                this.buffer.update(cx, |buffer, cx| {
12597                    let snapshot = buffer.read(cx);
12598                    auto_indent_on_paste = snapshot
12599                        .language_settings_at(cursor_offset, cx)
12600                        .auto_indent_on_paste;
12601
12602                    let mut start_offset = 0;
12603                    let mut edits = Vec::new();
12604                    let mut original_indent_columns = Vec::new();
12605                    for (ix, selection) in old_selections.iter().enumerate() {
12606                        let to_insert;
12607                        let entire_line;
12608                        let original_indent_column;
12609                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
12610                            let end_offset = start_offset + clipboard_selection.len;
12611                            to_insert = &clipboard_text[start_offset..end_offset];
12612                            entire_line = clipboard_selection.is_entire_line;
12613                            start_offset = end_offset + 1;
12614                            original_indent_column = Some(clipboard_selection.first_line_indent);
12615                        } else {
12616                            to_insert = &*clipboard_text;
12617                            entire_line = all_selections_were_entire_line;
12618                            original_indent_column = first_selection_indent_column
12619                        }
12620
12621                        let (range, to_insert) =
12622                            if selection.is_empty() && handle_entire_lines && entire_line {
12623                                // If the corresponding selection was empty when this slice of the
12624                                // clipboard text was written, then the entire line containing the
12625                                // selection was copied. If this selection is also currently empty,
12626                                // then paste the line before the current line of the buffer.
12627                                let column = selection.start.to_point(&snapshot).column as usize;
12628                                let line_start = selection.start - column;
12629                                (line_start..line_start, Cow::Borrowed(to_insert))
12630                            } else {
12631                                let language = snapshot.language_at(selection.head());
12632                                let range = selection.range();
12633                                if let Some(language) = language
12634                                    && language.name() == "Markdown".into()
12635                                {
12636                                    edit_for_markdown_paste(
12637                                        &snapshot,
12638                                        range,
12639                                        to_insert,
12640                                        url::Url::parse(to_insert).ok(),
12641                                    )
12642                                } else {
12643                                    (range, Cow::Borrowed(to_insert))
12644                                }
12645                            };
12646
12647                        edits.push((range, to_insert));
12648                        original_indent_columns.push(original_indent_column);
12649                    }
12650                    drop(snapshot);
12651
12652                    buffer.edit(
12653                        edits,
12654                        if auto_indent_on_paste {
12655                            Some(AutoindentMode::Block {
12656                                original_indent_columns,
12657                            })
12658                        } else {
12659                            None
12660                        },
12661                        cx,
12662                    );
12663                });
12664
12665                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
12666                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
12667            } else {
12668                let url = url::Url::parse(&clipboard_text).ok();
12669
12670                let auto_indent_mode = if !clipboard_text.is_empty() {
12671                    Some(AutoindentMode::Block {
12672                        original_indent_columns: Vec::new(),
12673                    })
12674                } else {
12675                    None
12676                };
12677
12678                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
12679                    let snapshot = buffer.snapshot(cx);
12680
12681                    let anchors = old_selections
12682                        .iter()
12683                        .map(|s| {
12684                            let anchor = snapshot.anchor_after(s.head());
12685                            s.map(|_| anchor)
12686                        })
12687                        .collect::<Vec<_>>();
12688
12689                    let mut edits = Vec::new();
12690
12691                    for selection in old_selections.iter() {
12692                        let language = snapshot.language_at(selection.head());
12693                        let range = selection.range();
12694
12695                        let (edit_range, edit_text) = if let Some(language) = language
12696                            && language.name() == "Markdown".into()
12697                        {
12698                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
12699                        } else {
12700                            (range, clipboard_text.clone())
12701                        };
12702
12703                        edits.push((edit_range, edit_text));
12704                    }
12705
12706                    drop(snapshot);
12707                    buffer.edit(edits, auto_indent_mode, cx);
12708
12709                    anchors
12710                });
12711
12712                this.change_selections(Default::default(), window, cx, |s| {
12713                    s.select_anchors(selection_anchors);
12714                });
12715            }
12716
12717            let trigger_in_words =
12718                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
12719
12720            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
12721        });
12722    }
12723
12724    pub fn diff_clipboard_with_selection(
12725        &mut self,
12726        _: &DiffClipboardWithSelection,
12727        window: &mut Window,
12728        cx: &mut Context<Self>,
12729    ) {
12730        let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
12731
12732        if selections.is_empty() {
12733            log::warn!("There should always be at least one selection in Zed. This is a bug.");
12734            return;
12735        };
12736
12737        let clipboard_text = match cx.read_from_clipboard() {
12738            Some(item) => match item.entries().first() {
12739                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
12740                _ => None,
12741            },
12742            None => None,
12743        };
12744
12745        let Some(clipboard_text) = clipboard_text else {
12746            log::warn!("Clipboard doesn't contain text.");
12747            return;
12748        };
12749
12750        window.dispatch_action(
12751            Box::new(DiffClipboardWithSelectionData {
12752                clipboard_text,
12753                editor: cx.entity(),
12754            }),
12755            cx,
12756        );
12757    }
12758
12759    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
12760        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12761        if let Some(item) = cx.read_from_clipboard() {
12762            let entries = item.entries();
12763
12764            match entries.first() {
12765                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
12766                // of all the pasted entries.
12767                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
12768                    .do_paste(
12769                        clipboard_string.text(),
12770                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
12771                        true,
12772                        window,
12773                        cx,
12774                    ),
12775                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
12776            }
12777        }
12778    }
12779
12780    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
12781        if self.read_only(cx) {
12782            return;
12783        }
12784
12785        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12786
12787        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
12788            if let Some((selections, _)) =
12789                self.selection_history.transaction(transaction_id).cloned()
12790            {
12791                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12792                    s.select_anchors(selections.to_vec());
12793                });
12794            } else {
12795                log::error!(
12796                    "No entry in selection_history found for undo. \
12797                     This may correspond to a bug where undo does not update the selection. \
12798                     If this is occurring, please add details to \
12799                     https://github.com/zed-industries/zed/issues/22692"
12800                );
12801            }
12802            self.request_autoscroll(Autoscroll::fit(), cx);
12803            self.unmark_text(window, cx);
12804            self.refresh_edit_prediction(true, false, window, cx);
12805            cx.emit(EditorEvent::Edited { transaction_id });
12806            cx.emit(EditorEvent::TransactionUndone { transaction_id });
12807        }
12808    }
12809
12810    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
12811        if self.read_only(cx) {
12812            return;
12813        }
12814
12815        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12816
12817        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
12818            if let Some((_, Some(selections))) =
12819                self.selection_history.transaction(transaction_id).cloned()
12820            {
12821                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12822                    s.select_anchors(selections.to_vec());
12823                });
12824            } else {
12825                log::error!(
12826                    "No entry in selection_history found for redo. \
12827                     This may correspond to a bug where undo does not update the selection. \
12828                     If this is occurring, please add details to \
12829                     https://github.com/zed-industries/zed/issues/22692"
12830                );
12831            }
12832            self.request_autoscroll(Autoscroll::fit(), cx);
12833            self.unmark_text(window, cx);
12834            self.refresh_edit_prediction(true, false, window, cx);
12835            cx.emit(EditorEvent::Edited { transaction_id });
12836        }
12837    }
12838
12839    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
12840        self.buffer
12841            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
12842    }
12843
12844    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
12845        self.buffer
12846            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
12847    }
12848
12849    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
12850        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12851        self.change_selections(Default::default(), window, cx, |s| {
12852            s.move_with(|map, selection| {
12853                let cursor = if selection.is_empty() {
12854                    movement::left(map, selection.start)
12855                } else {
12856                    selection.start
12857                };
12858                selection.collapse_to(cursor, SelectionGoal::None);
12859            });
12860        })
12861    }
12862
12863    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
12864        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12865        self.change_selections(Default::default(), window, cx, |s| {
12866            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
12867        })
12868    }
12869
12870    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
12871        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12872        self.change_selections(Default::default(), window, cx, |s| {
12873            s.move_with(|map, selection| {
12874                let cursor = if selection.is_empty() {
12875                    movement::right(map, selection.end)
12876                } else {
12877                    selection.end
12878                };
12879                selection.collapse_to(cursor, SelectionGoal::None)
12880            });
12881        })
12882    }
12883
12884    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
12885        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12886        self.change_selections(Default::default(), window, cx, |s| {
12887            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
12888        });
12889    }
12890
12891    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
12892        if self.take_rename(true, window, cx).is_some() {
12893            return;
12894        }
12895
12896        if self.mode.is_single_line() {
12897            cx.propagate();
12898            return;
12899        }
12900
12901        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12902
12903        let text_layout_details = &self.text_layout_details(window);
12904        let selection_count = self.selections.count();
12905        let first_selection = self.selections.first_anchor();
12906
12907        self.change_selections(Default::default(), window, cx, |s| {
12908            s.move_with(|map, selection| {
12909                if !selection.is_empty() {
12910                    selection.goal = SelectionGoal::None;
12911                }
12912                let (cursor, goal) = movement::up(
12913                    map,
12914                    selection.start,
12915                    selection.goal,
12916                    false,
12917                    text_layout_details,
12918                );
12919                selection.collapse_to(cursor, goal);
12920            });
12921        });
12922
12923        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
12924        {
12925            cx.propagate();
12926        }
12927    }
12928
12929    pub fn move_up_by_lines(
12930        &mut self,
12931        action: &MoveUpByLines,
12932        window: &mut Window,
12933        cx: &mut Context<Self>,
12934    ) {
12935        if self.take_rename(true, window, cx).is_some() {
12936            return;
12937        }
12938
12939        if self.mode.is_single_line() {
12940            cx.propagate();
12941            return;
12942        }
12943
12944        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12945
12946        let text_layout_details = &self.text_layout_details(window);
12947
12948        self.change_selections(Default::default(), window, cx, |s| {
12949            s.move_with(|map, selection| {
12950                if !selection.is_empty() {
12951                    selection.goal = SelectionGoal::None;
12952                }
12953                let (cursor, goal) = movement::up_by_rows(
12954                    map,
12955                    selection.start,
12956                    action.lines,
12957                    selection.goal,
12958                    false,
12959                    text_layout_details,
12960                );
12961                selection.collapse_to(cursor, goal);
12962            });
12963        })
12964    }
12965
12966    pub fn move_down_by_lines(
12967        &mut self,
12968        action: &MoveDownByLines,
12969        window: &mut Window,
12970        cx: &mut Context<Self>,
12971    ) {
12972        if self.take_rename(true, window, cx).is_some() {
12973            return;
12974        }
12975
12976        if self.mode.is_single_line() {
12977            cx.propagate();
12978            return;
12979        }
12980
12981        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
12982
12983        let text_layout_details = &self.text_layout_details(window);
12984
12985        self.change_selections(Default::default(), window, cx, |s| {
12986            s.move_with(|map, selection| {
12987                if !selection.is_empty() {
12988                    selection.goal = SelectionGoal::None;
12989                }
12990                let (cursor, goal) = movement::down_by_rows(
12991                    map,
12992                    selection.start,
12993                    action.lines,
12994                    selection.goal,
12995                    false,
12996                    text_layout_details,
12997                );
12998                selection.collapse_to(cursor, goal);
12999            });
13000        })
13001    }
13002
13003    pub fn select_down_by_lines(
13004        &mut self,
13005        action: &SelectDownByLines,
13006        window: &mut Window,
13007        cx: &mut Context<Self>,
13008    ) {
13009        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13010        let text_layout_details = &self.text_layout_details(window);
13011        self.change_selections(Default::default(), window, cx, |s| {
13012            s.move_heads_with(|map, head, goal| {
13013                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13014            })
13015        })
13016    }
13017
13018    pub fn select_up_by_lines(
13019        &mut self,
13020        action: &SelectUpByLines,
13021        window: &mut Window,
13022        cx: &mut Context<Self>,
13023    ) {
13024        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13025        let text_layout_details = &self.text_layout_details(window);
13026        self.change_selections(Default::default(), window, cx, |s| {
13027            s.move_heads_with(|map, head, goal| {
13028                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13029            })
13030        })
13031    }
13032
13033    pub fn select_page_up(
13034        &mut self,
13035        _: &SelectPageUp,
13036        window: &mut Window,
13037        cx: &mut Context<Self>,
13038    ) {
13039        let Some(row_count) = self.visible_row_count() else {
13040            return;
13041        };
13042
13043        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13044
13045        let text_layout_details = &self.text_layout_details(window);
13046
13047        self.change_selections(Default::default(), window, cx, |s| {
13048            s.move_heads_with(|map, head, goal| {
13049                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13050            })
13051        })
13052    }
13053
13054    pub fn move_page_up(
13055        &mut self,
13056        action: &MovePageUp,
13057        window: &mut Window,
13058        cx: &mut Context<Self>,
13059    ) {
13060        if self.take_rename(true, window, cx).is_some() {
13061            return;
13062        }
13063
13064        if self
13065            .context_menu
13066            .borrow_mut()
13067            .as_mut()
13068            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13069            .unwrap_or(false)
13070        {
13071            return;
13072        }
13073
13074        if matches!(self.mode, EditorMode::SingleLine) {
13075            cx.propagate();
13076            return;
13077        }
13078
13079        let Some(row_count) = self.visible_row_count() else {
13080            return;
13081        };
13082
13083        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13084
13085        let effects = if action.center_cursor {
13086            SelectionEffects::scroll(Autoscroll::center())
13087        } else {
13088            SelectionEffects::default()
13089        };
13090
13091        let text_layout_details = &self.text_layout_details(window);
13092
13093        self.change_selections(effects, window, cx, |s| {
13094            s.move_with(|map, selection| {
13095                if !selection.is_empty() {
13096                    selection.goal = SelectionGoal::None;
13097                }
13098                let (cursor, goal) = movement::up_by_rows(
13099                    map,
13100                    selection.end,
13101                    row_count,
13102                    selection.goal,
13103                    false,
13104                    text_layout_details,
13105                );
13106                selection.collapse_to(cursor, goal);
13107            });
13108        });
13109    }
13110
13111    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13112        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13113        let text_layout_details = &self.text_layout_details(window);
13114        self.change_selections(Default::default(), window, cx, |s| {
13115            s.move_heads_with(|map, head, goal| {
13116                movement::up(map, head, goal, false, text_layout_details)
13117            })
13118        })
13119    }
13120
13121    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13122        self.take_rename(true, window, cx);
13123
13124        if self.mode.is_single_line() {
13125            cx.propagate();
13126            return;
13127        }
13128
13129        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13130
13131        let text_layout_details = &self.text_layout_details(window);
13132        let selection_count = self.selections.count();
13133        let first_selection = self.selections.first_anchor();
13134
13135        self.change_selections(Default::default(), window, cx, |s| {
13136            s.move_with(|map, selection| {
13137                if !selection.is_empty() {
13138                    selection.goal = SelectionGoal::None;
13139                }
13140                let (cursor, goal) = movement::down(
13141                    map,
13142                    selection.end,
13143                    selection.goal,
13144                    false,
13145                    text_layout_details,
13146                );
13147                selection.collapse_to(cursor, goal);
13148            });
13149        });
13150
13151        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13152        {
13153            cx.propagate();
13154        }
13155    }
13156
13157    pub fn select_page_down(
13158        &mut self,
13159        _: &SelectPageDown,
13160        window: &mut Window,
13161        cx: &mut Context<Self>,
13162    ) {
13163        let Some(row_count) = self.visible_row_count() else {
13164            return;
13165        };
13166
13167        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13168
13169        let text_layout_details = &self.text_layout_details(window);
13170
13171        self.change_selections(Default::default(), window, cx, |s| {
13172            s.move_heads_with(|map, head, goal| {
13173                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13174            })
13175        })
13176    }
13177
13178    pub fn move_page_down(
13179        &mut self,
13180        action: &MovePageDown,
13181        window: &mut Window,
13182        cx: &mut Context<Self>,
13183    ) {
13184        if self.take_rename(true, window, cx).is_some() {
13185            return;
13186        }
13187
13188        if self
13189            .context_menu
13190            .borrow_mut()
13191            .as_mut()
13192            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13193            .unwrap_or(false)
13194        {
13195            return;
13196        }
13197
13198        if matches!(self.mode, EditorMode::SingleLine) {
13199            cx.propagate();
13200            return;
13201        }
13202
13203        let Some(row_count) = self.visible_row_count() else {
13204            return;
13205        };
13206
13207        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13208
13209        let effects = if action.center_cursor {
13210            SelectionEffects::scroll(Autoscroll::center())
13211        } else {
13212            SelectionEffects::default()
13213        };
13214
13215        let text_layout_details = &self.text_layout_details(window);
13216        self.change_selections(effects, window, cx, |s| {
13217            s.move_with(|map, selection| {
13218                if !selection.is_empty() {
13219                    selection.goal = SelectionGoal::None;
13220                }
13221                let (cursor, goal) = movement::down_by_rows(
13222                    map,
13223                    selection.end,
13224                    row_count,
13225                    selection.goal,
13226                    false,
13227                    text_layout_details,
13228                );
13229                selection.collapse_to(cursor, goal);
13230            });
13231        });
13232    }
13233
13234    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13235        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13236        let text_layout_details = &self.text_layout_details(window);
13237        self.change_selections(Default::default(), window, cx, |s| {
13238            s.move_heads_with(|map, head, goal| {
13239                movement::down(map, head, goal, false, text_layout_details)
13240            })
13241        });
13242    }
13243
13244    pub fn context_menu_first(
13245        &mut self,
13246        _: &ContextMenuFirst,
13247        window: &mut Window,
13248        cx: &mut Context<Self>,
13249    ) {
13250        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13251            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13252        }
13253    }
13254
13255    pub fn context_menu_prev(
13256        &mut self,
13257        _: &ContextMenuPrevious,
13258        window: &mut Window,
13259        cx: &mut Context<Self>,
13260    ) {
13261        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13262            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13263        }
13264    }
13265
13266    pub fn context_menu_next(
13267        &mut self,
13268        _: &ContextMenuNext,
13269        window: &mut Window,
13270        cx: &mut Context<Self>,
13271    ) {
13272        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13273            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13274        }
13275    }
13276
13277    pub fn context_menu_last(
13278        &mut self,
13279        _: &ContextMenuLast,
13280        window: &mut Window,
13281        cx: &mut Context<Self>,
13282    ) {
13283        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13284            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13285        }
13286    }
13287
13288    pub fn signature_help_prev(
13289        &mut self,
13290        _: &SignatureHelpPrevious,
13291        _: &mut Window,
13292        cx: &mut Context<Self>,
13293    ) {
13294        if let Some(popover) = self.signature_help_state.popover_mut() {
13295            if popover.current_signature == 0 {
13296                popover.current_signature = popover.signatures.len() - 1;
13297            } else {
13298                popover.current_signature -= 1;
13299            }
13300            cx.notify();
13301        }
13302    }
13303
13304    pub fn signature_help_next(
13305        &mut self,
13306        _: &SignatureHelpNext,
13307        _: &mut Window,
13308        cx: &mut Context<Self>,
13309    ) {
13310        if let Some(popover) = self.signature_help_state.popover_mut() {
13311            if popover.current_signature + 1 == popover.signatures.len() {
13312                popover.current_signature = 0;
13313            } else {
13314                popover.current_signature += 1;
13315            }
13316            cx.notify();
13317        }
13318    }
13319
13320    pub fn move_to_previous_word_start(
13321        &mut self,
13322        _: &MoveToPreviousWordStart,
13323        window: &mut Window,
13324        cx: &mut Context<Self>,
13325    ) {
13326        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13327        self.change_selections(Default::default(), window, cx, |s| {
13328            s.move_cursors_with(|map, head, _| {
13329                (
13330                    movement::previous_word_start(map, head),
13331                    SelectionGoal::None,
13332                )
13333            });
13334        })
13335    }
13336
13337    pub fn move_to_previous_subword_start(
13338        &mut self,
13339        _: &MoveToPreviousSubwordStart,
13340        window: &mut Window,
13341        cx: &mut Context<Self>,
13342    ) {
13343        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13344        self.change_selections(Default::default(), window, cx, |s| {
13345            s.move_cursors_with(|map, head, _| {
13346                (
13347                    movement::previous_subword_start(map, head),
13348                    SelectionGoal::None,
13349                )
13350            });
13351        })
13352    }
13353
13354    pub fn select_to_previous_word_start(
13355        &mut self,
13356        _: &SelectToPreviousWordStart,
13357        window: &mut Window,
13358        cx: &mut Context<Self>,
13359    ) {
13360        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13361        self.change_selections(Default::default(), window, cx, |s| {
13362            s.move_heads_with(|map, head, _| {
13363                (
13364                    movement::previous_word_start(map, head),
13365                    SelectionGoal::None,
13366                )
13367            });
13368        })
13369    }
13370
13371    pub fn select_to_previous_subword_start(
13372        &mut self,
13373        _: &SelectToPreviousSubwordStart,
13374        window: &mut Window,
13375        cx: &mut Context<Self>,
13376    ) {
13377        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13378        self.change_selections(Default::default(), window, cx, |s| {
13379            s.move_heads_with(|map, head, _| {
13380                (
13381                    movement::previous_subword_start(map, head),
13382                    SelectionGoal::None,
13383                )
13384            });
13385        })
13386    }
13387
13388    pub fn delete_to_previous_word_start(
13389        &mut self,
13390        action: &DeleteToPreviousWordStart,
13391        window: &mut Window,
13392        cx: &mut Context<Self>,
13393    ) {
13394        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13395        self.transact(window, cx, |this, window, cx| {
13396            this.select_autoclose_pair(window, cx);
13397            this.change_selections(Default::default(), window, cx, |s| {
13398                s.move_with(|map, selection| {
13399                    if selection.is_empty() {
13400                        let mut cursor = if action.ignore_newlines {
13401                            movement::previous_word_start(map, selection.head())
13402                        } else {
13403                            movement::previous_word_start_or_newline(map, selection.head())
13404                        };
13405                        cursor = movement::adjust_greedy_deletion(
13406                            map,
13407                            selection.head(),
13408                            cursor,
13409                            action.ignore_brackets,
13410                        );
13411                        selection.set_head(cursor, SelectionGoal::None);
13412                    }
13413                });
13414            });
13415            this.insert("", window, cx);
13416        });
13417    }
13418
13419    pub fn delete_to_previous_subword_start(
13420        &mut self,
13421        _: &DeleteToPreviousSubwordStart,
13422        window: &mut Window,
13423        cx: &mut Context<Self>,
13424    ) {
13425        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13426        self.transact(window, cx, |this, window, cx| {
13427            this.select_autoclose_pair(window, cx);
13428            this.change_selections(Default::default(), window, cx, |s| {
13429                s.move_with(|map, selection| {
13430                    if selection.is_empty() {
13431                        let mut cursor = movement::previous_subword_start(map, selection.head());
13432                        cursor =
13433                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13434                        selection.set_head(cursor, SelectionGoal::None);
13435                    }
13436                });
13437            });
13438            this.insert("", window, cx);
13439        });
13440    }
13441
13442    pub fn move_to_next_word_end(
13443        &mut self,
13444        _: &MoveToNextWordEnd,
13445        window: &mut Window,
13446        cx: &mut Context<Self>,
13447    ) {
13448        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13449        self.change_selections(Default::default(), window, cx, |s| {
13450            s.move_cursors_with(|map, head, _| {
13451                (movement::next_word_end(map, head), SelectionGoal::None)
13452            });
13453        })
13454    }
13455
13456    pub fn move_to_next_subword_end(
13457        &mut self,
13458        _: &MoveToNextSubwordEnd,
13459        window: &mut Window,
13460        cx: &mut Context<Self>,
13461    ) {
13462        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13463        self.change_selections(Default::default(), window, cx, |s| {
13464            s.move_cursors_with(|map, head, _| {
13465                (movement::next_subword_end(map, head), SelectionGoal::None)
13466            });
13467        })
13468    }
13469
13470    pub fn select_to_next_word_end(
13471        &mut self,
13472        _: &SelectToNextWordEnd,
13473        window: &mut Window,
13474        cx: &mut Context<Self>,
13475    ) {
13476        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13477        self.change_selections(Default::default(), window, cx, |s| {
13478            s.move_heads_with(|map, head, _| {
13479                (movement::next_word_end(map, head), SelectionGoal::None)
13480            });
13481        })
13482    }
13483
13484    pub fn select_to_next_subword_end(
13485        &mut self,
13486        _: &SelectToNextSubwordEnd,
13487        window: &mut Window,
13488        cx: &mut Context<Self>,
13489    ) {
13490        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13491        self.change_selections(Default::default(), window, cx, |s| {
13492            s.move_heads_with(|map, head, _| {
13493                (movement::next_subword_end(map, head), SelectionGoal::None)
13494            });
13495        })
13496    }
13497
13498    pub fn delete_to_next_word_end(
13499        &mut self,
13500        action: &DeleteToNextWordEnd,
13501        window: &mut Window,
13502        cx: &mut Context<Self>,
13503    ) {
13504        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13505        self.transact(window, cx, |this, window, cx| {
13506            this.change_selections(Default::default(), window, cx, |s| {
13507                s.move_with(|map, selection| {
13508                    if selection.is_empty() {
13509                        let mut cursor = if action.ignore_newlines {
13510                            movement::next_word_end(map, selection.head())
13511                        } else {
13512                            movement::next_word_end_or_newline(map, selection.head())
13513                        };
13514                        cursor = movement::adjust_greedy_deletion(
13515                            map,
13516                            selection.head(),
13517                            cursor,
13518                            action.ignore_brackets,
13519                        );
13520                        selection.set_head(cursor, SelectionGoal::None);
13521                    }
13522                });
13523            });
13524            this.insert("", window, cx);
13525        });
13526    }
13527
13528    pub fn delete_to_next_subword_end(
13529        &mut self,
13530        _: &DeleteToNextSubwordEnd,
13531        window: &mut Window,
13532        cx: &mut Context<Self>,
13533    ) {
13534        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13535        self.transact(window, cx, |this, window, cx| {
13536            this.change_selections(Default::default(), window, cx, |s| {
13537                s.move_with(|map, selection| {
13538                    if selection.is_empty() {
13539                        let mut cursor = movement::next_subword_end(map, selection.head());
13540                        cursor =
13541                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
13542                        selection.set_head(cursor, SelectionGoal::None);
13543                    }
13544                });
13545            });
13546            this.insert("", window, cx);
13547        });
13548    }
13549
13550    pub fn move_to_beginning_of_line(
13551        &mut self,
13552        action: &MoveToBeginningOfLine,
13553        window: &mut Window,
13554        cx: &mut Context<Self>,
13555    ) {
13556        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13557        self.change_selections(Default::default(), window, cx, |s| {
13558            s.move_cursors_with(|map, head, _| {
13559                (
13560                    movement::indented_line_beginning(
13561                        map,
13562                        head,
13563                        action.stop_at_soft_wraps,
13564                        action.stop_at_indent,
13565                    ),
13566                    SelectionGoal::None,
13567                )
13568            });
13569        })
13570    }
13571
13572    pub fn select_to_beginning_of_line(
13573        &mut self,
13574        action: &SelectToBeginningOfLine,
13575        window: &mut Window,
13576        cx: &mut Context<Self>,
13577    ) {
13578        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13579        self.change_selections(Default::default(), window, cx, |s| {
13580            s.move_heads_with(|map, head, _| {
13581                (
13582                    movement::indented_line_beginning(
13583                        map,
13584                        head,
13585                        action.stop_at_soft_wraps,
13586                        action.stop_at_indent,
13587                    ),
13588                    SelectionGoal::None,
13589                )
13590            });
13591        });
13592    }
13593
13594    pub fn delete_to_beginning_of_line(
13595        &mut self,
13596        action: &DeleteToBeginningOfLine,
13597        window: &mut Window,
13598        cx: &mut Context<Self>,
13599    ) {
13600        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13601        self.transact(window, cx, |this, window, cx| {
13602            this.change_selections(Default::default(), window, cx, |s| {
13603                s.move_with(|_, selection| {
13604                    selection.reversed = true;
13605                });
13606            });
13607
13608            this.select_to_beginning_of_line(
13609                &SelectToBeginningOfLine {
13610                    stop_at_soft_wraps: false,
13611                    stop_at_indent: action.stop_at_indent,
13612                },
13613                window,
13614                cx,
13615            );
13616            this.backspace(&Backspace, window, cx);
13617        });
13618    }
13619
13620    pub fn move_to_end_of_line(
13621        &mut self,
13622        action: &MoveToEndOfLine,
13623        window: &mut Window,
13624        cx: &mut Context<Self>,
13625    ) {
13626        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13627        self.change_selections(Default::default(), window, cx, |s| {
13628            s.move_cursors_with(|map, head, _| {
13629                (
13630                    movement::line_end(map, head, action.stop_at_soft_wraps),
13631                    SelectionGoal::None,
13632                )
13633            });
13634        })
13635    }
13636
13637    pub fn select_to_end_of_line(
13638        &mut self,
13639        action: &SelectToEndOfLine,
13640        window: &mut Window,
13641        cx: &mut Context<Self>,
13642    ) {
13643        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13644        self.change_selections(Default::default(), window, cx, |s| {
13645            s.move_heads_with(|map, head, _| {
13646                (
13647                    movement::line_end(map, head, action.stop_at_soft_wraps),
13648                    SelectionGoal::None,
13649                )
13650            });
13651        })
13652    }
13653
13654    pub fn delete_to_end_of_line(
13655        &mut self,
13656        _: &DeleteToEndOfLine,
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.select_to_end_of_line(
13663                &SelectToEndOfLine {
13664                    stop_at_soft_wraps: false,
13665                },
13666                window,
13667                cx,
13668            );
13669            this.delete(&Delete, window, cx);
13670        });
13671    }
13672
13673    pub fn cut_to_end_of_line(
13674        &mut self,
13675        action: &CutToEndOfLine,
13676        window: &mut Window,
13677        cx: &mut Context<Self>,
13678    ) {
13679        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13680        self.transact(window, cx, |this, window, cx| {
13681            this.select_to_end_of_line(
13682                &SelectToEndOfLine {
13683                    stop_at_soft_wraps: false,
13684                },
13685                window,
13686                cx,
13687            );
13688            if !action.stop_at_newlines {
13689                this.change_selections(Default::default(), window, cx, |s| {
13690                    s.move_with(|_, sel| {
13691                        if sel.is_empty() {
13692                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13693                        }
13694                    });
13695                });
13696            }
13697            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13698            let item = this.cut_common(false, window, cx);
13699            cx.write_to_clipboard(item);
13700        });
13701    }
13702
13703    pub fn move_to_start_of_paragraph(
13704        &mut self,
13705        _: &MoveToStartOfParagraph,
13706        window: &mut Window,
13707        cx: &mut Context<Self>,
13708    ) {
13709        if matches!(self.mode, EditorMode::SingleLine) {
13710            cx.propagate();
13711            return;
13712        }
13713        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13714        self.change_selections(Default::default(), window, cx, |s| {
13715            s.move_with(|map, selection| {
13716                selection.collapse_to(
13717                    movement::start_of_paragraph(map, selection.head(), 1),
13718                    SelectionGoal::None,
13719                )
13720            });
13721        })
13722    }
13723
13724    pub fn move_to_end_of_paragraph(
13725        &mut self,
13726        _: &MoveToEndOfParagraph,
13727        window: &mut Window,
13728        cx: &mut Context<Self>,
13729    ) {
13730        if matches!(self.mode, EditorMode::SingleLine) {
13731            cx.propagate();
13732            return;
13733        }
13734        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13735        self.change_selections(Default::default(), window, cx, |s| {
13736            s.move_with(|map, selection| {
13737                selection.collapse_to(
13738                    movement::end_of_paragraph(map, selection.head(), 1),
13739                    SelectionGoal::None,
13740                )
13741            });
13742        })
13743    }
13744
13745    pub fn select_to_start_of_paragraph(
13746        &mut self,
13747        _: &SelectToStartOfParagraph,
13748        window: &mut Window,
13749        cx: &mut Context<Self>,
13750    ) {
13751        if matches!(self.mode, EditorMode::SingleLine) {
13752            cx.propagate();
13753            return;
13754        }
13755        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13756        self.change_selections(Default::default(), window, cx, |s| {
13757            s.move_heads_with(|map, head, _| {
13758                (
13759                    movement::start_of_paragraph(map, head, 1),
13760                    SelectionGoal::None,
13761                )
13762            });
13763        })
13764    }
13765
13766    pub fn select_to_end_of_paragraph(
13767        &mut self,
13768        _: &SelectToEndOfParagraph,
13769        window: &mut Window,
13770        cx: &mut Context<Self>,
13771    ) {
13772        if matches!(self.mode, EditorMode::SingleLine) {
13773            cx.propagate();
13774            return;
13775        }
13776        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13777        self.change_selections(Default::default(), window, cx, |s| {
13778            s.move_heads_with(|map, head, _| {
13779                (
13780                    movement::end_of_paragraph(map, head, 1),
13781                    SelectionGoal::None,
13782                )
13783            });
13784        })
13785    }
13786
13787    pub fn move_to_start_of_excerpt(
13788        &mut self,
13789        _: &MoveToStartOfExcerpt,
13790        window: &mut Window,
13791        cx: &mut Context<Self>,
13792    ) {
13793        if matches!(self.mode, EditorMode::SingleLine) {
13794            cx.propagate();
13795            return;
13796        }
13797        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13798        self.change_selections(Default::default(), window, cx, |s| {
13799            s.move_with(|map, selection| {
13800                selection.collapse_to(
13801                    movement::start_of_excerpt(
13802                        map,
13803                        selection.head(),
13804                        workspace::searchable::Direction::Prev,
13805                    ),
13806                    SelectionGoal::None,
13807                )
13808            });
13809        })
13810    }
13811
13812    pub fn move_to_start_of_next_excerpt(
13813        &mut self,
13814        _: &MoveToStartOfNextExcerpt,
13815        window: &mut Window,
13816        cx: &mut Context<Self>,
13817    ) {
13818        if matches!(self.mode, EditorMode::SingleLine) {
13819            cx.propagate();
13820            return;
13821        }
13822
13823        self.change_selections(Default::default(), window, cx, |s| {
13824            s.move_with(|map, selection| {
13825                selection.collapse_to(
13826                    movement::start_of_excerpt(
13827                        map,
13828                        selection.head(),
13829                        workspace::searchable::Direction::Next,
13830                    ),
13831                    SelectionGoal::None,
13832                )
13833            });
13834        })
13835    }
13836
13837    pub fn move_to_end_of_excerpt(
13838        &mut self,
13839        _: &MoveToEndOfExcerpt,
13840        window: &mut Window,
13841        cx: &mut Context<Self>,
13842    ) {
13843        if matches!(self.mode, EditorMode::SingleLine) {
13844            cx.propagate();
13845            return;
13846        }
13847        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13848        self.change_selections(Default::default(), window, cx, |s| {
13849            s.move_with(|map, selection| {
13850                selection.collapse_to(
13851                    movement::end_of_excerpt(
13852                        map,
13853                        selection.head(),
13854                        workspace::searchable::Direction::Next,
13855                    ),
13856                    SelectionGoal::None,
13857                )
13858            });
13859        })
13860    }
13861
13862    pub fn move_to_end_of_previous_excerpt(
13863        &mut self,
13864        _: &MoveToEndOfPreviousExcerpt,
13865        window: &mut Window,
13866        cx: &mut Context<Self>,
13867    ) {
13868        if matches!(self.mode, EditorMode::SingleLine) {
13869            cx.propagate();
13870            return;
13871        }
13872        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13873        self.change_selections(Default::default(), window, cx, |s| {
13874            s.move_with(|map, selection| {
13875                selection.collapse_to(
13876                    movement::end_of_excerpt(
13877                        map,
13878                        selection.head(),
13879                        workspace::searchable::Direction::Prev,
13880                    ),
13881                    SelectionGoal::None,
13882                )
13883            });
13884        })
13885    }
13886
13887    pub fn select_to_start_of_excerpt(
13888        &mut self,
13889        _: &SelectToStartOfExcerpt,
13890        window: &mut Window,
13891        cx: &mut Context<Self>,
13892    ) {
13893        if matches!(self.mode, EditorMode::SingleLine) {
13894            cx.propagate();
13895            return;
13896        }
13897        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13898        self.change_selections(Default::default(), window, cx, |s| {
13899            s.move_heads_with(|map, head, _| {
13900                (
13901                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13902                    SelectionGoal::None,
13903                )
13904            });
13905        })
13906    }
13907
13908    pub fn select_to_start_of_next_excerpt(
13909        &mut self,
13910        _: &SelectToStartOfNextExcerpt,
13911        window: &mut Window,
13912        cx: &mut Context<Self>,
13913    ) {
13914        if matches!(self.mode, EditorMode::SingleLine) {
13915            cx.propagate();
13916            return;
13917        }
13918        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13919        self.change_selections(Default::default(), window, cx, |s| {
13920            s.move_heads_with(|map, head, _| {
13921                (
13922                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
13923                    SelectionGoal::None,
13924                )
13925            });
13926        })
13927    }
13928
13929    pub fn select_to_end_of_excerpt(
13930        &mut self,
13931        _: &SelectToEndOfExcerpt,
13932        window: &mut Window,
13933        cx: &mut Context<Self>,
13934    ) {
13935        if matches!(self.mode, EditorMode::SingleLine) {
13936            cx.propagate();
13937            return;
13938        }
13939        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13940        self.change_selections(Default::default(), window, cx, |s| {
13941            s.move_heads_with(|map, head, _| {
13942                (
13943                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
13944                    SelectionGoal::None,
13945                )
13946            });
13947        })
13948    }
13949
13950    pub fn select_to_end_of_previous_excerpt(
13951        &mut self,
13952        _: &SelectToEndOfPreviousExcerpt,
13953        window: &mut Window,
13954        cx: &mut Context<Self>,
13955    ) {
13956        if matches!(self.mode, EditorMode::SingleLine) {
13957            cx.propagate();
13958            return;
13959        }
13960        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13961        self.change_selections(Default::default(), window, cx, |s| {
13962            s.move_heads_with(|map, head, _| {
13963                (
13964                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
13965                    SelectionGoal::None,
13966                )
13967            });
13968        })
13969    }
13970
13971    pub fn move_to_beginning(
13972        &mut self,
13973        _: &MoveToBeginning,
13974        window: &mut Window,
13975        cx: &mut Context<Self>,
13976    ) {
13977        if matches!(self.mode, EditorMode::SingleLine) {
13978            cx.propagate();
13979            return;
13980        }
13981        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13982        self.change_selections(Default::default(), window, cx, |s| {
13983            s.select_ranges(vec![0..0]);
13984        });
13985    }
13986
13987    pub fn select_to_beginning(
13988        &mut self,
13989        _: &SelectToBeginning,
13990        window: &mut Window,
13991        cx: &mut Context<Self>,
13992    ) {
13993        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
13994        selection.set_head(Point::zero(), SelectionGoal::None);
13995        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13996        self.change_selections(Default::default(), window, cx, |s| {
13997            s.select(vec![selection]);
13998        });
13999    }
14000
14001    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14002        if matches!(self.mode, EditorMode::SingleLine) {
14003            cx.propagate();
14004            return;
14005        }
14006        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14007        let cursor = self.buffer.read(cx).read(cx).len();
14008        self.change_selections(Default::default(), window, cx, |s| {
14009            s.select_ranges(vec![cursor..cursor])
14010        });
14011    }
14012
14013    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14014        self.nav_history = nav_history;
14015    }
14016
14017    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14018        self.nav_history.as_ref()
14019    }
14020
14021    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14022        self.push_to_nav_history(
14023            self.selections.newest_anchor().head(),
14024            None,
14025            false,
14026            true,
14027            cx,
14028        );
14029    }
14030
14031    fn push_to_nav_history(
14032        &mut self,
14033        cursor_anchor: Anchor,
14034        new_position: Option<Point>,
14035        is_deactivate: bool,
14036        always: bool,
14037        cx: &mut Context<Self>,
14038    ) {
14039        if let Some(nav_history) = self.nav_history.as_mut() {
14040            let buffer = self.buffer.read(cx).read(cx);
14041            let cursor_position = cursor_anchor.to_point(&buffer);
14042            let scroll_state = self.scroll_manager.anchor();
14043            let scroll_top_row = scroll_state.top_row(&buffer);
14044            drop(buffer);
14045
14046            if let Some(new_position) = new_position {
14047                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14048                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14049                    return;
14050                }
14051            }
14052
14053            nav_history.push(
14054                Some(NavigationData {
14055                    cursor_anchor,
14056                    cursor_position,
14057                    scroll_anchor: scroll_state,
14058                    scroll_top_row,
14059                }),
14060                cx,
14061            );
14062            cx.emit(EditorEvent::PushedToNavHistory {
14063                anchor: cursor_anchor,
14064                is_deactivate,
14065            })
14066        }
14067    }
14068
14069    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14070        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14071        let buffer = self.buffer.read(cx).snapshot(cx);
14072        let mut selection = self.selections.first::<usize>(&self.display_snapshot(cx));
14073        selection.set_head(buffer.len(), SelectionGoal::None);
14074        self.change_selections(Default::default(), window, cx, |s| {
14075            s.select(vec![selection]);
14076        });
14077    }
14078
14079    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14080        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14081        let end = self.buffer.read(cx).read(cx).len();
14082        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14083            s.select_ranges(vec![0..end]);
14084        });
14085    }
14086
14087    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14088        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14089        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14090        let mut selections = self.selections.all::<Point>(&display_map);
14091        let max_point = display_map.buffer_snapshot().max_point();
14092        for selection in &mut selections {
14093            let rows = selection.spanned_rows(true, &display_map);
14094            selection.start = Point::new(rows.start.0, 0);
14095            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14096            selection.reversed = false;
14097        }
14098        self.change_selections(Default::default(), window, cx, |s| {
14099            s.select(selections);
14100        });
14101    }
14102
14103    pub fn split_selection_into_lines(
14104        &mut self,
14105        action: &SplitSelectionIntoLines,
14106        window: &mut Window,
14107        cx: &mut Context<Self>,
14108    ) {
14109        let selections = self
14110            .selections
14111            .all::<Point>(&self.display_snapshot(cx))
14112            .into_iter()
14113            .map(|selection| selection.start..selection.end)
14114            .collect::<Vec<_>>();
14115        self.unfold_ranges(&selections, true, true, cx);
14116
14117        let mut new_selection_ranges = Vec::new();
14118        {
14119            let buffer = self.buffer.read(cx).read(cx);
14120            for selection in selections {
14121                for row in selection.start.row..selection.end.row {
14122                    let line_start = Point::new(row, 0);
14123                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14124
14125                    if action.keep_selections {
14126                        // Keep the selection range for each line
14127                        let selection_start = if row == selection.start.row {
14128                            selection.start
14129                        } else {
14130                            line_start
14131                        };
14132                        new_selection_ranges.push(selection_start..line_end);
14133                    } else {
14134                        // Collapse to cursor at end of line
14135                        new_selection_ranges.push(line_end..line_end);
14136                    }
14137                }
14138
14139                let is_multiline_selection = selection.start.row != selection.end.row;
14140                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14141                // so this action feels more ergonomic when paired with other selection operations
14142                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14143                if !should_skip_last {
14144                    if action.keep_selections {
14145                        if is_multiline_selection {
14146                            let line_start = Point::new(selection.end.row, 0);
14147                            new_selection_ranges.push(line_start..selection.end);
14148                        } else {
14149                            new_selection_ranges.push(selection.start..selection.end);
14150                        }
14151                    } else {
14152                        new_selection_ranges.push(selection.end..selection.end);
14153                    }
14154                }
14155            }
14156        }
14157        self.change_selections(Default::default(), window, cx, |s| {
14158            s.select_ranges(new_selection_ranges);
14159        });
14160    }
14161
14162    pub fn add_selection_above(
14163        &mut self,
14164        action: &AddSelectionAbove,
14165        window: &mut Window,
14166        cx: &mut Context<Self>,
14167    ) {
14168        self.add_selection(true, action.skip_soft_wrap, window, cx);
14169    }
14170
14171    pub fn add_selection_below(
14172        &mut self,
14173        action: &AddSelectionBelow,
14174        window: &mut Window,
14175        cx: &mut Context<Self>,
14176    ) {
14177        self.add_selection(false, action.skip_soft_wrap, window, cx);
14178    }
14179
14180    fn add_selection(
14181        &mut self,
14182        above: bool,
14183        skip_soft_wrap: bool,
14184        window: &mut Window,
14185        cx: &mut Context<Self>,
14186    ) {
14187        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14188
14189        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14190        let all_selections = self.selections.all::<Point>(&display_map);
14191        let text_layout_details = self.text_layout_details(window);
14192
14193        let (mut columnar_selections, new_selections_to_columnarize) = {
14194            if let Some(state) = self.add_selections_state.as_ref() {
14195                let columnar_selection_ids: HashSet<_> = state
14196                    .groups
14197                    .iter()
14198                    .flat_map(|group| group.stack.iter())
14199                    .copied()
14200                    .collect();
14201
14202                all_selections
14203                    .into_iter()
14204                    .partition(|s| columnar_selection_ids.contains(&s.id))
14205            } else {
14206                (Vec::new(), all_selections)
14207            }
14208        };
14209
14210        let mut state = self
14211            .add_selections_state
14212            .take()
14213            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14214
14215        for selection in new_selections_to_columnarize {
14216            let range = selection.display_range(&display_map).sorted();
14217            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14218            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14219            let positions = start_x.min(end_x)..start_x.max(end_x);
14220            let mut stack = Vec::new();
14221            for row in range.start.row().0..=range.end.row().0 {
14222                if let Some(selection) = self.selections.build_columnar_selection(
14223                    &display_map,
14224                    DisplayRow(row),
14225                    &positions,
14226                    selection.reversed,
14227                    &text_layout_details,
14228                ) {
14229                    stack.push(selection.id);
14230                    columnar_selections.push(selection);
14231                }
14232            }
14233            if !stack.is_empty() {
14234                if above {
14235                    stack.reverse();
14236                }
14237                state.groups.push(AddSelectionsGroup { above, stack });
14238            }
14239        }
14240
14241        let mut final_selections = Vec::new();
14242        let end_row = if above {
14243            DisplayRow(0)
14244        } else {
14245            display_map.max_point().row()
14246        };
14247
14248        let mut last_added_item_per_group = HashMap::default();
14249        for group in state.groups.iter_mut() {
14250            if let Some(last_id) = group.stack.last() {
14251                last_added_item_per_group.insert(*last_id, group);
14252            }
14253        }
14254
14255        for selection in columnar_selections {
14256            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14257                if above == group.above {
14258                    let range = selection.display_range(&display_map).sorted();
14259                    debug_assert_eq!(range.start.row(), range.end.row());
14260                    let mut row = range.start.row();
14261                    let positions =
14262                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14263                            Pixels::from(start)..Pixels::from(end)
14264                        } else {
14265                            let start_x =
14266                                display_map.x_for_display_point(range.start, &text_layout_details);
14267                            let end_x =
14268                                display_map.x_for_display_point(range.end, &text_layout_details);
14269                            start_x.min(end_x)..start_x.max(end_x)
14270                        };
14271
14272                    let mut maybe_new_selection = None;
14273                    let direction = if above { -1 } else { 1 };
14274
14275                    while row != end_row {
14276                        if skip_soft_wrap {
14277                            row = display_map
14278                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14279                                .row();
14280                        } else if above {
14281                            row.0 -= 1;
14282                        } else {
14283                            row.0 += 1;
14284                        }
14285
14286                        if let Some(new_selection) = self.selections.build_columnar_selection(
14287                            &display_map,
14288                            row,
14289                            &positions,
14290                            selection.reversed,
14291                            &text_layout_details,
14292                        ) {
14293                            maybe_new_selection = Some(new_selection);
14294                            break;
14295                        }
14296                    }
14297
14298                    if let Some(new_selection) = maybe_new_selection {
14299                        group.stack.push(new_selection.id);
14300                        if above {
14301                            final_selections.push(new_selection);
14302                            final_selections.push(selection);
14303                        } else {
14304                            final_selections.push(selection);
14305                            final_selections.push(new_selection);
14306                        }
14307                    } else {
14308                        final_selections.push(selection);
14309                    }
14310                } else {
14311                    group.stack.pop();
14312                }
14313            } else {
14314                final_selections.push(selection);
14315            }
14316        }
14317
14318        self.change_selections(Default::default(), window, cx, |s| {
14319            s.select(final_selections);
14320        });
14321
14322        let final_selection_ids: HashSet<_> = self
14323            .selections
14324            .all::<Point>(&display_map)
14325            .iter()
14326            .map(|s| s.id)
14327            .collect();
14328        state.groups.retain_mut(|group| {
14329            // selections might get merged above so we remove invalid items from stacks
14330            group.stack.retain(|id| final_selection_ids.contains(id));
14331
14332            // single selection in stack can be treated as initial state
14333            group.stack.len() > 1
14334        });
14335
14336        if !state.groups.is_empty() {
14337            self.add_selections_state = Some(state);
14338        }
14339    }
14340
14341    fn select_match_ranges(
14342        &mut self,
14343        range: Range<usize>,
14344        reversed: bool,
14345        replace_newest: bool,
14346        auto_scroll: Option<Autoscroll>,
14347        window: &mut Window,
14348        cx: &mut Context<Editor>,
14349    ) {
14350        self.unfold_ranges(
14351            std::slice::from_ref(&range),
14352            false,
14353            auto_scroll.is_some(),
14354            cx,
14355        );
14356        let effects = if let Some(scroll) = auto_scroll {
14357            SelectionEffects::scroll(scroll)
14358        } else {
14359            SelectionEffects::no_scroll()
14360        };
14361        self.change_selections(effects, window, cx, |s| {
14362            if replace_newest {
14363                s.delete(s.newest_anchor().id);
14364            }
14365            if reversed {
14366                s.insert_range(range.end..range.start);
14367            } else {
14368                s.insert_range(range);
14369            }
14370        });
14371    }
14372
14373    pub fn select_next_match_internal(
14374        &mut self,
14375        display_map: &DisplaySnapshot,
14376        replace_newest: bool,
14377        autoscroll: Option<Autoscroll>,
14378        window: &mut Window,
14379        cx: &mut Context<Self>,
14380    ) -> Result<()> {
14381        let buffer = display_map.buffer_snapshot();
14382        let mut selections = self.selections.all::<usize>(&display_map);
14383        if let Some(mut select_next_state) = self.select_next_state.take() {
14384            let query = &select_next_state.query;
14385            if !select_next_state.done {
14386                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14387                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14388                let mut next_selected_range = None;
14389
14390                let bytes_after_last_selection =
14391                    buffer.bytes_in_range(last_selection.end..buffer.len());
14392                let bytes_before_first_selection = buffer.bytes_in_range(0..first_selection.start);
14393                let query_matches = query
14394                    .stream_find_iter(bytes_after_last_selection)
14395                    .map(|result| (last_selection.end, result))
14396                    .chain(
14397                        query
14398                            .stream_find_iter(bytes_before_first_selection)
14399                            .map(|result| (0, result)),
14400                    );
14401
14402                for (start_offset, query_match) in query_matches {
14403                    let query_match = query_match.unwrap(); // can only fail due to I/O
14404                    let offset_range =
14405                        start_offset + query_match.start()..start_offset + query_match.end();
14406
14407                    if !select_next_state.wordwise
14408                        || (!buffer.is_inside_word(offset_range.start, None)
14409                            && !buffer.is_inside_word(offset_range.end, None))
14410                    {
14411                        let idx = selections
14412                            .partition_point(|selection| selection.end <= offset_range.start);
14413                        let overlaps = selections
14414                            .get(idx)
14415                            .map_or(false, |selection| selection.start < offset_range.end);
14416
14417                        if !overlaps {
14418                            next_selected_range = Some(offset_range);
14419                            break;
14420                        }
14421                    }
14422                }
14423
14424                if let Some(next_selected_range) = next_selected_range {
14425                    self.select_match_ranges(
14426                        next_selected_range,
14427                        last_selection.reversed,
14428                        replace_newest,
14429                        autoscroll,
14430                        window,
14431                        cx,
14432                    );
14433                } else {
14434                    select_next_state.done = true;
14435                }
14436            }
14437
14438            self.select_next_state = Some(select_next_state);
14439        } else {
14440            let mut only_carets = true;
14441            let mut same_text_selected = true;
14442            let mut selected_text = None;
14443
14444            let mut selections_iter = selections.iter().peekable();
14445            while let Some(selection) = selections_iter.next() {
14446                if selection.start != selection.end {
14447                    only_carets = false;
14448                }
14449
14450                if same_text_selected {
14451                    if selected_text.is_none() {
14452                        selected_text =
14453                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14454                    }
14455
14456                    if let Some(next_selection) = selections_iter.peek() {
14457                        if next_selection.range().len() == selection.range().len() {
14458                            let next_selected_text = buffer
14459                                .text_for_range(next_selection.range())
14460                                .collect::<String>();
14461                            if Some(next_selected_text) != selected_text {
14462                                same_text_selected = false;
14463                                selected_text = None;
14464                            }
14465                        } else {
14466                            same_text_selected = false;
14467                            selected_text = None;
14468                        }
14469                    }
14470                }
14471            }
14472
14473            if only_carets {
14474                for selection in &mut selections {
14475                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14476                    selection.start = word_range.start;
14477                    selection.end = word_range.end;
14478                    selection.goal = SelectionGoal::None;
14479                    selection.reversed = false;
14480                    self.select_match_ranges(
14481                        selection.start..selection.end,
14482                        selection.reversed,
14483                        replace_newest,
14484                        autoscroll,
14485                        window,
14486                        cx,
14487                    );
14488                }
14489
14490                if selections.len() == 1 {
14491                    let selection = selections
14492                        .last()
14493                        .expect("ensured that there's only one selection");
14494                    let query = buffer
14495                        .text_for_range(selection.start..selection.end)
14496                        .collect::<String>();
14497                    let is_empty = query.is_empty();
14498                    let select_state = SelectNextState {
14499                        query: AhoCorasick::new(&[query])?,
14500                        wordwise: true,
14501                        done: is_empty,
14502                    };
14503                    self.select_next_state = Some(select_state);
14504                } else {
14505                    self.select_next_state = None;
14506                }
14507            } else if let Some(selected_text) = selected_text {
14508                self.select_next_state = Some(SelectNextState {
14509                    query: AhoCorasick::new(&[selected_text])?,
14510                    wordwise: false,
14511                    done: false,
14512                });
14513                self.select_next_match_internal(
14514                    display_map,
14515                    replace_newest,
14516                    autoscroll,
14517                    window,
14518                    cx,
14519                )?;
14520            }
14521        }
14522        Ok(())
14523    }
14524
14525    pub fn select_all_matches(
14526        &mut self,
14527        _action: &SelectAllMatches,
14528        window: &mut Window,
14529        cx: &mut Context<Self>,
14530    ) -> Result<()> {
14531        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14532
14533        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14534
14535        self.select_next_match_internal(&display_map, false, None, window, cx)?;
14536        let Some(select_next_state) = self.select_next_state.as_mut() else {
14537            return Ok(());
14538        };
14539        if select_next_state.done {
14540            return Ok(());
14541        }
14542
14543        let mut new_selections = Vec::new();
14544
14545        let reversed = self.selections.oldest::<usize>(&display_map).reversed;
14546        let buffer = display_map.buffer_snapshot();
14547        let query_matches = select_next_state
14548            .query
14549            .stream_find_iter(buffer.bytes_in_range(0..buffer.len()));
14550
14551        for query_match in query_matches.into_iter() {
14552            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
14553            let offset_range = if reversed {
14554                query_match.end()..query_match.start()
14555            } else {
14556                query_match.start()..query_match.end()
14557            };
14558
14559            if !select_next_state.wordwise
14560                || (!buffer.is_inside_word(offset_range.start, None)
14561                    && !buffer.is_inside_word(offset_range.end, None))
14562            {
14563                new_selections.push(offset_range.start..offset_range.end);
14564            }
14565        }
14566
14567        select_next_state.done = true;
14568
14569        if new_selections.is_empty() {
14570            log::error!("bug: new_selections is empty in select_all_matches");
14571            return Ok(());
14572        }
14573
14574        self.unfold_ranges(&new_selections.clone(), false, false, cx);
14575        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
14576            selections.select_ranges(new_selections)
14577        });
14578
14579        Ok(())
14580    }
14581
14582    pub fn select_next(
14583        &mut self,
14584        action: &SelectNext,
14585        window: &mut Window,
14586        cx: &mut Context<Self>,
14587    ) -> Result<()> {
14588        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14589        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14590        self.select_next_match_internal(
14591            &display_map,
14592            action.replace_newest,
14593            Some(Autoscroll::newest()),
14594            window,
14595            cx,
14596        )?;
14597        Ok(())
14598    }
14599
14600    pub fn select_previous(
14601        &mut self,
14602        action: &SelectPrevious,
14603        window: &mut Window,
14604        cx: &mut Context<Self>,
14605    ) -> Result<()> {
14606        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14607        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14608        let buffer = display_map.buffer_snapshot();
14609        let mut selections = self.selections.all::<usize>(&display_map);
14610        if let Some(mut select_prev_state) = self.select_prev_state.take() {
14611            let query = &select_prev_state.query;
14612            if !select_prev_state.done {
14613                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
14614                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
14615                let mut next_selected_range = None;
14616                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
14617                let bytes_before_last_selection =
14618                    buffer.reversed_bytes_in_range(0..last_selection.start);
14619                let bytes_after_first_selection =
14620                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
14621                let query_matches = query
14622                    .stream_find_iter(bytes_before_last_selection)
14623                    .map(|result| (last_selection.start, result))
14624                    .chain(
14625                        query
14626                            .stream_find_iter(bytes_after_first_selection)
14627                            .map(|result| (buffer.len(), result)),
14628                    );
14629                for (end_offset, query_match) in query_matches {
14630                    let query_match = query_match.unwrap(); // can only fail due to I/O
14631                    let offset_range =
14632                        end_offset - query_match.end()..end_offset - query_match.start();
14633
14634                    if !select_prev_state.wordwise
14635                        || (!buffer.is_inside_word(offset_range.start, None)
14636                            && !buffer.is_inside_word(offset_range.end, None))
14637                    {
14638                        next_selected_range = Some(offset_range);
14639                        break;
14640                    }
14641                }
14642
14643                if let Some(next_selected_range) = next_selected_range {
14644                    self.select_match_ranges(
14645                        next_selected_range,
14646                        last_selection.reversed,
14647                        action.replace_newest,
14648                        Some(Autoscroll::newest()),
14649                        window,
14650                        cx,
14651                    );
14652                } else {
14653                    select_prev_state.done = true;
14654                }
14655            }
14656
14657            self.select_prev_state = Some(select_prev_state);
14658        } else {
14659            let mut only_carets = true;
14660            let mut same_text_selected = true;
14661            let mut selected_text = None;
14662
14663            let mut selections_iter = selections.iter().peekable();
14664            while let Some(selection) = selections_iter.next() {
14665                if selection.start != selection.end {
14666                    only_carets = false;
14667                }
14668
14669                if same_text_selected {
14670                    if selected_text.is_none() {
14671                        selected_text =
14672                            Some(buffer.text_for_range(selection.range()).collect::<String>());
14673                    }
14674
14675                    if let Some(next_selection) = selections_iter.peek() {
14676                        if next_selection.range().len() == selection.range().len() {
14677                            let next_selected_text = buffer
14678                                .text_for_range(next_selection.range())
14679                                .collect::<String>();
14680                            if Some(next_selected_text) != selected_text {
14681                                same_text_selected = false;
14682                                selected_text = None;
14683                            }
14684                        } else {
14685                            same_text_selected = false;
14686                            selected_text = None;
14687                        }
14688                    }
14689                }
14690            }
14691
14692            if only_carets {
14693                for selection in &mut selections {
14694                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
14695                    selection.start = word_range.start;
14696                    selection.end = word_range.end;
14697                    selection.goal = SelectionGoal::None;
14698                    selection.reversed = false;
14699                    self.select_match_ranges(
14700                        selection.start..selection.end,
14701                        selection.reversed,
14702                        action.replace_newest,
14703                        Some(Autoscroll::newest()),
14704                        window,
14705                        cx,
14706                    );
14707                }
14708                if selections.len() == 1 {
14709                    let selection = selections
14710                        .last()
14711                        .expect("ensured that there's only one selection");
14712                    let query = buffer
14713                        .text_for_range(selection.start..selection.end)
14714                        .collect::<String>();
14715                    let is_empty = query.is_empty();
14716                    let select_state = SelectNextState {
14717                        query: AhoCorasick::new(&[query.chars().rev().collect::<String>()])?,
14718                        wordwise: true,
14719                        done: is_empty,
14720                    };
14721                    self.select_prev_state = Some(select_state);
14722                } else {
14723                    self.select_prev_state = None;
14724                }
14725            } else if let Some(selected_text) = selected_text {
14726                self.select_prev_state = Some(SelectNextState {
14727                    query: AhoCorasick::new(&[selected_text.chars().rev().collect::<String>()])?,
14728                    wordwise: false,
14729                    done: false,
14730                });
14731                self.select_previous(action, window, cx)?;
14732            }
14733        }
14734        Ok(())
14735    }
14736
14737    pub fn find_next_match(
14738        &mut self,
14739        _: &FindNextMatch,
14740        window: &mut Window,
14741        cx: &mut Context<Self>,
14742    ) -> Result<()> {
14743        let selections = self.selections.disjoint_anchors_arc();
14744        match selections.first() {
14745            Some(first) if selections.len() >= 2 => {
14746                self.change_selections(Default::default(), window, cx, |s| {
14747                    s.select_ranges([first.range()]);
14748                });
14749            }
14750            _ => self.select_next(
14751                &SelectNext {
14752                    replace_newest: true,
14753                },
14754                window,
14755                cx,
14756            )?,
14757        }
14758        Ok(())
14759    }
14760
14761    pub fn find_previous_match(
14762        &mut self,
14763        _: &FindPreviousMatch,
14764        window: &mut Window,
14765        cx: &mut Context<Self>,
14766    ) -> Result<()> {
14767        let selections = self.selections.disjoint_anchors_arc();
14768        match selections.last() {
14769            Some(last) if selections.len() >= 2 => {
14770                self.change_selections(Default::default(), window, cx, |s| {
14771                    s.select_ranges([last.range()]);
14772                });
14773            }
14774            _ => self.select_previous(
14775                &SelectPrevious {
14776                    replace_newest: true,
14777                },
14778                window,
14779                cx,
14780            )?,
14781        }
14782        Ok(())
14783    }
14784
14785    pub fn toggle_comments(
14786        &mut self,
14787        action: &ToggleComments,
14788        window: &mut Window,
14789        cx: &mut Context<Self>,
14790    ) {
14791        if self.read_only(cx) {
14792            return;
14793        }
14794        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14795        let text_layout_details = &self.text_layout_details(window);
14796        self.transact(window, cx, |this, window, cx| {
14797            let mut selections = this
14798                .selections
14799                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
14800            let mut edits = Vec::new();
14801            let mut selection_edit_ranges = Vec::new();
14802            let mut last_toggled_row = None;
14803            let snapshot = this.buffer.read(cx).read(cx);
14804            let empty_str: Arc<str> = Arc::default();
14805            let mut suffixes_inserted = Vec::new();
14806            let ignore_indent = action.ignore_indent;
14807
14808            fn comment_prefix_range(
14809                snapshot: &MultiBufferSnapshot,
14810                row: MultiBufferRow,
14811                comment_prefix: &str,
14812                comment_prefix_whitespace: &str,
14813                ignore_indent: bool,
14814            ) -> Range<Point> {
14815                let indent_size = if ignore_indent {
14816                    0
14817                } else {
14818                    snapshot.indent_size_for_line(row).len
14819                };
14820
14821                let start = Point::new(row.0, indent_size);
14822
14823                let mut line_bytes = snapshot
14824                    .bytes_in_range(start..snapshot.max_point())
14825                    .flatten()
14826                    .copied();
14827
14828                // If this line currently begins with the line comment prefix, then record
14829                // the range containing the prefix.
14830                if line_bytes
14831                    .by_ref()
14832                    .take(comment_prefix.len())
14833                    .eq(comment_prefix.bytes())
14834                {
14835                    // Include any whitespace that matches the comment prefix.
14836                    let matching_whitespace_len = line_bytes
14837                        .zip(comment_prefix_whitespace.bytes())
14838                        .take_while(|(a, b)| a == b)
14839                        .count() as u32;
14840                    let end = Point::new(
14841                        start.row,
14842                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
14843                    );
14844                    start..end
14845                } else {
14846                    start..start
14847                }
14848            }
14849
14850            fn comment_suffix_range(
14851                snapshot: &MultiBufferSnapshot,
14852                row: MultiBufferRow,
14853                comment_suffix: &str,
14854                comment_suffix_has_leading_space: bool,
14855            ) -> Range<Point> {
14856                let end = Point::new(row.0, snapshot.line_len(row));
14857                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
14858
14859                let mut line_end_bytes = snapshot
14860                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
14861                    .flatten()
14862                    .copied();
14863
14864                let leading_space_len = if suffix_start_column > 0
14865                    && line_end_bytes.next() == Some(b' ')
14866                    && comment_suffix_has_leading_space
14867                {
14868                    1
14869                } else {
14870                    0
14871                };
14872
14873                // If this line currently begins with the line comment prefix, then record
14874                // the range containing the prefix.
14875                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
14876                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
14877                    start..end
14878                } else {
14879                    end..end
14880                }
14881            }
14882
14883            // TODO: Handle selections that cross excerpts
14884            for selection in &mut selections {
14885                let start_column = snapshot
14886                    .indent_size_for_line(MultiBufferRow(selection.start.row))
14887                    .len;
14888                let language = if let Some(language) =
14889                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
14890                {
14891                    language
14892                } else {
14893                    continue;
14894                };
14895
14896                selection_edit_ranges.clear();
14897
14898                // If multiple selections contain a given row, avoid processing that
14899                // row more than once.
14900                let mut start_row = MultiBufferRow(selection.start.row);
14901                if last_toggled_row == Some(start_row) {
14902                    start_row = start_row.next_row();
14903                }
14904                let end_row =
14905                    if selection.end.row > selection.start.row && selection.end.column == 0 {
14906                        MultiBufferRow(selection.end.row - 1)
14907                    } else {
14908                        MultiBufferRow(selection.end.row)
14909                    };
14910                last_toggled_row = Some(end_row);
14911
14912                if start_row > end_row {
14913                    continue;
14914                }
14915
14916                // If the language has line comments, toggle those.
14917                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
14918
14919                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
14920                if ignore_indent {
14921                    full_comment_prefixes = full_comment_prefixes
14922                        .into_iter()
14923                        .map(|s| Arc::from(s.trim_end()))
14924                        .collect();
14925                }
14926
14927                if !full_comment_prefixes.is_empty() {
14928                    let first_prefix = full_comment_prefixes
14929                        .first()
14930                        .expect("prefixes is non-empty");
14931                    let prefix_trimmed_lengths = full_comment_prefixes
14932                        .iter()
14933                        .map(|p| p.trim_end_matches(' ').len())
14934                        .collect::<SmallVec<[usize; 4]>>();
14935
14936                    let mut all_selection_lines_are_comments = true;
14937
14938                    for row in start_row.0..=end_row.0 {
14939                        let row = MultiBufferRow(row);
14940                        if start_row < end_row && snapshot.is_line_blank(row) {
14941                            continue;
14942                        }
14943
14944                        let prefix_range = full_comment_prefixes
14945                            .iter()
14946                            .zip(prefix_trimmed_lengths.iter().copied())
14947                            .map(|(prefix, trimmed_prefix_len)| {
14948                                comment_prefix_range(
14949                                    snapshot.deref(),
14950                                    row,
14951                                    &prefix[..trimmed_prefix_len],
14952                                    &prefix[trimmed_prefix_len..],
14953                                    ignore_indent,
14954                                )
14955                            })
14956                            .max_by_key(|range| range.end.column - range.start.column)
14957                            .expect("prefixes is non-empty");
14958
14959                        if prefix_range.is_empty() {
14960                            all_selection_lines_are_comments = false;
14961                        }
14962
14963                        selection_edit_ranges.push(prefix_range);
14964                    }
14965
14966                    if all_selection_lines_are_comments {
14967                        edits.extend(
14968                            selection_edit_ranges
14969                                .iter()
14970                                .cloned()
14971                                .map(|range| (range, empty_str.clone())),
14972                        );
14973                    } else {
14974                        let min_column = selection_edit_ranges
14975                            .iter()
14976                            .map(|range| range.start.column)
14977                            .min()
14978                            .unwrap_or(0);
14979                        edits.extend(selection_edit_ranges.iter().map(|range| {
14980                            let position = Point::new(range.start.row, min_column);
14981                            (position..position, first_prefix.clone())
14982                        }));
14983                    }
14984                } else if let Some(BlockCommentConfig {
14985                    start: full_comment_prefix,
14986                    end: comment_suffix,
14987                    ..
14988                }) = language.block_comment()
14989                {
14990                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
14991                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
14992                    let prefix_range = comment_prefix_range(
14993                        snapshot.deref(),
14994                        start_row,
14995                        comment_prefix,
14996                        comment_prefix_whitespace,
14997                        ignore_indent,
14998                    );
14999                    let suffix_range = comment_suffix_range(
15000                        snapshot.deref(),
15001                        end_row,
15002                        comment_suffix.trim_start_matches(' '),
15003                        comment_suffix.starts_with(' '),
15004                    );
15005
15006                    if prefix_range.is_empty() || suffix_range.is_empty() {
15007                        edits.push((
15008                            prefix_range.start..prefix_range.start,
15009                            full_comment_prefix.clone(),
15010                        ));
15011                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15012                        suffixes_inserted.push((end_row, comment_suffix.len()));
15013                    } else {
15014                        edits.push((prefix_range, empty_str.clone()));
15015                        edits.push((suffix_range, empty_str.clone()));
15016                    }
15017                } else {
15018                    continue;
15019                }
15020            }
15021
15022            drop(snapshot);
15023            this.buffer.update(cx, |buffer, cx| {
15024                buffer.edit(edits, None, cx);
15025            });
15026
15027            // Adjust selections so that they end before any comment suffixes that
15028            // were inserted.
15029            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15030            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15031            let snapshot = this.buffer.read(cx).read(cx);
15032            for selection in &mut selections {
15033                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15034                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15035                        Ordering::Less => {
15036                            suffixes_inserted.next();
15037                            continue;
15038                        }
15039                        Ordering::Greater => break,
15040                        Ordering::Equal => {
15041                            if selection.end.column == snapshot.line_len(row) {
15042                                if selection.is_empty() {
15043                                    selection.start.column -= suffix_len as u32;
15044                                }
15045                                selection.end.column -= suffix_len as u32;
15046                            }
15047                            break;
15048                        }
15049                    }
15050                }
15051            }
15052
15053            drop(snapshot);
15054            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15055
15056            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15057            let selections_on_single_row = selections.windows(2).all(|selections| {
15058                selections[0].start.row == selections[1].start.row
15059                    && selections[0].end.row == selections[1].end.row
15060                    && selections[0].start.row == selections[0].end.row
15061            });
15062            let selections_selecting = selections
15063                .iter()
15064                .any(|selection| selection.start != selection.end);
15065            let advance_downwards = action.advance_downwards
15066                && selections_on_single_row
15067                && !selections_selecting
15068                && !matches!(this.mode, EditorMode::SingleLine);
15069
15070            if advance_downwards {
15071                let snapshot = this.buffer.read(cx).snapshot(cx);
15072
15073                this.change_selections(Default::default(), window, cx, |s| {
15074                    s.move_cursors_with(|display_snapshot, display_point, _| {
15075                        let mut point = display_point.to_point(display_snapshot);
15076                        point.row += 1;
15077                        point = snapshot.clip_point(point, Bias::Left);
15078                        let display_point = point.to_display_point(display_snapshot);
15079                        let goal = SelectionGoal::HorizontalPosition(
15080                            display_snapshot
15081                                .x_for_display_point(display_point, text_layout_details)
15082                                .into(),
15083                        );
15084                        (display_point, goal)
15085                    })
15086                });
15087            }
15088        });
15089    }
15090
15091    pub fn select_enclosing_symbol(
15092        &mut self,
15093        _: &SelectEnclosingSymbol,
15094        window: &mut Window,
15095        cx: &mut Context<Self>,
15096    ) {
15097        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15098
15099        let buffer = self.buffer.read(cx).snapshot(cx);
15100        let old_selections = self
15101            .selections
15102            .all::<usize>(&self.display_snapshot(cx))
15103            .into_boxed_slice();
15104
15105        fn update_selection(
15106            selection: &Selection<usize>,
15107            buffer_snap: &MultiBufferSnapshot,
15108        ) -> Option<Selection<usize>> {
15109            let cursor = selection.head();
15110            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15111            for symbol in symbols.iter().rev() {
15112                let start = symbol.range.start.to_offset(buffer_snap);
15113                let end = symbol.range.end.to_offset(buffer_snap);
15114                let new_range = start..end;
15115                if start < selection.start || end > selection.end {
15116                    return Some(Selection {
15117                        id: selection.id,
15118                        start: new_range.start,
15119                        end: new_range.end,
15120                        goal: SelectionGoal::None,
15121                        reversed: selection.reversed,
15122                    });
15123                }
15124            }
15125            None
15126        }
15127
15128        let mut selected_larger_symbol = false;
15129        let new_selections = old_selections
15130            .iter()
15131            .map(|selection| match update_selection(selection, &buffer) {
15132                Some(new_selection) => {
15133                    if new_selection.range() != selection.range() {
15134                        selected_larger_symbol = true;
15135                    }
15136                    new_selection
15137                }
15138                None => selection.clone(),
15139            })
15140            .collect::<Vec<_>>();
15141
15142        if selected_larger_symbol {
15143            self.change_selections(Default::default(), window, cx, |s| {
15144                s.select(new_selections);
15145            });
15146        }
15147    }
15148
15149    pub fn select_larger_syntax_node(
15150        &mut self,
15151        _: &SelectLargerSyntaxNode,
15152        window: &mut Window,
15153        cx: &mut Context<Self>,
15154    ) {
15155        let Some(visible_row_count) = self.visible_row_count() else {
15156            return;
15157        };
15158        let old_selections: Box<[_]> = self
15159            .selections
15160            .all::<usize>(&self.display_snapshot(cx))
15161            .into();
15162        if old_selections.is_empty() {
15163            return;
15164        }
15165
15166        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15167
15168        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15169        let buffer = self.buffer.read(cx).snapshot(cx);
15170
15171        let mut selected_larger_node = false;
15172        let mut new_selections = old_selections
15173            .iter()
15174            .map(|selection| {
15175                let old_range = selection.start..selection.end;
15176
15177                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15178                    // manually select word at selection
15179                    if ["string_content", "inline"].contains(&node.kind()) {
15180                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15181                        // ignore if word is already selected
15182                        if !word_range.is_empty() && old_range != word_range {
15183                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15184                            // only select word if start and end point belongs to same word
15185                            if word_range == last_word_range {
15186                                selected_larger_node = true;
15187                                return Selection {
15188                                    id: selection.id,
15189                                    start: word_range.start,
15190                                    end: word_range.end,
15191                                    goal: SelectionGoal::None,
15192                                    reversed: selection.reversed,
15193                                };
15194                            }
15195                        }
15196                    }
15197                }
15198
15199                let mut new_range = old_range.clone();
15200                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15201                    new_range = range;
15202                    if !node.is_named() {
15203                        continue;
15204                    }
15205                    if !display_map.intersects_fold(new_range.start)
15206                        && !display_map.intersects_fold(new_range.end)
15207                    {
15208                        break;
15209                    }
15210                }
15211
15212                selected_larger_node |= new_range != old_range;
15213                Selection {
15214                    id: selection.id,
15215                    start: new_range.start,
15216                    end: new_range.end,
15217                    goal: SelectionGoal::None,
15218                    reversed: selection.reversed,
15219                }
15220            })
15221            .collect::<Vec<_>>();
15222
15223        if !selected_larger_node {
15224            return; // don't put this call in the history
15225        }
15226
15227        // scroll based on transformation done to the last selection created by the user
15228        let (last_old, last_new) = old_selections
15229            .last()
15230            .zip(new_selections.last().cloned())
15231            .expect("old_selections isn't empty");
15232
15233        // revert selection
15234        let is_selection_reversed = {
15235            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15236            new_selections.last_mut().expect("checked above").reversed =
15237                should_newest_selection_be_reversed;
15238            should_newest_selection_be_reversed
15239        };
15240
15241        if selected_larger_node {
15242            self.select_syntax_node_history.disable_clearing = true;
15243            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15244                s.select(new_selections.clone());
15245            });
15246            self.select_syntax_node_history.disable_clearing = false;
15247        }
15248
15249        let start_row = last_new.start.to_display_point(&display_map).row().0;
15250        let end_row = last_new.end.to_display_point(&display_map).row().0;
15251        let selection_height = end_row - start_row + 1;
15252        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
15253
15254        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
15255        let scroll_behavior = if fits_on_the_screen {
15256            self.request_autoscroll(Autoscroll::fit(), cx);
15257            SelectSyntaxNodeScrollBehavior::FitSelection
15258        } else if is_selection_reversed {
15259            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15260            SelectSyntaxNodeScrollBehavior::CursorTop
15261        } else {
15262            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15263            SelectSyntaxNodeScrollBehavior::CursorBottom
15264        };
15265
15266        self.select_syntax_node_history.push((
15267            old_selections,
15268            scroll_behavior,
15269            is_selection_reversed,
15270        ));
15271    }
15272
15273    pub fn select_smaller_syntax_node(
15274        &mut self,
15275        _: &SelectSmallerSyntaxNode,
15276        window: &mut Window,
15277        cx: &mut Context<Self>,
15278    ) {
15279        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15280
15281        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
15282            self.select_syntax_node_history.pop()
15283        {
15284            if let Some(selection) = selections.last_mut() {
15285                selection.reversed = is_selection_reversed;
15286            }
15287
15288            self.select_syntax_node_history.disable_clearing = true;
15289            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15290                s.select(selections.to_vec());
15291            });
15292            self.select_syntax_node_history.disable_clearing = false;
15293
15294            match scroll_behavior {
15295                SelectSyntaxNodeScrollBehavior::CursorTop => {
15296                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
15297                }
15298                SelectSyntaxNodeScrollBehavior::FitSelection => {
15299                    self.request_autoscroll(Autoscroll::fit(), cx);
15300                }
15301                SelectSyntaxNodeScrollBehavior::CursorBottom => {
15302                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
15303                }
15304            }
15305        }
15306    }
15307
15308    pub fn unwrap_syntax_node(
15309        &mut self,
15310        _: &UnwrapSyntaxNode,
15311        window: &mut Window,
15312        cx: &mut Context<Self>,
15313    ) {
15314        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15315
15316        let buffer = self.buffer.read(cx).snapshot(cx);
15317        let selections = self
15318            .selections
15319            .all::<usize>(&self.display_snapshot(cx))
15320            .into_iter()
15321            // subtracting the offset requires sorting
15322            .sorted_by_key(|i| i.start);
15323
15324        let full_edits = selections
15325            .into_iter()
15326            .filter_map(|selection| {
15327                let child = if selection.is_empty()
15328                    && let Some((_, ancestor_range)) =
15329                        buffer.syntax_ancestor(selection.start..selection.end)
15330                {
15331                    ancestor_range
15332                } else {
15333                    selection.range()
15334                };
15335
15336                let mut parent = child.clone();
15337                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
15338                    parent = ancestor_range;
15339                    if parent.start < child.start || parent.end > child.end {
15340                        break;
15341                    }
15342                }
15343
15344                if parent == child {
15345                    return None;
15346                }
15347                let text = buffer.text_for_range(child).collect::<String>();
15348                Some((selection.id, parent, text))
15349            })
15350            .collect::<Vec<_>>();
15351        if full_edits.is_empty() {
15352            return;
15353        }
15354
15355        self.transact(window, cx, |this, window, cx| {
15356            this.buffer.update(cx, |buffer, cx| {
15357                buffer.edit(
15358                    full_edits
15359                        .iter()
15360                        .map(|(_, p, t)| (p.clone(), t.clone()))
15361                        .collect::<Vec<_>>(),
15362                    None,
15363                    cx,
15364                );
15365            });
15366            this.change_selections(Default::default(), window, cx, |s| {
15367                let mut offset = 0;
15368                let mut selections = vec![];
15369                for (id, parent, text) in full_edits {
15370                    let start = parent.start - offset;
15371                    offset += parent.len() - text.len();
15372                    selections.push(Selection {
15373                        id,
15374                        start,
15375                        end: start + text.len(),
15376                        reversed: false,
15377                        goal: Default::default(),
15378                    });
15379                }
15380                s.select(selections);
15381            });
15382        });
15383    }
15384
15385    pub fn select_next_syntax_node(
15386        &mut self,
15387        _: &SelectNextSyntaxNode,
15388        window: &mut Window,
15389        cx: &mut Context<Self>,
15390    ) {
15391        let old_selections: Box<[_]> = self
15392            .selections
15393            .all::<usize>(&self.display_snapshot(cx))
15394            .into();
15395        if old_selections.is_empty() {
15396            return;
15397        }
15398
15399        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15400
15401        let buffer = self.buffer.read(cx).snapshot(cx);
15402        let mut selected_sibling = false;
15403
15404        let new_selections = old_selections
15405            .iter()
15406            .map(|selection| {
15407                let old_range = selection.start..selection.end;
15408
15409                if let Some(node) = buffer.syntax_next_sibling(old_range) {
15410                    let new_range = node.byte_range();
15411                    selected_sibling = true;
15412                    Selection {
15413                        id: selection.id,
15414                        start: new_range.start,
15415                        end: new_range.end,
15416                        goal: SelectionGoal::None,
15417                        reversed: selection.reversed,
15418                    }
15419                } else {
15420                    selection.clone()
15421                }
15422            })
15423            .collect::<Vec<_>>();
15424
15425        if selected_sibling {
15426            self.change_selections(
15427                SelectionEffects::scroll(Autoscroll::fit()),
15428                window,
15429                cx,
15430                |s| {
15431                    s.select(new_selections);
15432                },
15433            );
15434        }
15435    }
15436
15437    pub fn select_prev_syntax_node(
15438        &mut self,
15439        _: &SelectPreviousSyntaxNode,
15440        window: &mut Window,
15441        cx: &mut Context<Self>,
15442    ) {
15443        let old_selections: Box<[_]> = self
15444            .selections
15445            .all::<usize>(&self.display_snapshot(cx))
15446            .into();
15447        if old_selections.is_empty() {
15448            return;
15449        }
15450
15451        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15452
15453        let buffer = self.buffer.read(cx).snapshot(cx);
15454        let mut selected_sibling = false;
15455
15456        let new_selections = old_selections
15457            .iter()
15458            .map(|selection| {
15459                let old_range = selection.start..selection.end;
15460
15461                if let Some(node) = buffer.syntax_prev_sibling(old_range) {
15462                    let new_range = node.byte_range();
15463                    selected_sibling = true;
15464                    Selection {
15465                        id: selection.id,
15466                        start: new_range.start,
15467                        end: new_range.end,
15468                        goal: SelectionGoal::None,
15469                        reversed: selection.reversed,
15470                    }
15471                } else {
15472                    selection.clone()
15473                }
15474            })
15475            .collect::<Vec<_>>();
15476
15477        if selected_sibling {
15478            self.change_selections(
15479                SelectionEffects::scroll(Autoscroll::fit()),
15480                window,
15481                cx,
15482                |s| {
15483                    s.select(new_selections);
15484                },
15485            );
15486        }
15487    }
15488
15489    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
15490        if !EditorSettings::get_global(cx).gutter.runnables {
15491            self.clear_tasks();
15492            return Task::ready(());
15493        }
15494        let project = self.project().map(Entity::downgrade);
15495        let task_sources = self.lsp_task_sources(cx);
15496        let multi_buffer = self.buffer.downgrade();
15497        cx.spawn_in(window, async move |editor, cx| {
15498            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
15499            let Some(project) = project.and_then(|p| p.upgrade()) else {
15500                return;
15501            };
15502            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
15503                this.display_map.update(cx, |map, cx| map.snapshot(cx))
15504            }) else {
15505                return;
15506            };
15507
15508            let hide_runnables = project
15509                .update(cx, |project, _| project.is_via_collab())
15510                .unwrap_or(true);
15511            if hide_runnables {
15512                return;
15513            }
15514            let new_rows =
15515                cx.background_spawn({
15516                    let snapshot = display_snapshot.clone();
15517                    async move {
15518                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
15519                    }
15520                })
15521                    .await;
15522            let Ok(lsp_tasks) =
15523                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
15524            else {
15525                return;
15526            };
15527            let lsp_tasks = lsp_tasks.await;
15528
15529            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
15530                lsp_tasks
15531                    .into_iter()
15532                    .flat_map(|(kind, tasks)| {
15533                        tasks.into_iter().filter_map(move |(location, task)| {
15534                            Some((kind.clone(), location?, task))
15535                        })
15536                    })
15537                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
15538                        let buffer = location.target.buffer;
15539                        let buffer_snapshot = buffer.read(cx).snapshot();
15540                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
15541                            |(excerpt_id, snapshot, _)| {
15542                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
15543                                    display_snapshot
15544                                        .buffer_snapshot()
15545                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
15546                                } else {
15547                                    None
15548                                }
15549                            },
15550                        );
15551                        if let Some(offset) = offset {
15552                            let task_buffer_range =
15553                                location.target.range.to_point(&buffer_snapshot);
15554                            let context_buffer_range =
15555                                task_buffer_range.to_offset(&buffer_snapshot);
15556                            let context_range = BufferOffset(context_buffer_range.start)
15557                                ..BufferOffset(context_buffer_range.end);
15558
15559                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
15560                                .or_insert_with(|| RunnableTasks {
15561                                    templates: Vec::new(),
15562                                    offset,
15563                                    column: task_buffer_range.start.column,
15564                                    extra_variables: HashMap::default(),
15565                                    context_range,
15566                                })
15567                                .templates
15568                                .push((kind, task.original_task().clone()));
15569                        }
15570
15571                        acc
15572                    })
15573            }) else {
15574                return;
15575            };
15576
15577            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
15578                buffer.language_settings(cx).tasks.prefer_lsp
15579            }) else {
15580                return;
15581            };
15582
15583            let rows = Self::runnable_rows(
15584                project,
15585                display_snapshot,
15586                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
15587                new_rows,
15588                cx.clone(),
15589            )
15590            .await;
15591            editor
15592                .update(cx, |editor, _| {
15593                    editor.clear_tasks();
15594                    for (key, mut value) in rows {
15595                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
15596                            value.templates.extend(lsp_tasks.templates);
15597                        }
15598
15599                        editor.insert_tasks(key, value);
15600                    }
15601                    for (key, value) in lsp_tasks_by_rows {
15602                        editor.insert_tasks(key, value);
15603                    }
15604                })
15605                .ok();
15606        })
15607    }
15608    fn fetch_runnable_ranges(
15609        snapshot: &DisplaySnapshot,
15610        range: Range<Anchor>,
15611    ) -> Vec<language::RunnableRange> {
15612        snapshot.buffer_snapshot().runnable_ranges(range).collect()
15613    }
15614
15615    fn runnable_rows(
15616        project: Entity<Project>,
15617        snapshot: DisplaySnapshot,
15618        prefer_lsp: bool,
15619        runnable_ranges: Vec<RunnableRange>,
15620        cx: AsyncWindowContext,
15621    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
15622        cx.spawn(async move |cx| {
15623            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
15624            for mut runnable in runnable_ranges {
15625                let Some(tasks) = cx
15626                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
15627                    .ok()
15628                else {
15629                    continue;
15630                };
15631                let mut tasks = tasks.await;
15632
15633                if prefer_lsp {
15634                    tasks.retain(|(task_kind, _)| {
15635                        !matches!(task_kind, TaskSourceKind::Language { .. })
15636                    });
15637                }
15638                if tasks.is_empty() {
15639                    continue;
15640                }
15641
15642                let point = runnable
15643                    .run_range
15644                    .start
15645                    .to_point(&snapshot.buffer_snapshot());
15646                let Some(row) = snapshot
15647                    .buffer_snapshot()
15648                    .buffer_line_for_row(MultiBufferRow(point.row))
15649                    .map(|(_, range)| range.start.row)
15650                else {
15651                    continue;
15652                };
15653
15654                let context_range =
15655                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
15656                runnable_rows.push((
15657                    (runnable.buffer_id, row),
15658                    RunnableTasks {
15659                        templates: tasks,
15660                        offset: snapshot
15661                            .buffer_snapshot()
15662                            .anchor_before(runnable.run_range.start),
15663                        context_range,
15664                        column: point.column,
15665                        extra_variables: runnable.extra_captures,
15666                    },
15667                ));
15668            }
15669            runnable_rows
15670        })
15671    }
15672
15673    fn templates_with_tags(
15674        project: &Entity<Project>,
15675        runnable: &mut Runnable,
15676        cx: &mut App,
15677    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
15678        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
15679            let (worktree_id, file) = project
15680                .buffer_for_id(runnable.buffer, cx)
15681                .and_then(|buffer| buffer.read(cx).file())
15682                .map(|file| (file.worktree_id(cx), file.clone()))
15683                .unzip();
15684
15685            (
15686                project.task_store().read(cx).task_inventory().cloned(),
15687                worktree_id,
15688                file,
15689            )
15690        });
15691
15692        let tags = mem::take(&mut runnable.tags);
15693        let language = runnable.language.clone();
15694        cx.spawn(async move |cx| {
15695            let mut templates_with_tags = Vec::new();
15696            if let Some(inventory) = inventory {
15697                for RunnableTag(tag) in tags {
15698                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
15699                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
15700                    }) else {
15701                        return templates_with_tags;
15702                    };
15703                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
15704                        move |(_, template)| {
15705                            template.tags.iter().any(|source_tag| source_tag == &tag)
15706                        },
15707                    ));
15708                }
15709            }
15710            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
15711
15712            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
15713                // Strongest source wins; if we have worktree tag binding, prefer that to
15714                // global and language bindings;
15715                // if we have a global binding, prefer that to language binding.
15716                let first_mismatch = templates_with_tags
15717                    .iter()
15718                    .position(|(tag_source, _)| tag_source != leading_tag_source);
15719                if let Some(index) = first_mismatch {
15720                    templates_with_tags.truncate(index);
15721                }
15722            }
15723
15724            templates_with_tags
15725        })
15726    }
15727
15728    pub fn move_to_enclosing_bracket(
15729        &mut self,
15730        _: &MoveToEnclosingBracket,
15731        window: &mut Window,
15732        cx: &mut Context<Self>,
15733    ) {
15734        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15735        self.change_selections(Default::default(), window, cx, |s| {
15736            s.move_offsets_with(|snapshot, selection| {
15737                let Some(enclosing_bracket_ranges) =
15738                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
15739                else {
15740                    return;
15741                };
15742
15743                let mut best_length = usize::MAX;
15744                let mut best_inside = false;
15745                let mut best_in_bracket_range = false;
15746                let mut best_destination = None;
15747                for (open, close) in enclosing_bracket_ranges {
15748                    let close = close.to_inclusive();
15749                    let length = close.end() - open.start;
15750                    let inside = selection.start >= open.end && selection.end <= *close.start();
15751                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
15752                        || close.contains(&selection.head());
15753
15754                    // If best is next to a bracket and current isn't, skip
15755                    if !in_bracket_range && best_in_bracket_range {
15756                        continue;
15757                    }
15758
15759                    // Prefer smaller lengths unless best is inside and current isn't
15760                    if length > best_length && (best_inside || !inside) {
15761                        continue;
15762                    }
15763
15764                    best_length = length;
15765                    best_inside = inside;
15766                    best_in_bracket_range = in_bracket_range;
15767                    best_destination = Some(
15768                        if close.contains(&selection.start) && close.contains(&selection.end) {
15769                            if inside { open.end } else { open.start }
15770                        } else if inside {
15771                            *close.start()
15772                        } else {
15773                            *close.end()
15774                        },
15775                    );
15776                }
15777
15778                if let Some(destination) = best_destination {
15779                    selection.collapse_to(destination, SelectionGoal::None);
15780                }
15781            })
15782        });
15783    }
15784
15785    pub fn undo_selection(
15786        &mut self,
15787        _: &UndoSelection,
15788        window: &mut Window,
15789        cx: &mut Context<Self>,
15790    ) {
15791        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15792        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
15793            self.selection_history.mode = SelectionHistoryMode::Undoing;
15794            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15795                this.end_selection(window, cx);
15796                this.change_selections(
15797                    SelectionEffects::scroll(Autoscroll::newest()),
15798                    window,
15799                    cx,
15800                    |s| s.select_anchors(entry.selections.to_vec()),
15801                );
15802            });
15803            self.selection_history.mode = SelectionHistoryMode::Normal;
15804
15805            self.select_next_state = entry.select_next_state;
15806            self.select_prev_state = entry.select_prev_state;
15807            self.add_selections_state = entry.add_selections_state;
15808        }
15809    }
15810
15811    pub fn redo_selection(
15812        &mut self,
15813        _: &RedoSelection,
15814        window: &mut Window,
15815        cx: &mut Context<Self>,
15816    ) {
15817        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15818        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
15819            self.selection_history.mode = SelectionHistoryMode::Redoing;
15820            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
15821                this.end_selection(window, cx);
15822                this.change_selections(
15823                    SelectionEffects::scroll(Autoscroll::newest()),
15824                    window,
15825                    cx,
15826                    |s| s.select_anchors(entry.selections.to_vec()),
15827                );
15828            });
15829            self.selection_history.mode = SelectionHistoryMode::Normal;
15830
15831            self.select_next_state = entry.select_next_state;
15832            self.select_prev_state = entry.select_prev_state;
15833            self.add_selections_state = entry.add_selections_state;
15834        }
15835    }
15836
15837    pub fn expand_excerpts(
15838        &mut self,
15839        action: &ExpandExcerpts,
15840        _: &mut Window,
15841        cx: &mut Context<Self>,
15842    ) {
15843        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
15844    }
15845
15846    pub fn expand_excerpts_down(
15847        &mut self,
15848        action: &ExpandExcerptsDown,
15849        _: &mut Window,
15850        cx: &mut Context<Self>,
15851    ) {
15852        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
15853    }
15854
15855    pub fn expand_excerpts_up(
15856        &mut self,
15857        action: &ExpandExcerptsUp,
15858        _: &mut Window,
15859        cx: &mut Context<Self>,
15860    ) {
15861        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
15862    }
15863
15864    pub fn expand_excerpts_for_direction(
15865        &mut self,
15866        lines: u32,
15867        direction: ExpandExcerptDirection,
15868
15869        cx: &mut Context<Self>,
15870    ) {
15871        let selections = self.selections.disjoint_anchors_arc();
15872
15873        let lines = if lines == 0 {
15874            EditorSettings::get_global(cx).expand_excerpt_lines
15875        } else {
15876            lines
15877        };
15878
15879        self.buffer.update(cx, |buffer, cx| {
15880            let snapshot = buffer.snapshot(cx);
15881            let mut excerpt_ids = selections
15882                .iter()
15883                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
15884                .collect::<Vec<_>>();
15885            excerpt_ids.sort();
15886            excerpt_ids.dedup();
15887            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
15888        })
15889    }
15890
15891    pub fn expand_excerpt(
15892        &mut self,
15893        excerpt: ExcerptId,
15894        direction: ExpandExcerptDirection,
15895        window: &mut Window,
15896        cx: &mut Context<Self>,
15897    ) {
15898        let current_scroll_position = self.scroll_position(cx);
15899        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
15900        let mut scroll = None;
15901
15902        if direction == ExpandExcerptDirection::Down {
15903            let multi_buffer = self.buffer.read(cx);
15904            let snapshot = multi_buffer.snapshot(cx);
15905            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
15906                && let Some(buffer) = multi_buffer.buffer(buffer_id)
15907                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
15908            {
15909                let buffer_snapshot = buffer.read(cx).snapshot();
15910                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
15911                let last_row = buffer_snapshot.max_point().row;
15912                let lines_below = last_row.saturating_sub(excerpt_end_row);
15913                if lines_below >= lines_to_expand {
15914                    scroll = Some(
15915                        current_scroll_position
15916                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
15917                    );
15918                }
15919            }
15920        }
15921        if direction == ExpandExcerptDirection::Up
15922            && self
15923                .buffer
15924                .read(cx)
15925                .snapshot(cx)
15926                .excerpt_before(excerpt)
15927                .is_none()
15928        {
15929            scroll = Some(current_scroll_position);
15930        }
15931
15932        self.buffer.update(cx, |buffer, cx| {
15933            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
15934        });
15935
15936        if let Some(new_scroll_position) = scroll {
15937            self.set_scroll_position(new_scroll_position, window, cx);
15938        }
15939    }
15940
15941    pub fn go_to_singleton_buffer_point(
15942        &mut self,
15943        point: Point,
15944        window: &mut Window,
15945        cx: &mut Context<Self>,
15946    ) {
15947        self.go_to_singleton_buffer_range(point..point, window, cx);
15948    }
15949
15950    pub fn go_to_singleton_buffer_range(
15951        &mut self,
15952        range: Range<Point>,
15953        window: &mut Window,
15954        cx: &mut Context<Self>,
15955    ) {
15956        let multibuffer = self.buffer().read(cx);
15957        let Some(buffer) = multibuffer.as_singleton() else {
15958            return;
15959        };
15960        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
15961            return;
15962        };
15963        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
15964            return;
15965        };
15966        self.change_selections(
15967            SelectionEffects::default().nav_history(true),
15968            window,
15969            cx,
15970            |s| s.select_anchor_ranges([start..end]),
15971        );
15972    }
15973
15974    pub fn go_to_diagnostic(
15975        &mut self,
15976        action: &GoToDiagnostic,
15977        window: &mut Window,
15978        cx: &mut Context<Self>,
15979    ) {
15980        if !self.diagnostics_enabled() {
15981            return;
15982        }
15983        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15984        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
15985    }
15986
15987    pub fn go_to_prev_diagnostic(
15988        &mut self,
15989        action: &GoToPreviousDiagnostic,
15990        window: &mut Window,
15991        cx: &mut Context<Self>,
15992    ) {
15993        if !self.diagnostics_enabled() {
15994            return;
15995        }
15996        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15997        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
15998    }
15999
16000    pub fn go_to_diagnostic_impl(
16001        &mut self,
16002        direction: Direction,
16003        severity: GoToDiagnosticSeverityFilter,
16004        window: &mut Window,
16005        cx: &mut Context<Self>,
16006    ) {
16007        let buffer = self.buffer.read(cx).snapshot(cx);
16008        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
16009
16010        let mut active_group_id = None;
16011        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16012            && active_group.active_range.start.to_offset(&buffer) == selection.start
16013        {
16014            active_group_id = Some(active_group.group_id);
16015        }
16016
16017        fn filtered<'a>(
16018            snapshot: EditorSnapshot,
16019            severity: GoToDiagnosticSeverityFilter,
16020            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, usize>>,
16021        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, usize>> {
16022            diagnostics
16023                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16024                .filter(|entry| entry.range.start != entry.range.end)
16025                .filter(|entry| !entry.diagnostic.is_unnecessary)
16026                .filter(move |entry| !snapshot.intersects_fold(entry.range.start))
16027        }
16028
16029        let snapshot = self.snapshot(window, cx);
16030        let before = filtered(
16031            snapshot.clone(),
16032            severity,
16033            buffer
16034                .diagnostics_in_range(0..selection.start)
16035                .filter(|entry| entry.range.start <= selection.start),
16036        );
16037        let after = filtered(
16038            snapshot,
16039            severity,
16040            buffer
16041                .diagnostics_in_range(selection.start..buffer.len())
16042                .filter(|entry| entry.range.start >= selection.start),
16043        );
16044
16045        let mut found: Option<DiagnosticEntryRef<usize>> = None;
16046        if direction == Direction::Prev {
16047            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16048            {
16049                for diagnostic in prev_diagnostics.into_iter().rev() {
16050                    if diagnostic.range.start != selection.start
16051                        || active_group_id
16052                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16053                    {
16054                        found = Some(diagnostic);
16055                        break 'outer;
16056                    }
16057                }
16058            }
16059        } else {
16060            for diagnostic in after.chain(before) {
16061                if diagnostic.range.start != selection.start
16062                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16063                {
16064                    found = Some(diagnostic);
16065                    break;
16066                }
16067            }
16068        }
16069        let Some(next_diagnostic) = found else {
16070            return;
16071        };
16072
16073        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16074        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16075            return;
16076        };
16077        self.change_selections(Default::default(), window, cx, |s| {
16078            s.select_ranges(vec![
16079                next_diagnostic.range.start..next_diagnostic.range.start,
16080            ])
16081        });
16082        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16083        self.refresh_edit_prediction(false, true, window, cx);
16084    }
16085
16086    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16087        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16088        let snapshot = self.snapshot(window, cx);
16089        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16090        self.go_to_hunk_before_or_after_position(
16091            &snapshot,
16092            selection.head(),
16093            Direction::Next,
16094            window,
16095            cx,
16096        );
16097    }
16098
16099    pub fn go_to_hunk_before_or_after_position(
16100        &mut self,
16101        snapshot: &EditorSnapshot,
16102        position: Point,
16103        direction: Direction,
16104        window: &mut Window,
16105        cx: &mut Context<Editor>,
16106    ) {
16107        let row = if direction == Direction::Next {
16108            self.hunk_after_position(snapshot, position)
16109                .map(|hunk| hunk.row_range.start)
16110        } else {
16111            self.hunk_before_position(snapshot, position)
16112        };
16113
16114        if let Some(row) = row {
16115            let destination = Point::new(row.0, 0);
16116            let autoscroll = Autoscroll::center();
16117
16118            self.unfold_ranges(&[destination..destination], false, false, cx);
16119            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16120                s.select_ranges([destination..destination]);
16121            });
16122        }
16123    }
16124
16125    fn hunk_after_position(
16126        &mut self,
16127        snapshot: &EditorSnapshot,
16128        position: Point,
16129    ) -> Option<MultiBufferDiffHunk> {
16130        snapshot
16131            .buffer_snapshot()
16132            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16133            .find(|hunk| hunk.row_range.start.0 > position.row)
16134            .or_else(|| {
16135                snapshot
16136                    .buffer_snapshot()
16137                    .diff_hunks_in_range(Point::zero()..position)
16138                    .find(|hunk| hunk.row_range.end.0 < position.row)
16139            })
16140    }
16141
16142    fn go_to_prev_hunk(
16143        &mut self,
16144        _: &GoToPreviousHunk,
16145        window: &mut Window,
16146        cx: &mut Context<Self>,
16147    ) {
16148        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16149        let snapshot = self.snapshot(window, cx);
16150        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16151        self.go_to_hunk_before_or_after_position(
16152            &snapshot,
16153            selection.head(),
16154            Direction::Prev,
16155            window,
16156            cx,
16157        );
16158    }
16159
16160    fn hunk_before_position(
16161        &mut self,
16162        snapshot: &EditorSnapshot,
16163        position: Point,
16164    ) -> Option<MultiBufferRow> {
16165        snapshot
16166            .buffer_snapshot()
16167            .diff_hunk_before(position)
16168            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16169    }
16170
16171    fn go_to_next_change(
16172        &mut self,
16173        _: &GoToNextChange,
16174        window: &mut Window,
16175        cx: &mut Context<Self>,
16176    ) {
16177        if let Some(selections) = self
16178            .change_list
16179            .next_change(1, Direction::Next)
16180            .map(|s| s.to_vec())
16181        {
16182            self.change_selections(Default::default(), window, cx, |s| {
16183                let map = s.display_map();
16184                s.select_display_ranges(selections.iter().map(|a| {
16185                    let point = a.to_display_point(&map);
16186                    point..point
16187                }))
16188            })
16189        }
16190    }
16191
16192    fn go_to_previous_change(
16193        &mut self,
16194        _: &GoToPreviousChange,
16195        window: &mut Window,
16196        cx: &mut Context<Self>,
16197    ) {
16198        if let Some(selections) = self
16199            .change_list
16200            .next_change(1, Direction::Prev)
16201            .map(|s| s.to_vec())
16202        {
16203            self.change_selections(Default::default(), window, cx, |s| {
16204                let map = s.display_map();
16205                s.select_display_ranges(selections.iter().map(|a| {
16206                    let point = a.to_display_point(&map);
16207                    point..point
16208                }))
16209            })
16210        }
16211    }
16212
16213    pub fn go_to_next_document_highlight(
16214        &mut self,
16215        _: &GoToNextDocumentHighlight,
16216        window: &mut Window,
16217        cx: &mut Context<Self>,
16218    ) {
16219        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16220    }
16221
16222    pub fn go_to_prev_document_highlight(
16223        &mut self,
16224        _: &GoToPreviousDocumentHighlight,
16225        window: &mut Window,
16226        cx: &mut Context<Self>,
16227    ) {
16228        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
16229    }
16230
16231    pub fn go_to_document_highlight_before_or_after_position(
16232        &mut self,
16233        direction: Direction,
16234        window: &mut Window,
16235        cx: &mut Context<Editor>,
16236    ) {
16237        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16238        let snapshot = self.snapshot(window, cx);
16239        let buffer = &snapshot.buffer_snapshot();
16240        let position = self
16241            .selections
16242            .newest::<Point>(&snapshot.display_snapshot)
16243            .head();
16244        let anchor_position = buffer.anchor_after(position);
16245
16246        // Get all document highlights (both read and write)
16247        let mut all_highlights = Vec::new();
16248
16249        if let Some((_, read_highlights)) = self
16250            .background_highlights
16251            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
16252        {
16253            all_highlights.extend(read_highlights.iter());
16254        }
16255
16256        if let Some((_, write_highlights)) = self
16257            .background_highlights
16258            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
16259        {
16260            all_highlights.extend(write_highlights.iter());
16261        }
16262
16263        if all_highlights.is_empty() {
16264            return;
16265        }
16266
16267        // Sort highlights by position
16268        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
16269
16270        let target_highlight = match direction {
16271            Direction::Next => {
16272                // Find the first highlight after the current position
16273                all_highlights
16274                    .iter()
16275                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
16276            }
16277            Direction::Prev => {
16278                // Find the last highlight before the current position
16279                all_highlights
16280                    .iter()
16281                    .rev()
16282                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
16283            }
16284        };
16285
16286        if let Some(highlight) = target_highlight {
16287            let destination = highlight.start.to_point(buffer);
16288            let autoscroll = Autoscroll::center();
16289
16290            self.unfold_ranges(&[destination..destination], false, false, cx);
16291            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16292                s.select_ranges([destination..destination]);
16293            });
16294        }
16295    }
16296
16297    fn go_to_line<T: 'static>(
16298        &mut self,
16299        position: Anchor,
16300        highlight_color: Option<Hsla>,
16301        window: &mut Window,
16302        cx: &mut Context<Self>,
16303    ) {
16304        let snapshot = self.snapshot(window, cx).display_snapshot;
16305        let position = position.to_point(&snapshot.buffer_snapshot());
16306        let start = snapshot
16307            .buffer_snapshot()
16308            .clip_point(Point::new(position.row, 0), Bias::Left);
16309        let end = start + Point::new(1, 0);
16310        let start = snapshot.buffer_snapshot().anchor_before(start);
16311        let end = snapshot.buffer_snapshot().anchor_before(end);
16312
16313        self.highlight_rows::<T>(
16314            start..end,
16315            highlight_color
16316                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
16317            Default::default(),
16318            cx,
16319        );
16320
16321        if self.buffer.read(cx).is_singleton() {
16322            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
16323        }
16324    }
16325
16326    pub fn go_to_definition(
16327        &mut self,
16328        _: &GoToDefinition,
16329        window: &mut Window,
16330        cx: &mut Context<Self>,
16331    ) -> Task<Result<Navigated>> {
16332        let definition =
16333            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
16334        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
16335        cx.spawn_in(window, async move |editor, cx| {
16336            if definition.await? == Navigated::Yes {
16337                return Ok(Navigated::Yes);
16338            }
16339            match fallback_strategy {
16340                GoToDefinitionFallback::None => Ok(Navigated::No),
16341                GoToDefinitionFallback::FindAllReferences => {
16342                    match editor.update_in(cx, |editor, window, cx| {
16343                        editor.find_all_references(&FindAllReferences, window, cx)
16344                    })? {
16345                        Some(references) => references.await,
16346                        None => Ok(Navigated::No),
16347                    }
16348                }
16349            }
16350        })
16351    }
16352
16353    pub fn go_to_declaration(
16354        &mut self,
16355        _: &GoToDeclaration,
16356        window: &mut Window,
16357        cx: &mut Context<Self>,
16358    ) -> Task<Result<Navigated>> {
16359        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
16360    }
16361
16362    pub fn go_to_declaration_split(
16363        &mut self,
16364        _: &GoToDeclaration,
16365        window: &mut Window,
16366        cx: &mut Context<Self>,
16367    ) -> Task<Result<Navigated>> {
16368        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
16369    }
16370
16371    pub fn go_to_implementation(
16372        &mut self,
16373        _: &GoToImplementation,
16374        window: &mut Window,
16375        cx: &mut Context<Self>,
16376    ) -> Task<Result<Navigated>> {
16377        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
16378    }
16379
16380    pub fn go_to_implementation_split(
16381        &mut self,
16382        _: &GoToImplementationSplit,
16383        window: &mut Window,
16384        cx: &mut Context<Self>,
16385    ) -> Task<Result<Navigated>> {
16386        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
16387    }
16388
16389    pub fn go_to_type_definition(
16390        &mut self,
16391        _: &GoToTypeDefinition,
16392        window: &mut Window,
16393        cx: &mut Context<Self>,
16394    ) -> Task<Result<Navigated>> {
16395        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
16396    }
16397
16398    pub fn go_to_definition_split(
16399        &mut self,
16400        _: &GoToDefinitionSplit,
16401        window: &mut Window,
16402        cx: &mut Context<Self>,
16403    ) -> Task<Result<Navigated>> {
16404        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
16405    }
16406
16407    pub fn go_to_type_definition_split(
16408        &mut self,
16409        _: &GoToTypeDefinitionSplit,
16410        window: &mut Window,
16411        cx: &mut Context<Self>,
16412    ) -> Task<Result<Navigated>> {
16413        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
16414    }
16415
16416    fn go_to_definition_of_kind(
16417        &mut self,
16418        kind: GotoDefinitionKind,
16419        split: bool,
16420        window: &mut Window,
16421        cx: &mut Context<Self>,
16422    ) -> Task<Result<Navigated>> {
16423        let Some(provider) = self.semantics_provider.clone() else {
16424            return Task::ready(Ok(Navigated::No));
16425        };
16426        let head = self
16427            .selections
16428            .newest::<usize>(&self.display_snapshot(cx))
16429            .head();
16430        let buffer = self.buffer.read(cx);
16431        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
16432            return Task::ready(Ok(Navigated::No));
16433        };
16434        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
16435            return Task::ready(Ok(Navigated::No));
16436        };
16437
16438        cx.spawn_in(window, async move |editor, cx| {
16439            let Some(definitions) = definitions.await? else {
16440                return Ok(Navigated::No);
16441            };
16442            let navigated = editor
16443                .update_in(cx, |editor, window, cx| {
16444                    editor.navigate_to_hover_links(
16445                        Some(kind),
16446                        definitions
16447                            .into_iter()
16448                            .filter(|location| {
16449                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
16450                            })
16451                            .map(HoverLink::Text)
16452                            .collect::<Vec<_>>(),
16453                        split,
16454                        window,
16455                        cx,
16456                    )
16457                })?
16458                .await?;
16459            anyhow::Ok(navigated)
16460        })
16461    }
16462
16463    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
16464        let selection = self.selections.newest_anchor();
16465        let head = selection.head();
16466        let tail = selection.tail();
16467
16468        let Some((buffer, start_position)) =
16469            self.buffer.read(cx).text_anchor_for_position(head, cx)
16470        else {
16471            return;
16472        };
16473
16474        let end_position = if head != tail {
16475            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
16476                return;
16477            };
16478            Some(pos)
16479        } else {
16480            None
16481        };
16482
16483        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
16484            let url = if let Some(end_pos) = end_position {
16485                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
16486            } else {
16487                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
16488            };
16489
16490            if let Some(url) = url {
16491                cx.update(|window, cx| {
16492                    if parse_zed_link(&url, cx).is_some() {
16493                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
16494                    } else {
16495                        cx.open_url(&url);
16496                    }
16497                })?;
16498            }
16499
16500            anyhow::Ok(())
16501        });
16502
16503        url_finder.detach();
16504    }
16505
16506    pub fn open_selected_filename(
16507        &mut self,
16508        _: &OpenSelectedFilename,
16509        window: &mut Window,
16510        cx: &mut Context<Self>,
16511    ) {
16512        let Some(workspace) = self.workspace() else {
16513            return;
16514        };
16515
16516        let position = self.selections.newest_anchor().head();
16517
16518        let Some((buffer, buffer_position)) =
16519            self.buffer.read(cx).text_anchor_for_position(position, cx)
16520        else {
16521            return;
16522        };
16523
16524        let project = self.project.clone();
16525
16526        cx.spawn_in(window, async move |_, cx| {
16527            let result = find_file(&buffer, project, buffer_position, cx).await;
16528
16529            if let Some((_, path)) = result {
16530                workspace
16531                    .update_in(cx, |workspace, window, cx| {
16532                        workspace.open_resolved_path(path, window, cx)
16533                    })?
16534                    .await?;
16535            }
16536            anyhow::Ok(())
16537        })
16538        .detach();
16539    }
16540
16541    pub(crate) fn navigate_to_hover_links(
16542        &mut self,
16543        kind: Option<GotoDefinitionKind>,
16544        definitions: Vec<HoverLink>,
16545        split: bool,
16546        window: &mut Window,
16547        cx: &mut Context<Editor>,
16548    ) -> Task<Result<Navigated>> {
16549        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
16550        let mut first_url_or_file = None;
16551        let definitions: Vec<_> = definitions
16552            .into_iter()
16553            .filter_map(|def| match def {
16554                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
16555                HoverLink::InlayHint(lsp_location, server_id) => {
16556                    let computation =
16557                        self.compute_target_location(lsp_location, server_id, window, cx);
16558                    Some(cx.background_spawn(computation))
16559                }
16560                HoverLink::Url(url) => {
16561                    first_url_or_file = Some(Either::Left(url));
16562                    None
16563                }
16564                HoverLink::File(path) => {
16565                    first_url_or_file = Some(Either::Right(path));
16566                    None
16567                }
16568            })
16569            .collect();
16570
16571        let workspace = self.workspace();
16572
16573        cx.spawn_in(window, async move |editor, cx| {
16574            let locations: Vec<Location> = future::join_all(definitions)
16575                .await
16576                .into_iter()
16577                .filter_map(|location| location.transpose())
16578                .collect::<Result<_>>()
16579                .context("location tasks")?;
16580            let mut locations = cx.update(|_, cx| {
16581                locations
16582                    .into_iter()
16583                    .map(|location| {
16584                        let buffer = location.buffer.read(cx);
16585                        (location.buffer, location.range.to_point(buffer))
16586                    })
16587                    .into_group_map()
16588            })?;
16589            let mut num_locations = 0;
16590            for ranges in locations.values_mut() {
16591                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16592                ranges.dedup();
16593                num_locations += ranges.len();
16594            }
16595
16596            if num_locations > 1 {
16597                let Some(workspace) = workspace else {
16598                    return Ok(Navigated::No);
16599                };
16600
16601                let tab_kind = match kind {
16602                    Some(GotoDefinitionKind::Implementation) => "Implementations",
16603                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
16604                    Some(GotoDefinitionKind::Declaration) => "Declarations",
16605                    Some(GotoDefinitionKind::Type) => "Types",
16606                };
16607                let title = editor
16608                    .update_in(cx, |_, _, cx| {
16609                        let target = locations
16610                            .iter()
16611                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16612                            .map(|(buffer, location)| {
16613                                buffer
16614                                    .read(cx)
16615                                    .text_for_range(location.clone())
16616                                    .collect::<String>()
16617                            })
16618                            .filter(|text| !text.contains('\n'))
16619                            .unique()
16620                            .take(3)
16621                            .join(", ");
16622                        if target.is_empty() {
16623                            tab_kind.to_owned()
16624                        } else {
16625                            format!("{tab_kind} for {target}")
16626                        }
16627                    })
16628                    .context("buffer title")?;
16629
16630                let opened = workspace
16631                    .update_in(cx, |workspace, window, cx| {
16632                        Self::open_locations_in_multibuffer(
16633                            workspace,
16634                            locations,
16635                            title,
16636                            split,
16637                            MultibufferSelectionMode::First,
16638                            window,
16639                            cx,
16640                        )
16641                    })
16642                    .is_ok();
16643
16644                anyhow::Ok(Navigated::from_bool(opened))
16645            } else if num_locations == 0 {
16646                // If there is one url or file, open it directly
16647                match first_url_or_file {
16648                    Some(Either::Left(url)) => {
16649                        cx.update(|_, cx| cx.open_url(&url))?;
16650                        Ok(Navigated::Yes)
16651                    }
16652                    Some(Either::Right(path)) => {
16653                        let Some(workspace) = workspace else {
16654                            return Ok(Navigated::No);
16655                        };
16656
16657                        workspace
16658                            .update_in(cx, |workspace, window, cx| {
16659                                workspace.open_resolved_path(path, window, cx)
16660                            })?
16661                            .await?;
16662                        Ok(Navigated::Yes)
16663                    }
16664                    None => Ok(Navigated::No),
16665                }
16666            } else {
16667                let Some(workspace) = workspace else {
16668                    return Ok(Navigated::No);
16669                };
16670
16671                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
16672                let target_range = target_ranges.first().unwrap().clone();
16673
16674                editor.update_in(cx, |editor, window, cx| {
16675                    let range = target_range.to_point(target_buffer.read(cx));
16676                    let range = editor.range_for_match(&range, false);
16677                    let range = collapse_multiline_range(range);
16678
16679                    if !split
16680                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
16681                    {
16682                        editor.go_to_singleton_buffer_range(range, window, cx);
16683                    } else {
16684                        let pane = workspace.read(cx).active_pane().clone();
16685                        window.defer(cx, move |window, cx| {
16686                            let target_editor: Entity<Self> =
16687                                workspace.update(cx, |workspace, cx| {
16688                                    let pane = if split {
16689                                        workspace.adjacent_pane(window, cx)
16690                                    } else {
16691                                        workspace.active_pane().clone()
16692                                    };
16693
16694                                    workspace.open_project_item(
16695                                        pane,
16696                                        target_buffer.clone(),
16697                                        true,
16698                                        true,
16699                                        window,
16700                                        cx,
16701                                    )
16702                                });
16703                            target_editor.update(cx, |target_editor, cx| {
16704                                // When selecting a definition in a different buffer, disable the nav history
16705                                // to avoid creating a history entry at the previous cursor location.
16706                                pane.update(cx, |pane, _| pane.disable_history());
16707                                target_editor.go_to_singleton_buffer_range(range, window, cx);
16708                                pane.update(cx, |pane, _| pane.enable_history());
16709                            });
16710                        });
16711                    }
16712                    Navigated::Yes
16713                })
16714            }
16715        })
16716    }
16717
16718    fn compute_target_location(
16719        &self,
16720        lsp_location: lsp::Location,
16721        server_id: LanguageServerId,
16722        window: &mut Window,
16723        cx: &mut Context<Self>,
16724    ) -> Task<anyhow::Result<Option<Location>>> {
16725        let Some(project) = self.project.clone() else {
16726            return Task::ready(Ok(None));
16727        };
16728
16729        cx.spawn_in(window, async move |editor, cx| {
16730            let location_task = editor.update(cx, |_, cx| {
16731                project.update(cx, |project, cx| {
16732                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
16733                })
16734            })?;
16735            let location = Some({
16736                let target_buffer_handle = location_task.await.context("open local buffer")?;
16737                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
16738                    let target_start = target_buffer
16739                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
16740                    let target_end = target_buffer
16741                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
16742                    target_buffer.anchor_after(target_start)
16743                        ..target_buffer.anchor_before(target_end)
16744                })?;
16745                Location {
16746                    buffer: target_buffer_handle,
16747                    range,
16748                }
16749            });
16750            Ok(location)
16751        })
16752    }
16753
16754    fn go_to_next_reference(
16755        &mut self,
16756        _: &GoToNextReference,
16757        window: &mut Window,
16758        cx: &mut Context<Self>,
16759    ) {
16760        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
16761        if let Some(task) = task {
16762            task.detach();
16763        };
16764    }
16765
16766    fn go_to_prev_reference(
16767        &mut self,
16768        _: &GoToPreviousReference,
16769        window: &mut Window,
16770        cx: &mut Context<Self>,
16771    ) {
16772        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
16773        if let Some(task) = task {
16774            task.detach();
16775        };
16776    }
16777
16778    pub fn go_to_reference_before_or_after_position(
16779        &mut self,
16780        direction: Direction,
16781        count: usize,
16782        window: &mut Window,
16783        cx: &mut Context<Self>,
16784    ) -> Option<Task<Result<()>>> {
16785        let selection = self.selections.newest_anchor();
16786        let head = selection.head();
16787
16788        let multi_buffer = self.buffer.read(cx);
16789
16790        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
16791        let workspace = self.workspace()?;
16792        let project = workspace.read(cx).project().clone();
16793        let references =
16794            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
16795        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
16796            let Some(locations) = references.await? else {
16797                return Ok(());
16798            };
16799
16800            if locations.is_empty() {
16801                // totally normal - the cursor may be on something which is not
16802                // a symbol (e.g. a keyword)
16803                log::info!("no references found under cursor");
16804                return Ok(());
16805            }
16806
16807            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
16808
16809            let multi_buffer_snapshot =
16810                multi_buffer.read_with(cx, |multi_buffer, cx| multi_buffer.snapshot(cx))?;
16811
16812            let (locations, current_location_index) =
16813                multi_buffer.update(cx, |multi_buffer, cx| {
16814                    let mut locations = locations
16815                        .into_iter()
16816                        .filter_map(|loc| {
16817                            let start = multi_buffer.buffer_anchor_to_anchor(
16818                                &loc.buffer,
16819                                loc.range.start,
16820                                cx,
16821                            )?;
16822                            let end = multi_buffer.buffer_anchor_to_anchor(
16823                                &loc.buffer,
16824                                loc.range.end,
16825                                cx,
16826                            )?;
16827                            Some(start..end)
16828                        })
16829                        .collect::<Vec<_>>();
16830
16831                    // There is an O(n) implementation, but given this list will be
16832                    // small (usually <100 items), the extra O(log(n)) factor isn't
16833                    // worth the (surprisingly large amount of) extra complexity.
16834                    locations
16835                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
16836
16837                    let head_offset = head.to_offset(&multi_buffer_snapshot);
16838
16839                    let current_location_index = locations.iter().position(|loc| {
16840                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
16841                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
16842                    });
16843
16844                    (locations, current_location_index)
16845                })?;
16846
16847            let Some(current_location_index) = current_location_index else {
16848                // This indicates something has gone wrong, because we already
16849                // handle the "no references" case above
16850                log::error!(
16851                    "failed to find current reference under cursor. Total references: {}",
16852                    locations.len()
16853                );
16854                return Ok(());
16855            };
16856
16857            let destination_location_index = match direction {
16858                Direction::Next => (current_location_index + count) % locations.len(),
16859                Direction::Prev => {
16860                    (current_location_index + locations.len() - count % locations.len())
16861                        % locations.len()
16862                }
16863            };
16864
16865            // TODO(cameron): is this needed?
16866            // the thinking is to avoid "jumping to the current location" (avoid
16867            // polluting "jumplist" in vim terms)
16868            if current_location_index == destination_location_index {
16869                return Ok(());
16870            }
16871
16872            let Range { start, end } = locations[destination_location_index];
16873
16874            editor.update_in(cx, |editor, window, cx| {
16875                let effects = SelectionEffects::default();
16876
16877                editor.unfold_ranges(&[start..end], false, false, cx);
16878                editor.change_selections(effects, window, cx, |s| {
16879                    s.select_ranges([start..start]);
16880                });
16881            })?;
16882
16883            Ok(())
16884        }))
16885    }
16886
16887    pub fn find_all_references(
16888        &mut self,
16889        _: &FindAllReferences,
16890        window: &mut Window,
16891        cx: &mut Context<Self>,
16892    ) -> Option<Task<Result<Navigated>>> {
16893        let selection = self.selections.newest::<usize>(&self.display_snapshot(cx));
16894        let multi_buffer = self.buffer.read(cx);
16895        let head = selection.head();
16896
16897        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
16898        let head_anchor = multi_buffer_snapshot.anchor_at(
16899            head,
16900            if head < selection.tail() {
16901                Bias::Right
16902            } else {
16903                Bias::Left
16904            },
16905        );
16906
16907        match self
16908            .find_all_references_task_sources
16909            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16910        {
16911            Ok(_) => {
16912                log::info!(
16913                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
16914                );
16915                return None;
16916            }
16917            Err(i) => {
16918                self.find_all_references_task_sources.insert(i, head_anchor);
16919            }
16920        }
16921
16922        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
16923        let workspace = self.workspace()?;
16924        let project = workspace.read(cx).project().clone();
16925        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
16926        Some(cx.spawn_in(window, async move |editor, cx| {
16927            let _cleanup = cx.on_drop(&editor, move |editor, _| {
16928                if let Ok(i) = editor
16929                    .find_all_references_task_sources
16930                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
16931                {
16932                    editor.find_all_references_task_sources.remove(i);
16933                }
16934            });
16935
16936            let Some(locations) = references.await? else {
16937                return anyhow::Ok(Navigated::No);
16938            };
16939            let mut locations = cx.update(|_, cx| {
16940                locations
16941                    .into_iter()
16942                    .map(|location| {
16943                        let buffer = location.buffer.read(cx);
16944                        (location.buffer, location.range.to_point(buffer))
16945                    })
16946                    .into_group_map()
16947            })?;
16948            if locations.is_empty() {
16949                return anyhow::Ok(Navigated::No);
16950            }
16951            for ranges in locations.values_mut() {
16952                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
16953                ranges.dedup();
16954            }
16955
16956            workspace.update_in(cx, |workspace, window, cx| {
16957                let target = locations
16958                    .iter()
16959                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
16960                    .map(|(buffer, location)| {
16961                        buffer
16962                            .read(cx)
16963                            .text_for_range(location.clone())
16964                            .collect::<String>()
16965                    })
16966                    .filter(|text| !text.contains('\n'))
16967                    .unique()
16968                    .take(3)
16969                    .join(", ");
16970                let title = if target.is_empty() {
16971                    "References".to_owned()
16972                } else {
16973                    format!("References to {target}")
16974                };
16975                Self::open_locations_in_multibuffer(
16976                    workspace,
16977                    locations,
16978                    title,
16979                    false,
16980                    MultibufferSelectionMode::First,
16981                    window,
16982                    cx,
16983                );
16984                Navigated::Yes
16985            })
16986        }))
16987    }
16988
16989    /// Opens a multibuffer with the given project locations in it
16990    pub fn open_locations_in_multibuffer(
16991        workspace: &mut Workspace,
16992        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
16993        title: String,
16994        split: bool,
16995        multibuffer_selection_mode: MultibufferSelectionMode,
16996        window: &mut Window,
16997        cx: &mut Context<Workspace>,
16998    ) {
16999        if locations.is_empty() {
17000            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
17001            return;
17002        }
17003
17004        let capability = workspace.project().read(cx).capability();
17005        let mut ranges = <Vec<Range<Anchor>>>::new();
17006
17007        // a key to find existing multibuffer editors with the same set of locations
17008        // to prevent us from opening more and more multibuffer tabs for searches and the like
17009        let mut key = (title.clone(), vec![]);
17010        let excerpt_buffer = cx.new(|cx| {
17011            let key = &mut key.1;
17012            let mut multibuffer = MultiBuffer::new(capability);
17013            for (buffer, mut ranges_for_buffer) in locations {
17014                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17015                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17016                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17017                    PathKey::for_buffer(&buffer, cx),
17018                    buffer.clone(),
17019                    ranges_for_buffer,
17020                    multibuffer_context_lines(cx),
17021                    cx,
17022                );
17023                ranges.extend(new_ranges)
17024            }
17025
17026            multibuffer.with_title(title)
17027        });
17028        let existing = workspace.active_pane().update(cx, |pane, cx| {
17029            pane.items()
17030                .filter_map(|item| item.downcast::<Editor>())
17031                .find(|editor| {
17032                    editor
17033                        .read(cx)
17034                        .lookup_key
17035                        .as_ref()
17036                        .and_then(|it| {
17037                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17038                        })
17039                        .is_some_and(|it| *it == key)
17040                })
17041        });
17042        let editor = existing.unwrap_or_else(|| {
17043            cx.new(|cx| {
17044                let mut editor = Editor::for_multibuffer(
17045                    excerpt_buffer,
17046                    Some(workspace.project().clone()),
17047                    window,
17048                    cx,
17049                );
17050                editor.lookup_key = Some(Box::new(key));
17051                editor
17052            })
17053        });
17054        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17055            MultibufferSelectionMode::First => {
17056                if let Some(first_range) = ranges.first() {
17057                    editor.change_selections(
17058                        SelectionEffects::no_scroll(),
17059                        window,
17060                        cx,
17061                        |selections| {
17062                            selections.clear_disjoint();
17063                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17064                        },
17065                    );
17066                }
17067                editor.highlight_background::<Self>(
17068                    &ranges,
17069                    |theme| theme.colors().editor_highlighted_line_background,
17070                    cx,
17071                );
17072            }
17073            MultibufferSelectionMode::All => {
17074                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17075                    selections.clear_disjoint();
17076                    selections.select_anchor_ranges(ranges);
17077                });
17078            }
17079        });
17080
17081        let item = Box::new(editor);
17082        let item_id = item.item_id();
17083
17084        if split {
17085            let pane = workspace.adjacent_pane(window, cx);
17086            workspace.add_item(pane, item, None, true, true, window, cx);
17087        } else if PreviewTabsSettings::get_global(cx).enable_preview_from_code_navigation {
17088            let (preview_item_id, preview_item_idx) =
17089                workspace.active_pane().read_with(cx, |pane, _| {
17090                    (pane.preview_item_id(), pane.preview_item_idx())
17091                });
17092
17093            workspace.add_item_to_active_pane(item, preview_item_idx, true, window, cx);
17094
17095            if let Some(preview_item_id) = preview_item_id {
17096                workspace.active_pane().update(cx, |pane, cx| {
17097                    pane.remove_item(preview_item_id, false, false, window, cx);
17098                });
17099            }
17100        } else {
17101            workspace.add_item_to_active_pane(item, None, true, window, cx);
17102        }
17103        workspace.active_pane().update(cx, |pane, cx| {
17104            pane.set_preview_item_id(Some(item_id), cx);
17105        });
17106    }
17107
17108    pub fn rename(
17109        &mut self,
17110        _: &Rename,
17111        window: &mut Window,
17112        cx: &mut Context<Self>,
17113    ) -> Option<Task<Result<()>>> {
17114        use language::ToOffset as _;
17115
17116        let provider = self.semantics_provider.clone()?;
17117        let selection = self.selections.newest_anchor().clone();
17118        let (cursor_buffer, cursor_buffer_position) = self
17119            .buffer
17120            .read(cx)
17121            .text_anchor_for_position(selection.head(), cx)?;
17122        let (tail_buffer, cursor_buffer_position_end) = self
17123            .buffer
17124            .read(cx)
17125            .text_anchor_for_position(selection.tail(), cx)?;
17126        if tail_buffer != cursor_buffer {
17127            return None;
17128        }
17129
17130        let snapshot = cursor_buffer.read(cx).snapshot();
17131        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17132        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17133        let prepare_rename = provider
17134            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17135            .unwrap_or_else(|| Task::ready(Ok(None)));
17136        drop(snapshot);
17137
17138        Some(cx.spawn_in(window, async move |this, cx| {
17139            let rename_range = if let Some(range) = prepare_rename.await? {
17140                Some(range)
17141            } else {
17142                this.update(cx, |this, cx| {
17143                    let buffer = this.buffer.read(cx).snapshot(cx);
17144                    let mut buffer_highlights = this
17145                        .document_highlights_for_position(selection.head(), &buffer)
17146                        .filter(|highlight| {
17147                            highlight.start.excerpt_id == selection.head().excerpt_id
17148                                && highlight.end.excerpt_id == selection.head().excerpt_id
17149                        });
17150                    buffer_highlights
17151                        .next()
17152                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
17153                })?
17154            };
17155            if let Some(rename_range) = rename_range {
17156                this.update_in(cx, |this, window, cx| {
17157                    let snapshot = cursor_buffer.read(cx).snapshot();
17158                    let rename_buffer_range = rename_range.to_offset(&snapshot);
17159                    let cursor_offset_in_rename_range =
17160                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
17161                    let cursor_offset_in_rename_range_end =
17162                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
17163
17164                    this.take_rename(false, window, cx);
17165                    let buffer = this.buffer.read(cx).read(cx);
17166                    let cursor_offset = selection.head().to_offset(&buffer);
17167                    let rename_start = cursor_offset.saturating_sub(cursor_offset_in_rename_range);
17168                    let rename_end = rename_start + rename_buffer_range.len();
17169                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
17170                    let mut old_highlight_id = None;
17171                    let old_name: Arc<str> = buffer
17172                        .chunks(rename_start..rename_end, true)
17173                        .map(|chunk| {
17174                            if old_highlight_id.is_none() {
17175                                old_highlight_id = chunk.syntax_highlight_id;
17176                            }
17177                            chunk.text
17178                        })
17179                        .collect::<String>()
17180                        .into();
17181
17182                    drop(buffer);
17183
17184                    // Position the selection in the rename editor so that it matches the current selection.
17185                    this.show_local_selections = false;
17186                    let rename_editor = cx.new(|cx| {
17187                        let mut editor = Editor::single_line(window, cx);
17188                        editor.buffer.update(cx, |buffer, cx| {
17189                            buffer.edit([(0..0, old_name.clone())], None, cx)
17190                        });
17191                        let rename_selection_range = match cursor_offset_in_rename_range
17192                            .cmp(&cursor_offset_in_rename_range_end)
17193                        {
17194                            Ordering::Equal => {
17195                                editor.select_all(&SelectAll, window, cx);
17196                                return editor;
17197                            }
17198                            Ordering::Less => {
17199                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
17200                            }
17201                            Ordering::Greater => {
17202                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
17203                            }
17204                        };
17205                        if rename_selection_range.end > old_name.len() {
17206                            editor.select_all(&SelectAll, window, cx);
17207                        } else {
17208                            editor.change_selections(Default::default(), window, cx, |s| {
17209                                s.select_ranges([rename_selection_range]);
17210                            });
17211                        }
17212                        editor
17213                    });
17214                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
17215                        if e == &EditorEvent::Focused {
17216                            cx.emit(EditorEvent::FocusedIn)
17217                        }
17218                    })
17219                    .detach();
17220
17221                    let write_highlights =
17222                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
17223                    let read_highlights =
17224                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
17225                    let ranges = write_highlights
17226                        .iter()
17227                        .flat_map(|(_, ranges)| ranges.iter())
17228                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
17229                        .cloned()
17230                        .collect();
17231
17232                    this.highlight_text::<Rename>(
17233                        ranges,
17234                        HighlightStyle {
17235                            fade_out: Some(0.6),
17236                            ..Default::default()
17237                        },
17238                        cx,
17239                    );
17240                    let rename_focus_handle = rename_editor.focus_handle(cx);
17241                    window.focus(&rename_focus_handle);
17242                    let block_id = this.insert_blocks(
17243                        [BlockProperties {
17244                            style: BlockStyle::Flex,
17245                            placement: BlockPlacement::Below(range.start),
17246                            height: Some(1),
17247                            render: Arc::new({
17248                                let rename_editor = rename_editor.clone();
17249                                move |cx: &mut BlockContext| {
17250                                    let mut text_style = cx.editor_style.text.clone();
17251                                    if let Some(highlight_style) = old_highlight_id
17252                                        .and_then(|h| h.style(&cx.editor_style.syntax))
17253                                    {
17254                                        text_style = text_style.highlight(highlight_style);
17255                                    }
17256                                    div()
17257                                        .block_mouse_except_scroll()
17258                                        .pl(cx.anchor_x)
17259                                        .child(EditorElement::new(
17260                                            &rename_editor,
17261                                            EditorStyle {
17262                                                background: cx.theme().system().transparent,
17263                                                local_player: cx.editor_style.local_player,
17264                                                text: text_style,
17265                                                scrollbar_width: cx.editor_style.scrollbar_width,
17266                                                syntax: cx.editor_style.syntax.clone(),
17267                                                status: cx.editor_style.status.clone(),
17268                                                inlay_hints_style: HighlightStyle {
17269                                                    font_weight: Some(FontWeight::BOLD),
17270                                                    ..make_inlay_hints_style(cx.app)
17271                                                },
17272                                                edit_prediction_styles: make_suggestion_styles(
17273                                                    cx.app,
17274                                                ),
17275                                                ..EditorStyle::default()
17276                                            },
17277                                        ))
17278                                        .into_any_element()
17279                                }
17280                            }),
17281                            priority: 0,
17282                        }],
17283                        Some(Autoscroll::fit()),
17284                        cx,
17285                    )[0];
17286                    this.pending_rename = Some(RenameState {
17287                        range,
17288                        old_name,
17289                        editor: rename_editor,
17290                        block_id,
17291                    });
17292                })?;
17293            }
17294
17295            Ok(())
17296        }))
17297    }
17298
17299    pub fn confirm_rename(
17300        &mut self,
17301        _: &ConfirmRename,
17302        window: &mut Window,
17303        cx: &mut Context<Self>,
17304    ) -> Option<Task<Result<()>>> {
17305        let rename = self.take_rename(false, window, cx)?;
17306        let workspace = self.workspace()?.downgrade();
17307        let (buffer, start) = self
17308            .buffer
17309            .read(cx)
17310            .text_anchor_for_position(rename.range.start, cx)?;
17311        let (end_buffer, _) = self
17312            .buffer
17313            .read(cx)
17314            .text_anchor_for_position(rename.range.end, cx)?;
17315        if buffer != end_buffer {
17316            return None;
17317        }
17318
17319        let old_name = rename.old_name;
17320        let new_name = rename.editor.read(cx).text(cx);
17321
17322        let rename = self.semantics_provider.as_ref()?.perform_rename(
17323            &buffer,
17324            start,
17325            new_name.clone(),
17326            cx,
17327        )?;
17328
17329        Some(cx.spawn_in(window, async move |editor, cx| {
17330            let project_transaction = rename.await?;
17331            Self::open_project_transaction(
17332                &editor,
17333                workspace,
17334                project_transaction,
17335                format!("Rename: {}{}", old_name, new_name),
17336                cx,
17337            )
17338            .await?;
17339
17340            editor.update(cx, |editor, cx| {
17341                editor.refresh_document_highlights(cx);
17342            })?;
17343            Ok(())
17344        }))
17345    }
17346
17347    fn take_rename(
17348        &mut self,
17349        moving_cursor: bool,
17350        window: &mut Window,
17351        cx: &mut Context<Self>,
17352    ) -> Option<RenameState> {
17353        let rename = self.pending_rename.take()?;
17354        if rename.editor.focus_handle(cx).is_focused(window) {
17355            window.focus(&self.focus_handle);
17356        }
17357
17358        self.remove_blocks(
17359            [rename.block_id].into_iter().collect(),
17360            Some(Autoscroll::fit()),
17361            cx,
17362        );
17363        self.clear_highlights::<Rename>(cx);
17364        self.show_local_selections = true;
17365
17366        if moving_cursor {
17367            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
17368                editor
17369                    .selections
17370                    .newest::<usize>(&editor.display_snapshot(cx))
17371                    .head()
17372            });
17373
17374            // Update the selection to match the position of the selection inside
17375            // the rename editor.
17376            let snapshot = self.buffer.read(cx).read(cx);
17377            let rename_range = rename.range.to_offset(&snapshot);
17378            let cursor_in_editor = snapshot
17379                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
17380                .min(rename_range.end);
17381            drop(snapshot);
17382
17383            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17384                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
17385            });
17386        } else {
17387            self.refresh_document_highlights(cx);
17388        }
17389
17390        Some(rename)
17391    }
17392
17393    pub fn pending_rename(&self) -> Option<&RenameState> {
17394        self.pending_rename.as_ref()
17395    }
17396
17397    fn format(
17398        &mut self,
17399        _: &Format,
17400        window: &mut Window,
17401        cx: &mut Context<Self>,
17402    ) -> Option<Task<Result<()>>> {
17403        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17404
17405        let project = match &self.project {
17406            Some(project) => project.clone(),
17407            None => return None,
17408        };
17409
17410        Some(self.perform_format(
17411            project,
17412            FormatTrigger::Manual,
17413            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
17414            window,
17415            cx,
17416        ))
17417    }
17418
17419    fn format_selections(
17420        &mut self,
17421        _: &FormatSelections,
17422        window: &mut Window,
17423        cx: &mut Context<Self>,
17424    ) -> Option<Task<Result<()>>> {
17425        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17426
17427        let project = match &self.project {
17428            Some(project) => project.clone(),
17429            None => return None,
17430        };
17431
17432        let ranges = self
17433            .selections
17434            .all_adjusted(&self.display_snapshot(cx))
17435            .into_iter()
17436            .map(|selection| selection.range())
17437            .collect_vec();
17438
17439        Some(self.perform_format(
17440            project,
17441            FormatTrigger::Manual,
17442            FormatTarget::Ranges(ranges),
17443            window,
17444            cx,
17445        ))
17446    }
17447
17448    fn perform_format(
17449        &mut self,
17450        project: Entity<Project>,
17451        trigger: FormatTrigger,
17452        target: FormatTarget,
17453        window: &mut Window,
17454        cx: &mut Context<Self>,
17455    ) -> Task<Result<()>> {
17456        let buffer = self.buffer.clone();
17457        let (buffers, target) = match target {
17458            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
17459            FormatTarget::Ranges(selection_ranges) => {
17460                let multi_buffer = buffer.read(cx);
17461                let snapshot = multi_buffer.read(cx);
17462                let mut buffers = HashSet::default();
17463                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
17464                    BTreeMap::new();
17465                for selection_range in selection_ranges {
17466                    for (buffer, buffer_range, _) in
17467                        snapshot.range_to_buffer_ranges(selection_range)
17468                    {
17469                        let buffer_id = buffer.remote_id();
17470                        let start = buffer.anchor_before(buffer_range.start);
17471                        let end = buffer.anchor_after(buffer_range.end);
17472                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
17473                        buffer_id_to_ranges
17474                            .entry(buffer_id)
17475                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
17476                            .or_insert_with(|| vec![start..end]);
17477                    }
17478                }
17479                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
17480            }
17481        };
17482
17483        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
17484        let selections_prev = transaction_id_prev
17485            .and_then(|transaction_id_prev| {
17486                // default to selections as they were after the last edit, if we have them,
17487                // instead of how they are now.
17488                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
17489                // will take you back to where you made the last edit, instead of staying where you scrolled
17490                self.selection_history
17491                    .transaction(transaction_id_prev)
17492                    .map(|t| t.0.clone())
17493            })
17494            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
17495
17496        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
17497        let format = project.update(cx, |project, cx| {
17498            project.format(buffers, target, true, trigger, cx)
17499        });
17500
17501        cx.spawn_in(window, async move |editor, cx| {
17502            let transaction = futures::select_biased! {
17503                transaction = format.log_err().fuse() => transaction,
17504                () = timeout => {
17505                    log::warn!("timed out waiting for formatting");
17506                    None
17507                }
17508            };
17509
17510            buffer
17511                .update(cx, |buffer, cx| {
17512                    if let Some(transaction) = transaction
17513                        && !buffer.is_singleton()
17514                    {
17515                        buffer.push_transaction(&transaction.0, cx);
17516                    }
17517                    cx.notify();
17518                })
17519                .ok();
17520
17521            if let Some(transaction_id_now) =
17522                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
17523            {
17524                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
17525                if has_new_transaction {
17526                    _ = editor.update(cx, |editor, _| {
17527                        editor
17528                            .selection_history
17529                            .insert_transaction(transaction_id_now, selections_prev);
17530                    });
17531                }
17532            }
17533
17534            Ok(())
17535        })
17536    }
17537
17538    fn organize_imports(
17539        &mut self,
17540        _: &OrganizeImports,
17541        window: &mut Window,
17542        cx: &mut Context<Self>,
17543    ) -> Option<Task<Result<()>>> {
17544        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
17545        let project = match &self.project {
17546            Some(project) => project.clone(),
17547            None => return None,
17548        };
17549        Some(self.perform_code_action_kind(
17550            project,
17551            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
17552            window,
17553            cx,
17554        ))
17555    }
17556
17557    fn perform_code_action_kind(
17558        &mut self,
17559        project: Entity<Project>,
17560        kind: CodeActionKind,
17561        window: &mut Window,
17562        cx: &mut Context<Self>,
17563    ) -> Task<Result<()>> {
17564        let buffer = self.buffer.clone();
17565        let buffers = buffer.read(cx).all_buffers();
17566        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
17567        let apply_action = project.update(cx, |project, cx| {
17568            project.apply_code_action_kind(buffers, kind, true, cx)
17569        });
17570        cx.spawn_in(window, async move |_, cx| {
17571            let transaction = futures::select_biased! {
17572                () = timeout => {
17573                    log::warn!("timed out waiting for executing code action");
17574                    None
17575                }
17576                transaction = apply_action.log_err().fuse() => transaction,
17577            };
17578            buffer
17579                .update(cx, |buffer, cx| {
17580                    // check if we need this
17581                    if let Some(transaction) = transaction
17582                        && !buffer.is_singleton()
17583                    {
17584                        buffer.push_transaction(&transaction.0, cx);
17585                    }
17586                    cx.notify();
17587                })
17588                .ok();
17589            Ok(())
17590        })
17591    }
17592
17593    pub fn restart_language_server(
17594        &mut self,
17595        _: &RestartLanguageServer,
17596        _: &mut Window,
17597        cx: &mut Context<Self>,
17598    ) {
17599        if let Some(project) = self.project.clone() {
17600            self.buffer.update(cx, |multi_buffer, cx| {
17601                project.update(cx, |project, cx| {
17602                    project.restart_language_servers_for_buffers(
17603                        multi_buffer.all_buffers().into_iter().collect(),
17604                        HashSet::default(),
17605                        cx,
17606                    );
17607                });
17608            })
17609        }
17610    }
17611
17612    pub fn stop_language_server(
17613        &mut self,
17614        _: &StopLanguageServer,
17615        _: &mut Window,
17616        cx: &mut Context<Self>,
17617    ) {
17618        if let Some(project) = self.project.clone() {
17619            self.buffer.update(cx, |multi_buffer, cx| {
17620                project.update(cx, |project, cx| {
17621                    project.stop_language_servers_for_buffers(
17622                        multi_buffer.all_buffers().into_iter().collect(),
17623                        HashSet::default(),
17624                        cx,
17625                    );
17626                });
17627            });
17628            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
17629        }
17630    }
17631
17632    fn cancel_language_server_work(
17633        workspace: &mut Workspace,
17634        _: &actions::CancelLanguageServerWork,
17635        _: &mut Window,
17636        cx: &mut Context<Workspace>,
17637    ) {
17638        let project = workspace.project();
17639        let buffers = workspace
17640            .active_item(cx)
17641            .and_then(|item| item.act_as::<Editor>(cx))
17642            .map_or(HashSet::default(), |editor| {
17643                editor.read(cx).buffer.read(cx).all_buffers()
17644            });
17645        project.update(cx, |project, cx| {
17646            project.cancel_language_server_work_for_buffers(buffers, cx);
17647        });
17648    }
17649
17650    fn show_character_palette(
17651        &mut self,
17652        _: &ShowCharacterPalette,
17653        window: &mut Window,
17654        _: &mut Context<Self>,
17655    ) {
17656        window.show_character_palette();
17657    }
17658
17659    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
17660        if !self.diagnostics_enabled() {
17661            return;
17662        }
17663
17664        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
17665            let buffer = self.buffer.read(cx).snapshot(cx);
17666            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
17667            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
17668            let is_valid = buffer
17669                .diagnostics_in_range::<usize>(primary_range_start..primary_range_end)
17670                .any(|entry| {
17671                    entry.diagnostic.is_primary
17672                        && !entry.range.is_empty()
17673                        && entry.range.start == primary_range_start
17674                        && entry.diagnostic.message == active_diagnostics.active_message
17675                });
17676
17677            if !is_valid {
17678                self.dismiss_diagnostics(cx);
17679            }
17680        }
17681    }
17682
17683    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
17684        match &self.active_diagnostics {
17685            ActiveDiagnostic::Group(group) => Some(group),
17686            _ => None,
17687        }
17688    }
17689
17690    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
17691        if !self.diagnostics_enabled() {
17692            return;
17693        }
17694        self.dismiss_diagnostics(cx);
17695        self.active_diagnostics = ActiveDiagnostic::All;
17696    }
17697
17698    fn activate_diagnostics(
17699        &mut self,
17700        buffer_id: BufferId,
17701        diagnostic: DiagnosticEntryRef<'_, usize>,
17702        window: &mut Window,
17703        cx: &mut Context<Self>,
17704    ) {
17705        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17706            return;
17707        }
17708        self.dismiss_diagnostics(cx);
17709        let snapshot = self.snapshot(window, cx);
17710        let buffer = self.buffer.read(cx).snapshot(cx);
17711        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
17712            return;
17713        };
17714
17715        let diagnostic_group = buffer
17716            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
17717            .collect::<Vec<_>>();
17718
17719        let blocks =
17720            renderer.render_group(diagnostic_group, buffer_id, snapshot, cx.weak_entity(), cx);
17721
17722        let blocks = self.display_map.update(cx, |display_map, cx| {
17723            display_map.insert_blocks(blocks, cx).into_iter().collect()
17724        });
17725        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
17726            active_range: buffer.anchor_before(diagnostic.range.start)
17727                ..buffer.anchor_after(diagnostic.range.end),
17728            active_message: diagnostic.diagnostic.message.clone(),
17729            group_id: diagnostic.diagnostic.group_id,
17730            blocks,
17731        });
17732        cx.notify();
17733    }
17734
17735    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
17736        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
17737            return;
17738        };
17739
17740        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
17741        if let ActiveDiagnostic::Group(group) = prev {
17742            self.display_map.update(cx, |display_map, cx| {
17743                display_map.remove_blocks(group.blocks, cx);
17744            });
17745            cx.notify();
17746        }
17747    }
17748
17749    /// Disable inline diagnostics rendering for this editor.
17750    pub fn disable_inline_diagnostics(&mut self) {
17751        self.inline_diagnostics_enabled = false;
17752        self.inline_diagnostics_update = Task::ready(());
17753        self.inline_diagnostics.clear();
17754    }
17755
17756    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
17757        self.diagnostics_enabled = false;
17758        self.dismiss_diagnostics(cx);
17759        self.inline_diagnostics_update = Task::ready(());
17760        self.inline_diagnostics.clear();
17761    }
17762
17763    pub fn disable_word_completions(&mut self) {
17764        self.word_completions_enabled = false;
17765    }
17766
17767    pub fn diagnostics_enabled(&self) -> bool {
17768        self.diagnostics_enabled && self.mode.is_full()
17769    }
17770
17771    pub fn inline_diagnostics_enabled(&self) -> bool {
17772        self.inline_diagnostics_enabled && self.diagnostics_enabled()
17773    }
17774
17775    pub fn show_inline_diagnostics(&self) -> bool {
17776        self.show_inline_diagnostics
17777    }
17778
17779    pub fn toggle_inline_diagnostics(
17780        &mut self,
17781        _: &ToggleInlineDiagnostics,
17782        window: &mut Window,
17783        cx: &mut Context<Editor>,
17784    ) {
17785        self.show_inline_diagnostics = !self.show_inline_diagnostics;
17786        self.refresh_inline_diagnostics(false, window, cx);
17787    }
17788
17789    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
17790        self.diagnostics_max_severity = severity;
17791        self.display_map.update(cx, |display_map, _| {
17792            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
17793        });
17794    }
17795
17796    pub fn toggle_diagnostics(
17797        &mut self,
17798        _: &ToggleDiagnostics,
17799        window: &mut Window,
17800        cx: &mut Context<Editor>,
17801    ) {
17802        if !self.diagnostics_enabled() {
17803            return;
17804        }
17805
17806        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17807            EditorSettings::get_global(cx)
17808                .diagnostics_max_severity
17809                .filter(|severity| severity != &DiagnosticSeverity::Off)
17810                .unwrap_or(DiagnosticSeverity::Hint)
17811        } else {
17812            DiagnosticSeverity::Off
17813        };
17814        self.set_max_diagnostics_severity(new_severity, cx);
17815        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
17816            self.active_diagnostics = ActiveDiagnostic::None;
17817            self.inline_diagnostics_update = Task::ready(());
17818            self.inline_diagnostics.clear();
17819        } else {
17820            self.refresh_inline_diagnostics(false, window, cx);
17821        }
17822
17823        cx.notify();
17824    }
17825
17826    pub fn toggle_minimap(
17827        &mut self,
17828        _: &ToggleMinimap,
17829        window: &mut Window,
17830        cx: &mut Context<Editor>,
17831    ) {
17832        if self.supports_minimap(cx) {
17833            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
17834        }
17835    }
17836
17837    fn refresh_inline_diagnostics(
17838        &mut self,
17839        debounce: bool,
17840        window: &mut Window,
17841        cx: &mut Context<Self>,
17842    ) {
17843        let max_severity = ProjectSettings::get_global(cx)
17844            .diagnostics
17845            .inline
17846            .max_severity
17847            .unwrap_or(self.diagnostics_max_severity);
17848
17849        if !self.inline_diagnostics_enabled()
17850            || !self.diagnostics_enabled()
17851            || !self.show_inline_diagnostics
17852            || max_severity == DiagnosticSeverity::Off
17853        {
17854            self.inline_diagnostics_update = Task::ready(());
17855            self.inline_diagnostics.clear();
17856            return;
17857        }
17858
17859        let debounce_ms = ProjectSettings::get_global(cx)
17860            .diagnostics
17861            .inline
17862            .update_debounce_ms;
17863        let debounce = if debounce && debounce_ms > 0 {
17864            Some(Duration::from_millis(debounce_ms))
17865        } else {
17866            None
17867        };
17868        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
17869            if let Some(debounce) = debounce {
17870                cx.background_executor().timer(debounce).await;
17871            }
17872            let Some(snapshot) = editor.upgrade().and_then(|editor| {
17873                editor
17874                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
17875                    .ok()
17876            }) else {
17877                return;
17878            };
17879
17880            let new_inline_diagnostics = cx
17881                .background_spawn(async move {
17882                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
17883                    for diagnostic_entry in snapshot.diagnostics_in_range(0..snapshot.len()) {
17884                        let message = diagnostic_entry
17885                            .diagnostic
17886                            .message
17887                            .split_once('\n')
17888                            .map(|(line, _)| line)
17889                            .map(SharedString::new)
17890                            .unwrap_or_else(|| {
17891                                SharedString::new(&*diagnostic_entry.diagnostic.message)
17892                            });
17893                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
17894                        let (Ok(i) | Err(i)) = inline_diagnostics
17895                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
17896                        inline_diagnostics.insert(
17897                            i,
17898                            (
17899                                start_anchor,
17900                                InlineDiagnostic {
17901                                    message,
17902                                    group_id: diagnostic_entry.diagnostic.group_id,
17903                                    start: diagnostic_entry.range.start.to_point(&snapshot),
17904                                    is_primary: diagnostic_entry.diagnostic.is_primary,
17905                                    severity: diagnostic_entry.diagnostic.severity,
17906                                },
17907                            ),
17908                        );
17909                    }
17910                    inline_diagnostics
17911                })
17912                .await;
17913
17914            editor
17915                .update(cx, |editor, cx| {
17916                    editor.inline_diagnostics = new_inline_diagnostics;
17917                    cx.notify();
17918                })
17919                .ok();
17920        });
17921    }
17922
17923    fn pull_diagnostics(
17924        &mut self,
17925        buffer_id: Option<BufferId>,
17926        window: &Window,
17927        cx: &mut Context<Self>,
17928    ) -> Option<()> {
17929        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
17930            return None;
17931        }
17932        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
17933            .diagnostics
17934            .lsp_pull_diagnostics;
17935        if !pull_diagnostics_settings.enabled {
17936            return None;
17937        }
17938        let project = self.project()?.downgrade();
17939        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
17940        let mut buffers = self.buffer.read(cx).all_buffers();
17941        buffers.retain(|buffer| {
17942            let buffer_id_to_retain = buffer.read(cx).remote_id();
17943            buffer_id.is_none_or(|buffer_id| buffer_id == buffer_id_to_retain)
17944                && self.registered_buffers.contains_key(&buffer_id_to_retain)
17945        });
17946        if buffers.is_empty() {
17947            self.pull_diagnostics_task = Task::ready(());
17948            return None;
17949        }
17950
17951        self.pull_diagnostics_task = cx.spawn_in(window, async move |editor, cx| {
17952            cx.background_executor().timer(debounce).await;
17953
17954            let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
17955                buffers
17956                    .into_iter()
17957                    .filter_map(|buffer| {
17958                        project
17959                            .update(cx, |project, cx| {
17960                                project.lsp_store().update(cx, |lsp_store, cx| {
17961                                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
17962                                })
17963                            })
17964                            .ok()
17965                    })
17966                    .collect::<FuturesUnordered<_>>()
17967            }) else {
17968                return;
17969            };
17970
17971            while let Some(pull_task) = pull_diagnostics_tasks.next().await {
17972                match pull_task {
17973                    Ok(()) => {
17974                        if editor
17975                            .update_in(cx, |editor, window, cx| {
17976                                editor.update_diagnostics_state(window, cx);
17977                            })
17978                            .is_err()
17979                        {
17980                            return;
17981                        }
17982                    }
17983                    Err(e) => log::error!("Failed to update project diagnostics: {e:#}"),
17984                }
17985            }
17986        });
17987
17988        Some(())
17989    }
17990
17991    pub fn set_selections_from_remote(
17992        &mut self,
17993        selections: Vec<Selection<Anchor>>,
17994        pending_selection: Option<Selection<Anchor>>,
17995        window: &mut Window,
17996        cx: &mut Context<Self>,
17997    ) {
17998        let old_cursor_position = self.selections.newest_anchor().head();
17999        self.selections.change_with(cx, |s| {
18000            s.select_anchors(selections);
18001            if let Some(pending_selection) = pending_selection {
18002                s.set_pending(pending_selection, SelectMode::Character);
18003            } else {
18004                s.clear_pending();
18005            }
18006        });
18007        self.selections_did_change(
18008            false,
18009            &old_cursor_position,
18010            SelectionEffects::default(),
18011            window,
18012            cx,
18013        );
18014    }
18015
18016    pub fn transact(
18017        &mut self,
18018        window: &mut Window,
18019        cx: &mut Context<Self>,
18020        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
18021    ) -> Option<TransactionId> {
18022        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18023            this.start_transaction_at(Instant::now(), window, cx);
18024            update(this, window, cx);
18025            this.end_transaction_at(Instant::now(), cx)
18026        })
18027    }
18028
18029    pub fn start_transaction_at(
18030        &mut self,
18031        now: Instant,
18032        window: &mut Window,
18033        cx: &mut Context<Self>,
18034    ) -> Option<TransactionId> {
18035        self.end_selection(window, cx);
18036        if let Some(tx_id) = self
18037            .buffer
18038            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18039        {
18040            self.selection_history
18041                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18042            cx.emit(EditorEvent::TransactionBegun {
18043                transaction_id: tx_id,
18044            });
18045            Some(tx_id)
18046        } else {
18047            None
18048        }
18049    }
18050
18051    pub fn end_transaction_at(
18052        &mut self,
18053        now: Instant,
18054        cx: &mut Context<Self>,
18055    ) -> Option<TransactionId> {
18056        if let Some(transaction_id) = self
18057            .buffer
18058            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18059        {
18060            if let Some((_, end_selections)) =
18061                self.selection_history.transaction_mut(transaction_id)
18062            {
18063                *end_selections = Some(self.selections.disjoint_anchors_arc());
18064            } else {
18065                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18066            }
18067
18068            cx.emit(EditorEvent::Edited { transaction_id });
18069            Some(transaction_id)
18070        } else {
18071            None
18072        }
18073    }
18074
18075    pub fn modify_transaction_selection_history(
18076        &mut self,
18077        transaction_id: TransactionId,
18078        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
18079    ) -> bool {
18080        self.selection_history
18081            .transaction_mut(transaction_id)
18082            .map(modify)
18083            .is_some()
18084    }
18085
18086    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
18087        if self.selection_mark_mode {
18088            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18089                s.move_with(|_, sel| {
18090                    sel.collapse_to(sel.head(), SelectionGoal::None);
18091                });
18092            })
18093        }
18094        self.selection_mark_mode = true;
18095        cx.notify();
18096    }
18097
18098    pub fn swap_selection_ends(
18099        &mut self,
18100        _: &actions::SwapSelectionEnds,
18101        window: &mut Window,
18102        cx: &mut Context<Self>,
18103    ) {
18104        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18105            s.move_with(|_, sel| {
18106                if sel.start != sel.end {
18107                    sel.reversed = !sel.reversed
18108                }
18109            });
18110        });
18111        self.request_autoscroll(Autoscroll::newest(), cx);
18112        cx.notify();
18113    }
18114
18115    pub fn toggle_focus(
18116        workspace: &mut Workspace,
18117        _: &actions::ToggleFocus,
18118        window: &mut Window,
18119        cx: &mut Context<Workspace>,
18120    ) {
18121        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
18122            return;
18123        };
18124        workspace.activate_item(&item, true, true, window, cx);
18125    }
18126
18127    pub fn toggle_fold(
18128        &mut self,
18129        _: &actions::ToggleFold,
18130        window: &mut Window,
18131        cx: &mut Context<Self>,
18132    ) {
18133        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18134            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18135            let selection = self.selections.newest::<Point>(&display_map);
18136
18137            let range = if selection.is_empty() {
18138                let point = selection.head().to_display_point(&display_map);
18139                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18140                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18141                    .to_point(&display_map);
18142                start..end
18143            } else {
18144                selection.range()
18145            };
18146            if display_map.folds_in_range(range).next().is_some() {
18147                self.unfold_lines(&Default::default(), window, cx)
18148            } else {
18149                self.fold(&Default::default(), window, cx)
18150            }
18151        } else {
18152            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18153            let buffer_ids: HashSet<_> = self
18154                .selections
18155                .disjoint_anchor_ranges()
18156                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18157                .collect();
18158
18159            let should_unfold = buffer_ids
18160                .iter()
18161                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18162
18163            for buffer_id in buffer_ids {
18164                if should_unfold {
18165                    self.unfold_buffer(buffer_id, cx);
18166                } else {
18167                    self.fold_buffer(buffer_id, cx);
18168                }
18169            }
18170        }
18171    }
18172
18173    pub fn toggle_fold_recursive(
18174        &mut self,
18175        _: &actions::ToggleFoldRecursive,
18176        window: &mut Window,
18177        cx: &mut Context<Self>,
18178    ) {
18179        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
18180
18181        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18182        let range = if selection.is_empty() {
18183            let point = selection.head().to_display_point(&display_map);
18184            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
18185            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
18186                .to_point(&display_map);
18187            start..end
18188        } else {
18189            selection.range()
18190        };
18191        if display_map.folds_in_range(range).next().is_some() {
18192            self.unfold_recursive(&Default::default(), window, cx)
18193        } else {
18194            self.fold_recursive(&Default::default(), window, cx)
18195        }
18196    }
18197
18198    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
18199        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18200            let mut to_fold = Vec::new();
18201            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18202            let selections = self.selections.all_adjusted(&display_map);
18203
18204            for selection in selections {
18205                let range = selection.range().sorted();
18206                let buffer_start_row = range.start.row;
18207
18208                if range.start.row != range.end.row {
18209                    let mut found = false;
18210                    let mut row = range.start.row;
18211                    while row <= range.end.row {
18212                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18213                        {
18214                            found = true;
18215                            row = crease.range().end.row + 1;
18216                            to_fold.push(crease);
18217                        } else {
18218                            row += 1
18219                        }
18220                    }
18221                    if found {
18222                        continue;
18223                    }
18224                }
18225
18226                for row in (0..=range.start.row).rev() {
18227                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
18228                        && crease.range().end.row >= buffer_start_row
18229                    {
18230                        to_fold.push(crease);
18231                        if row <= range.start.row {
18232                            break;
18233                        }
18234                    }
18235                }
18236            }
18237
18238            self.fold_creases(to_fold, true, window, cx);
18239        } else {
18240            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18241            let buffer_ids = self
18242                .selections
18243                .disjoint_anchor_ranges()
18244                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18245                .collect::<HashSet<_>>();
18246            for buffer_id in buffer_ids {
18247                self.fold_buffer(buffer_id, cx);
18248            }
18249        }
18250    }
18251
18252    pub fn toggle_fold_all(
18253        &mut self,
18254        _: &actions::ToggleFoldAll,
18255        window: &mut Window,
18256        cx: &mut Context<Self>,
18257    ) {
18258        if self.buffer.read(cx).is_singleton() {
18259            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18260            let has_folds = display_map
18261                .folds_in_range(0..display_map.buffer_snapshot().len())
18262                .next()
18263                .is_some();
18264
18265            if has_folds {
18266                self.unfold_all(&actions::UnfoldAll, window, cx);
18267            } else {
18268                self.fold_all(&actions::FoldAll, window, cx);
18269            }
18270        } else {
18271            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
18272            let should_unfold = buffer_ids
18273                .iter()
18274                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
18275
18276            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18277                editor
18278                    .update_in(cx, |editor, _, cx| {
18279                        for buffer_id in buffer_ids {
18280                            if should_unfold {
18281                                editor.unfold_buffer(buffer_id, cx);
18282                            } else {
18283                                editor.fold_buffer(buffer_id, cx);
18284                            }
18285                        }
18286                    })
18287                    .ok();
18288            });
18289        }
18290    }
18291
18292    fn fold_at_level(
18293        &mut self,
18294        fold_at: &FoldAtLevel,
18295        window: &mut Window,
18296        cx: &mut Context<Self>,
18297    ) {
18298        if !self.buffer.read(cx).is_singleton() {
18299            return;
18300        }
18301
18302        let fold_at_level = fold_at.0;
18303        let snapshot = self.buffer.read(cx).snapshot(cx);
18304        let mut to_fold = Vec::new();
18305        let mut stack = vec![(0, snapshot.max_row().0, 1)];
18306
18307        let row_ranges_to_keep: Vec<Range<u32>> = self
18308            .selections
18309            .all::<Point>(&self.display_snapshot(cx))
18310            .into_iter()
18311            .map(|sel| sel.start.row..sel.end.row)
18312            .collect();
18313
18314        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
18315            while start_row < end_row {
18316                match self
18317                    .snapshot(window, cx)
18318                    .crease_for_buffer_row(MultiBufferRow(start_row))
18319                {
18320                    Some(crease) => {
18321                        let nested_start_row = crease.range().start.row + 1;
18322                        let nested_end_row = crease.range().end.row;
18323
18324                        if current_level < fold_at_level {
18325                            stack.push((nested_start_row, nested_end_row, current_level + 1));
18326                        } else if current_level == fold_at_level {
18327                            // Fold iff there is no selection completely contained within the fold region
18328                            if !row_ranges_to_keep.iter().any(|selection| {
18329                                selection.end >= nested_start_row
18330                                    && selection.start <= nested_end_row
18331                            }) {
18332                                to_fold.push(crease);
18333                            }
18334                        }
18335
18336                        start_row = nested_end_row + 1;
18337                    }
18338                    None => start_row += 1,
18339                }
18340            }
18341        }
18342
18343        self.fold_creases(to_fold, true, window, cx);
18344    }
18345
18346    pub fn fold_at_level_1(
18347        &mut self,
18348        _: &actions::FoldAtLevel1,
18349        window: &mut Window,
18350        cx: &mut Context<Self>,
18351    ) {
18352        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
18353    }
18354
18355    pub fn fold_at_level_2(
18356        &mut self,
18357        _: &actions::FoldAtLevel2,
18358        window: &mut Window,
18359        cx: &mut Context<Self>,
18360    ) {
18361        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
18362    }
18363
18364    pub fn fold_at_level_3(
18365        &mut self,
18366        _: &actions::FoldAtLevel3,
18367        window: &mut Window,
18368        cx: &mut Context<Self>,
18369    ) {
18370        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
18371    }
18372
18373    pub fn fold_at_level_4(
18374        &mut self,
18375        _: &actions::FoldAtLevel4,
18376        window: &mut Window,
18377        cx: &mut Context<Self>,
18378    ) {
18379        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
18380    }
18381
18382    pub fn fold_at_level_5(
18383        &mut self,
18384        _: &actions::FoldAtLevel5,
18385        window: &mut Window,
18386        cx: &mut Context<Self>,
18387    ) {
18388        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
18389    }
18390
18391    pub fn fold_at_level_6(
18392        &mut self,
18393        _: &actions::FoldAtLevel6,
18394        window: &mut Window,
18395        cx: &mut Context<Self>,
18396    ) {
18397        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
18398    }
18399
18400    pub fn fold_at_level_7(
18401        &mut self,
18402        _: &actions::FoldAtLevel7,
18403        window: &mut Window,
18404        cx: &mut Context<Self>,
18405    ) {
18406        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
18407    }
18408
18409    pub fn fold_at_level_8(
18410        &mut self,
18411        _: &actions::FoldAtLevel8,
18412        window: &mut Window,
18413        cx: &mut Context<Self>,
18414    ) {
18415        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
18416    }
18417
18418    pub fn fold_at_level_9(
18419        &mut self,
18420        _: &actions::FoldAtLevel9,
18421        window: &mut Window,
18422        cx: &mut Context<Self>,
18423    ) {
18424        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
18425    }
18426
18427    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
18428        if self.buffer.read(cx).is_singleton() {
18429            let mut fold_ranges = Vec::new();
18430            let snapshot = self.buffer.read(cx).snapshot(cx);
18431
18432            for row in 0..snapshot.max_row().0 {
18433                if let Some(foldable_range) = self
18434                    .snapshot(window, cx)
18435                    .crease_for_buffer_row(MultiBufferRow(row))
18436                {
18437                    fold_ranges.push(foldable_range);
18438                }
18439            }
18440
18441            self.fold_creases(fold_ranges, true, window, cx);
18442        } else {
18443            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
18444                editor
18445                    .update_in(cx, |editor, _, cx| {
18446                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18447                            editor.fold_buffer(buffer_id, cx);
18448                        }
18449                    })
18450                    .ok();
18451            });
18452        }
18453    }
18454
18455    pub fn fold_function_bodies(
18456        &mut self,
18457        _: &actions::FoldFunctionBodies,
18458        window: &mut Window,
18459        cx: &mut Context<Self>,
18460    ) {
18461        let snapshot = self.buffer.read(cx).snapshot(cx);
18462
18463        let ranges = snapshot
18464            .text_object_ranges(0..snapshot.len(), TreeSitterOptions::default())
18465            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
18466            .collect::<Vec<_>>();
18467
18468        let creases = ranges
18469            .into_iter()
18470            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
18471            .collect();
18472
18473        self.fold_creases(creases, true, window, cx);
18474    }
18475
18476    pub fn fold_recursive(
18477        &mut self,
18478        _: &actions::FoldRecursive,
18479        window: &mut Window,
18480        cx: &mut Context<Self>,
18481    ) {
18482        let mut to_fold = Vec::new();
18483        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18484        let selections = self.selections.all_adjusted(&display_map);
18485
18486        for selection in selections {
18487            let range = selection.range().sorted();
18488            let buffer_start_row = range.start.row;
18489
18490            if range.start.row != range.end.row {
18491                let mut found = false;
18492                for row in range.start.row..=range.end.row {
18493                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18494                        found = true;
18495                        to_fold.push(crease);
18496                    }
18497                }
18498                if found {
18499                    continue;
18500                }
18501            }
18502
18503            for row in (0..=range.start.row).rev() {
18504                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
18505                    if crease.range().end.row >= buffer_start_row {
18506                        to_fold.push(crease);
18507                    } else {
18508                        break;
18509                    }
18510                }
18511            }
18512        }
18513
18514        self.fold_creases(to_fold, true, window, cx);
18515    }
18516
18517    pub fn fold_at(
18518        &mut self,
18519        buffer_row: MultiBufferRow,
18520        window: &mut Window,
18521        cx: &mut Context<Self>,
18522    ) {
18523        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18524
18525        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
18526            let autoscroll = self
18527                .selections
18528                .all::<Point>(&display_map)
18529                .iter()
18530                .any(|selection| crease.range().overlaps(&selection.range()));
18531
18532            self.fold_creases(vec![crease], autoscroll, window, cx);
18533        }
18534    }
18535
18536    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
18537        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
18538            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18539            let buffer = display_map.buffer_snapshot();
18540            let selections = self.selections.all::<Point>(&display_map);
18541            let ranges = selections
18542                .iter()
18543                .map(|s| {
18544                    let range = s.display_range(&display_map).sorted();
18545                    let mut start = range.start.to_point(&display_map);
18546                    let mut end = range.end.to_point(&display_map);
18547                    start.column = 0;
18548                    end.column = buffer.line_len(MultiBufferRow(end.row));
18549                    start..end
18550                })
18551                .collect::<Vec<_>>();
18552
18553            self.unfold_ranges(&ranges, true, true, cx);
18554        } else {
18555            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
18556            let buffer_ids = self
18557                .selections
18558                .disjoint_anchor_ranges()
18559                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
18560                .collect::<HashSet<_>>();
18561            for buffer_id in buffer_ids {
18562                self.unfold_buffer(buffer_id, cx);
18563            }
18564        }
18565    }
18566
18567    pub fn unfold_recursive(
18568        &mut self,
18569        _: &UnfoldRecursive,
18570        _window: &mut Window,
18571        cx: &mut Context<Self>,
18572    ) {
18573        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18574        let selections = self.selections.all::<Point>(&display_map);
18575        let ranges = selections
18576            .iter()
18577            .map(|s| {
18578                let mut range = s.display_range(&display_map).sorted();
18579                *range.start.column_mut() = 0;
18580                *range.end.column_mut() = display_map.line_len(range.end.row());
18581                let start = range.start.to_point(&display_map);
18582                let end = range.end.to_point(&display_map);
18583                start..end
18584            })
18585            .collect::<Vec<_>>();
18586
18587        self.unfold_ranges(&ranges, true, true, cx);
18588    }
18589
18590    pub fn unfold_at(
18591        &mut self,
18592        buffer_row: MultiBufferRow,
18593        _window: &mut Window,
18594        cx: &mut Context<Self>,
18595    ) {
18596        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18597
18598        let intersection_range = Point::new(buffer_row.0, 0)
18599            ..Point::new(
18600                buffer_row.0,
18601                display_map.buffer_snapshot().line_len(buffer_row),
18602            );
18603
18604        let autoscroll = self
18605            .selections
18606            .all::<Point>(&display_map)
18607            .iter()
18608            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
18609
18610        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
18611    }
18612
18613    pub fn unfold_all(
18614        &mut self,
18615        _: &actions::UnfoldAll,
18616        _window: &mut Window,
18617        cx: &mut Context<Self>,
18618    ) {
18619        if self.buffer.read(cx).is_singleton() {
18620            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18621            self.unfold_ranges(&[0..display_map.buffer_snapshot().len()], true, true, cx);
18622        } else {
18623            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
18624                editor
18625                    .update(cx, |editor, cx| {
18626                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
18627                            editor.unfold_buffer(buffer_id, cx);
18628                        }
18629                    })
18630                    .ok();
18631            });
18632        }
18633    }
18634
18635    pub fn fold_selected_ranges(
18636        &mut self,
18637        _: &FoldSelectedRanges,
18638        window: &mut Window,
18639        cx: &mut Context<Self>,
18640    ) {
18641        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18642        let selections = self.selections.all_adjusted(&display_map);
18643        let ranges = selections
18644            .into_iter()
18645            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
18646            .collect::<Vec<_>>();
18647        self.fold_creases(ranges, true, window, cx);
18648    }
18649
18650    pub fn fold_ranges<T: ToOffset + Clone>(
18651        &mut self,
18652        ranges: Vec<Range<T>>,
18653        auto_scroll: bool,
18654        window: &mut Window,
18655        cx: &mut Context<Self>,
18656    ) {
18657        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
18658        let ranges = ranges
18659            .into_iter()
18660            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
18661            .collect::<Vec<_>>();
18662        self.fold_creases(ranges, auto_scroll, window, cx);
18663    }
18664
18665    pub fn fold_creases<T: ToOffset + Clone>(
18666        &mut self,
18667        creases: Vec<Crease<T>>,
18668        auto_scroll: bool,
18669        _window: &mut Window,
18670        cx: &mut Context<Self>,
18671    ) {
18672        if creases.is_empty() {
18673            return;
18674        }
18675
18676        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
18677
18678        if auto_scroll {
18679            self.request_autoscroll(Autoscroll::fit(), cx);
18680        }
18681
18682        cx.notify();
18683
18684        self.scrollbar_marker_state.dirty = true;
18685        self.folds_did_change(cx);
18686    }
18687
18688    /// Removes any folds whose ranges intersect any of the given ranges.
18689    pub fn unfold_ranges<T: ToOffset + Clone>(
18690        &mut self,
18691        ranges: &[Range<T>],
18692        inclusive: bool,
18693        auto_scroll: bool,
18694        cx: &mut Context<Self>,
18695    ) {
18696        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18697            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
18698        });
18699        self.folds_did_change(cx);
18700    }
18701
18702    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18703        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
18704            return;
18705        }
18706        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18707        self.display_map.update(cx, |display_map, cx| {
18708            display_map.fold_buffers([buffer_id], cx)
18709        });
18710        cx.emit(EditorEvent::BufferFoldToggled {
18711            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
18712            folded: true,
18713        });
18714        cx.notify();
18715    }
18716
18717    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18718        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
18719            return;
18720        }
18721        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
18722        self.display_map.update(cx, |display_map, cx| {
18723            display_map.unfold_buffers([buffer_id], cx);
18724        });
18725        cx.emit(EditorEvent::BufferFoldToggled {
18726            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
18727            folded: false,
18728        });
18729        cx.notify();
18730    }
18731
18732    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
18733        self.display_map.read(cx).is_buffer_folded(buffer)
18734    }
18735
18736    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
18737        self.display_map.read(cx).folded_buffers()
18738    }
18739
18740    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
18741        self.display_map.update(cx, |display_map, cx| {
18742            display_map.disable_header_for_buffer(buffer_id, cx);
18743        });
18744        cx.notify();
18745    }
18746
18747    /// Removes any folds with the given ranges.
18748    pub fn remove_folds_with_type<T: ToOffset + Clone>(
18749        &mut self,
18750        ranges: &[Range<T>],
18751        type_id: TypeId,
18752        auto_scroll: bool,
18753        cx: &mut Context<Self>,
18754    ) {
18755        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
18756            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
18757        });
18758        self.folds_did_change(cx);
18759    }
18760
18761    fn remove_folds_with<T: ToOffset + Clone>(
18762        &mut self,
18763        ranges: &[Range<T>],
18764        auto_scroll: bool,
18765        cx: &mut Context<Self>,
18766        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
18767    ) {
18768        if ranges.is_empty() {
18769            return;
18770        }
18771
18772        let mut buffers_affected = HashSet::default();
18773        let multi_buffer = self.buffer().read(cx);
18774        for range in ranges {
18775            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
18776                buffers_affected.insert(buffer.read(cx).remote_id());
18777            };
18778        }
18779
18780        self.display_map.update(cx, update);
18781
18782        if auto_scroll {
18783            self.request_autoscroll(Autoscroll::fit(), cx);
18784        }
18785
18786        cx.notify();
18787        self.scrollbar_marker_state.dirty = true;
18788        self.active_indent_guides_state.dirty = true;
18789    }
18790
18791    pub fn update_renderer_widths(
18792        &mut self,
18793        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
18794        cx: &mut Context<Self>,
18795    ) -> bool {
18796        self.display_map
18797            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
18798    }
18799
18800    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
18801        self.display_map.read(cx).fold_placeholder.clone()
18802    }
18803
18804    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
18805        self.buffer.update(cx, |buffer, cx| {
18806            buffer.set_all_diff_hunks_expanded(cx);
18807        });
18808    }
18809
18810    pub fn expand_all_diff_hunks(
18811        &mut self,
18812        _: &ExpandAllDiffHunks,
18813        _window: &mut Window,
18814        cx: &mut Context<Self>,
18815    ) {
18816        self.buffer.update(cx, |buffer, cx| {
18817            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18818        });
18819    }
18820
18821    pub fn collapse_all_diff_hunks(
18822        &mut self,
18823        _: &CollapseAllDiffHunks,
18824        _window: &mut Window,
18825        cx: &mut Context<Self>,
18826    ) {
18827        self.buffer.update(cx, |buffer, cx| {
18828            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
18829        });
18830    }
18831
18832    pub fn toggle_selected_diff_hunks(
18833        &mut self,
18834        _: &ToggleSelectedDiffHunks,
18835        _window: &mut Window,
18836        cx: &mut Context<Self>,
18837    ) {
18838        let ranges: Vec<_> = self
18839            .selections
18840            .disjoint_anchors()
18841            .iter()
18842            .map(|s| s.range())
18843            .collect();
18844        self.toggle_diff_hunks_in_ranges(ranges, cx);
18845    }
18846
18847    pub fn diff_hunks_in_ranges<'a>(
18848        &'a self,
18849        ranges: &'a [Range<Anchor>],
18850        buffer: &'a MultiBufferSnapshot,
18851    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
18852        ranges.iter().flat_map(move |range| {
18853            let end_excerpt_id = range.end.excerpt_id;
18854            let range = range.to_point(buffer);
18855            let mut peek_end = range.end;
18856            if range.end.row < buffer.max_row().0 {
18857                peek_end = Point::new(range.end.row + 1, 0);
18858            }
18859            buffer
18860                .diff_hunks_in_range(range.start..peek_end)
18861                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
18862        })
18863    }
18864
18865    pub fn has_stageable_diff_hunks_in_ranges(
18866        &self,
18867        ranges: &[Range<Anchor>],
18868        snapshot: &MultiBufferSnapshot,
18869    ) -> bool {
18870        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
18871        hunks.any(|hunk| hunk.status().has_secondary_hunk())
18872    }
18873
18874    pub fn toggle_staged_selected_diff_hunks(
18875        &mut self,
18876        _: &::git::ToggleStaged,
18877        _: &mut Window,
18878        cx: &mut Context<Self>,
18879    ) {
18880        let snapshot = self.buffer.read(cx).snapshot(cx);
18881        let ranges: Vec<_> = self
18882            .selections
18883            .disjoint_anchors()
18884            .iter()
18885            .map(|s| s.range())
18886            .collect();
18887        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
18888        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18889    }
18890
18891    pub fn set_render_diff_hunk_controls(
18892        &mut self,
18893        render_diff_hunk_controls: RenderDiffHunkControlsFn,
18894        cx: &mut Context<Self>,
18895    ) {
18896        self.render_diff_hunk_controls = render_diff_hunk_controls;
18897        cx.notify();
18898    }
18899
18900    pub fn stage_and_next(
18901        &mut self,
18902        _: &::git::StageAndNext,
18903        window: &mut Window,
18904        cx: &mut Context<Self>,
18905    ) {
18906        self.do_stage_or_unstage_and_next(true, window, cx);
18907    }
18908
18909    pub fn unstage_and_next(
18910        &mut self,
18911        _: &::git::UnstageAndNext,
18912        window: &mut Window,
18913        cx: &mut Context<Self>,
18914    ) {
18915        self.do_stage_or_unstage_and_next(false, window, cx);
18916    }
18917
18918    pub fn stage_or_unstage_diff_hunks(
18919        &mut self,
18920        stage: bool,
18921        ranges: Vec<Range<Anchor>>,
18922        cx: &mut Context<Self>,
18923    ) {
18924        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
18925        cx.spawn(async move |this, cx| {
18926            task.await?;
18927            this.update(cx, |this, cx| {
18928                let snapshot = this.buffer.read(cx).snapshot(cx);
18929                let chunk_by = this
18930                    .diff_hunks_in_ranges(&ranges, &snapshot)
18931                    .chunk_by(|hunk| hunk.buffer_id);
18932                for (buffer_id, hunks) in &chunk_by {
18933                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
18934                }
18935            })
18936        })
18937        .detach_and_log_err(cx);
18938    }
18939
18940    fn save_buffers_for_ranges_if_needed(
18941        &mut self,
18942        ranges: &[Range<Anchor>],
18943        cx: &mut Context<Editor>,
18944    ) -> Task<Result<()>> {
18945        let multibuffer = self.buffer.read(cx);
18946        let snapshot = multibuffer.read(cx);
18947        let buffer_ids: HashSet<_> = ranges
18948            .iter()
18949            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
18950            .collect();
18951        drop(snapshot);
18952
18953        let mut buffers = HashSet::default();
18954        for buffer_id in buffer_ids {
18955            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
18956                let buffer = buffer_entity.read(cx);
18957                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
18958                {
18959                    buffers.insert(buffer_entity);
18960                }
18961            }
18962        }
18963
18964        if let Some(project) = &self.project {
18965            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
18966        } else {
18967            Task::ready(Ok(()))
18968        }
18969    }
18970
18971    fn do_stage_or_unstage_and_next(
18972        &mut self,
18973        stage: bool,
18974        window: &mut Window,
18975        cx: &mut Context<Self>,
18976    ) {
18977        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
18978
18979        if ranges.iter().any(|range| range.start != range.end) {
18980            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18981            return;
18982        }
18983
18984        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
18985        let snapshot = self.snapshot(window, cx);
18986        let position = self
18987            .selections
18988            .newest::<Point>(&snapshot.display_snapshot)
18989            .head();
18990        let mut row = snapshot
18991            .buffer_snapshot()
18992            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
18993            .find(|hunk| hunk.row_range.start.0 > position.row)
18994            .map(|hunk| hunk.row_range.start);
18995
18996        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
18997        // Outside of the project diff editor, wrap around to the beginning.
18998        if !all_diff_hunks_expanded {
18999            row = row.or_else(|| {
19000                snapshot
19001                    .buffer_snapshot()
19002                    .diff_hunks_in_range(Point::zero()..position)
19003                    .find(|hunk| hunk.row_range.end.0 < position.row)
19004                    .map(|hunk| hunk.row_range.start)
19005            });
19006        }
19007
19008        if let Some(row) = row {
19009            let destination = Point::new(row.0, 0);
19010            let autoscroll = Autoscroll::center();
19011
19012            self.unfold_ranges(&[destination..destination], false, false, cx);
19013            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
19014                s.select_ranges([destination..destination]);
19015            });
19016        }
19017    }
19018
19019    fn do_stage_or_unstage(
19020        &self,
19021        stage: bool,
19022        buffer_id: BufferId,
19023        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
19024        cx: &mut App,
19025    ) -> Option<()> {
19026        let project = self.project()?;
19027        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19028        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19029        let buffer_snapshot = buffer.read(cx).snapshot();
19030        let file_exists = buffer_snapshot
19031            .file()
19032            .is_some_and(|file| file.disk_state().exists());
19033        diff.update(cx, |diff, cx| {
19034            diff.stage_or_unstage_hunks(
19035                stage,
19036                &hunks
19037                    .map(|hunk| buffer_diff::DiffHunk {
19038                        buffer_range: hunk.buffer_range,
19039                        diff_base_byte_range: hunk.diff_base_byte_range,
19040                        secondary_status: hunk.secondary_status,
19041                        range: Point::zero()..Point::zero(), // unused
19042                    })
19043                    .collect::<Vec<_>>(),
19044                &buffer_snapshot,
19045                file_exists,
19046                cx,
19047            )
19048        });
19049        None
19050    }
19051
19052    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19053        let ranges: Vec<_> = self
19054            .selections
19055            .disjoint_anchors()
19056            .iter()
19057            .map(|s| s.range())
19058            .collect();
19059        self.buffer
19060            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
19061    }
19062
19063    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
19064        self.buffer.update(cx, |buffer, cx| {
19065            let ranges = vec![Anchor::min()..Anchor::max()];
19066            if !buffer.all_diff_hunks_expanded()
19067                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
19068            {
19069                buffer.collapse_diff_hunks(ranges, cx);
19070                true
19071            } else {
19072                false
19073            }
19074        })
19075    }
19076
19077    fn toggle_diff_hunks_in_ranges(
19078        &mut self,
19079        ranges: Vec<Range<Anchor>>,
19080        cx: &mut Context<Editor>,
19081    ) {
19082        self.buffer.update(cx, |buffer, cx| {
19083            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
19084            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
19085        })
19086    }
19087
19088    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
19089        self.buffer.update(cx, |buffer, cx| {
19090            let snapshot = buffer.snapshot(cx);
19091            let excerpt_id = range.end.excerpt_id;
19092            let point_range = range.to_point(&snapshot);
19093            let expand = !buffer.single_hunk_is_expanded(range, cx);
19094            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
19095        })
19096    }
19097
19098    pub(crate) fn apply_all_diff_hunks(
19099        &mut self,
19100        _: &ApplyAllDiffHunks,
19101        window: &mut Window,
19102        cx: &mut Context<Self>,
19103    ) {
19104        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19105
19106        let buffers = self.buffer.read(cx).all_buffers();
19107        for branch_buffer in buffers {
19108            branch_buffer.update(cx, |branch_buffer, cx| {
19109                branch_buffer.merge_into_base(Vec::new(), cx);
19110            });
19111        }
19112
19113        if let Some(project) = self.project.clone() {
19114            self.save(
19115                SaveOptions {
19116                    format: true,
19117                    autosave: false,
19118                },
19119                project,
19120                window,
19121                cx,
19122            )
19123            .detach_and_log_err(cx);
19124        }
19125    }
19126
19127    pub(crate) fn apply_selected_diff_hunks(
19128        &mut self,
19129        _: &ApplyDiffHunk,
19130        window: &mut Window,
19131        cx: &mut Context<Self>,
19132    ) {
19133        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19134        let snapshot = self.snapshot(window, cx);
19135        let hunks = snapshot.hunks_for_ranges(
19136            self.selections
19137                .all(&snapshot.display_snapshot)
19138                .into_iter()
19139                .map(|selection| selection.range()),
19140        );
19141        let mut ranges_by_buffer = HashMap::default();
19142        self.transact(window, cx, |editor, _window, cx| {
19143            for hunk in hunks {
19144                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
19145                    ranges_by_buffer
19146                        .entry(buffer.clone())
19147                        .or_insert_with(Vec::new)
19148                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
19149                }
19150            }
19151
19152            for (buffer, ranges) in ranges_by_buffer {
19153                buffer.update(cx, |buffer, cx| {
19154                    buffer.merge_into_base(ranges, cx);
19155                });
19156            }
19157        });
19158
19159        if let Some(project) = self.project.clone() {
19160            self.save(
19161                SaveOptions {
19162                    format: true,
19163                    autosave: false,
19164                },
19165                project,
19166                window,
19167                cx,
19168            )
19169            .detach_and_log_err(cx);
19170        }
19171    }
19172
19173    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
19174        if hovered != self.gutter_hovered {
19175            self.gutter_hovered = hovered;
19176            cx.notify();
19177        }
19178    }
19179
19180    pub fn insert_blocks(
19181        &mut self,
19182        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
19183        autoscroll: Option<Autoscroll>,
19184        cx: &mut Context<Self>,
19185    ) -> Vec<CustomBlockId> {
19186        let blocks = self
19187            .display_map
19188            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
19189        if let Some(autoscroll) = autoscroll {
19190            self.request_autoscroll(autoscroll, cx);
19191        }
19192        cx.notify();
19193        blocks
19194    }
19195
19196    pub fn resize_blocks(
19197        &mut self,
19198        heights: HashMap<CustomBlockId, u32>,
19199        autoscroll: Option<Autoscroll>,
19200        cx: &mut Context<Self>,
19201    ) {
19202        self.display_map
19203            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
19204        if let Some(autoscroll) = autoscroll {
19205            self.request_autoscroll(autoscroll, cx);
19206        }
19207        cx.notify();
19208    }
19209
19210    pub fn replace_blocks(
19211        &mut self,
19212        renderers: HashMap<CustomBlockId, RenderBlock>,
19213        autoscroll: Option<Autoscroll>,
19214        cx: &mut Context<Self>,
19215    ) {
19216        self.display_map
19217            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
19218        if let Some(autoscroll) = autoscroll {
19219            self.request_autoscroll(autoscroll, cx);
19220        }
19221        cx.notify();
19222    }
19223
19224    pub fn remove_blocks(
19225        &mut self,
19226        block_ids: HashSet<CustomBlockId>,
19227        autoscroll: Option<Autoscroll>,
19228        cx: &mut Context<Self>,
19229    ) {
19230        self.display_map.update(cx, |display_map, cx| {
19231            display_map.remove_blocks(block_ids, cx)
19232        });
19233        if let Some(autoscroll) = autoscroll {
19234            self.request_autoscroll(autoscroll, cx);
19235        }
19236        cx.notify();
19237    }
19238
19239    pub fn row_for_block(
19240        &self,
19241        block_id: CustomBlockId,
19242        cx: &mut Context<Self>,
19243    ) -> Option<DisplayRow> {
19244        self.display_map
19245            .update(cx, |map, cx| map.row_for_block(block_id, cx))
19246    }
19247
19248    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
19249        self.focused_block = Some(focused_block);
19250    }
19251
19252    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
19253        self.focused_block.take()
19254    }
19255
19256    pub fn insert_creases(
19257        &mut self,
19258        creases: impl IntoIterator<Item = Crease<Anchor>>,
19259        cx: &mut Context<Self>,
19260    ) -> Vec<CreaseId> {
19261        self.display_map
19262            .update(cx, |map, cx| map.insert_creases(creases, cx))
19263    }
19264
19265    pub fn remove_creases(
19266        &mut self,
19267        ids: impl IntoIterator<Item = CreaseId>,
19268        cx: &mut Context<Self>,
19269    ) -> Vec<(CreaseId, Range<Anchor>)> {
19270        self.display_map
19271            .update(cx, |map, cx| map.remove_creases(ids, cx))
19272    }
19273
19274    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
19275        self.display_map
19276            .update(cx, |map, cx| map.snapshot(cx))
19277            .longest_row()
19278    }
19279
19280    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
19281        self.display_map
19282            .update(cx, |map, cx| map.snapshot(cx))
19283            .max_point()
19284    }
19285
19286    pub fn text(&self, cx: &App) -> String {
19287        self.buffer.read(cx).read(cx).text()
19288    }
19289
19290    pub fn is_empty(&self, cx: &App) -> bool {
19291        self.buffer.read(cx).read(cx).is_empty()
19292    }
19293
19294    pub fn text_option(&self, cx: &App) -> Option<String> {
19295        let text = self.text(cx);
19296        let text = text.trim();
19297
19298        if text.is_empty() {
19299            return None;
19300        }
19301
19302        Some(text.to_string())
19303    }
19304
19305    pub fn set_text(
19306        &mut self,
19307        text: impl Into<Arc<str>>,
19308        window: &mut Window,
19309        cx: &mut Context<Self>,
19310    ) {
19311        self.transact(window, cx, |this, _, cx| {
19312            this.buffer
19313                .read(cx)
19314                .as_singleton()
19315                .expect("you can only call set_text on editors for singleton buffers")
19316                .update(cx, |buffer, cx| buffer.set_text(text, cx));
19317        });
19318    }
19319
19320    pub fn display_text(&self, cx: &mut App) -> String {
19321        self.display_map
19322            .update(cx, |map, cx| map.snapshot(cx))
19323            .text()
19324    }
19325
19326    fn create_minimap(
19327        &self,
19328        minimap_settings: MinimapSettings,
19329        window: &mut Window,
19330        cx: &mut Context<Self>,
19331    ) -> Option<Entity<Self>> {
19332        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
19333            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
19334    }
19335
19336    fn initialize_new_minimap(
19337        &self,
19338        minimap_settings: MinimapSettings,
19339        window: &mut Window,
19340        cx: &mut Context<Self>,
19341    ) -> Entity<Self> {
19342        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
19343
19344        let mut minimap = Editor::new_internal(
19345            EditorMode::Minimap {
19346                parent: cx.weak_entity(),
19347            },
19348            self.buffer.clone(),
19349            None,
19350            Some(self.display_map.clone()),
19351            window,
19352            cx,
19353        );
19354        minimap.scroll_manager.clone_state(&self.scroll_manager);
19355        minimap.set_text_style_refinement(TextStyleRefinement {
19356            font_size: Some(MINIMAP_FONT_SIZE),
19357            font_weight: Some(MINIMAP_FONT_WEIGHT),
19358            ..Default::default()
19359        });
19360        minimap.update_minimap_configuration(minimap_settings, cx);
19361        cx.new(|_| minimap)
19362    }
19363
19364    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
19365        let current_line_highlight = minimap_settings
19366            .current_line_highlight
19367            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
19368        self.set_current_line_highlight(Some(current_line_highlight));
19369    }
19370
19371    pub fn minimap(&self) -> Option<&Entity<Self>> {
19372        self.minimap
19373            .as_ref()
19374            .filter(|_| self.minimap_visibility.visible())
19375    }
19376
19377    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
19378        let mut wrap_guides = smallvec![];
19379
19380        if self.show_wrap_guides == Some(false) {
19381            return wrap_guides;
19382        }
19383
19384        let settings = self.buffer.read(cx).language_settings(cx);
19385        if settings.show_wrap_guides {
19386            match self.soft_wrap_mode(cx) {
19387                SoftWrap::Column(soft_wrap) => {
19388                    wrap_guides.push((soft_wrap as usize, true));
19389                }
19390                SoftWrap::Bounded(soft_wrap) => {
19391                    wrap_guides.push((soft_wrap as usize, true));
19392                }
19393                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
19394            }
19395            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
19396        }
19397
19398        wrap_guides
19399    }
19400
19401    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
19402        let settings = self.buffer.read(cx).language_settings(cx);
19403        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
19404        match mode {
19405            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
19406                SoftWrap::None
19407            }
19408            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
19409            language_settings::SoftWrap::PreferredLineLength => {
19410                SoftWrap::Column(settings.preferred_line_length)
19411            }
19412            language_settings::SoftWrap::Bounded => {
19413                SoftWrap::Bounded(settings.preferred_line_length)
19414            }
19415        }
19416    }
19417
19418    pub fn set_soft_wrap_mode(
19419        &mut self,
19420        mode: language_settings::SoftWrap,
19421
19422        cx: &mut Context<Self>,
19423    ) {
19424        self.soft_wrap_mode_override = Some(mode);
19425        cx.notify();
19426    }
19427
19428    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
19429        self.hard_wrap = hard_wrap;
19430        cx.notify();
19431    }
19432
19433    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
19434        self.text_style_refinement = Some(style);
19435    }
19436
19437    /// called by the Element so we know what style we were most recently rendered with.
19438    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
19439        // We intentionally do not inform the display map about the minimap style
19440        // so that wrapping is not recalculated and stays consistent for the editor
19441        // and its linked minimap.
19442        if !self.mode.is_minimap() {
19443            let font = style.text.font();
19444            let font_size = style.text.font_size.to_pixels(window.rem_size());
19445            let display_map = self
19446                .placeholder_display_map
19447                .as_ref()
19448                .filter(|_| self.is_empty(cx))
19449                .unwrap_or(&self.display_map);
19450
19451            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
19452        }
19453        self.style = Some(style);
19454    }
19455
19456    pub fn style(&self) -> Option<&EditorStyle> {
19457        self.style.as_ref()
19458    }
19459
19460    // Called by the element. This method is not designed to be called outside of the editor
19461    // element's layout code because it does not notify when rewrapping is computed synchronously.
19462    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
19463        if self.is_empty(cx) {
19464            self.placeholder_display_map
19465                .as_ref()
19466                .map_or(false, |display_map| {
19467                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
19468                })
19469        } else {
19470            self.display_map
19471                .update(cx, |map, cx| map.set_wrap_width(width, cx))
19472        }
19473    }
19474
19475    pub fn set_soft_wrap(&mut self) {
19476        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
19477    }
19478
19479    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
19480        if self.soft_wrap_mode_override.is_some() {
19481            self.soft_wrap_mode_override.take();
19482        } else {
19483            let soft_wrap = match self.soft_wrap_mode(cx) {
19484                SoftWrap::GitDiff => return,
19485                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
19486                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
19487                    language_settings::SoftWrap::None
19488                }
19489            };
19490            self.soft_wrap_mode_override = Some(soft_wrap);
19491        }
19492        cx.notify();
19493    }
19494
19495    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
19496        let Some(workspace) = self.workspace() else {
19497            return;
19498        };
19499        let fs = workspace.read(cx).app_state().fs.clone();
19500        let current_show = TabBarSettings::get_global(cx).show;
19501        update_settings_file(fs, cx, move |setting, _| {
19502            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
19503        });
19504    }
19505
19506    pub fn toggle_indent_guides(
19507        &mut self,
19508        _: &ToggleIndentGuides,
19509        _: &mut Window,
19510        cx: &mut Context<Self>,
19511    ) {
19512        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
19513            self.buffer
19514                .read(cx)
19515                .language_settings(cx)
19516                .indent_guides
19517                .enabled
19518        });
19519        self.show_indent_guides = Some(!currently_enabled);
19520        cx.notify();
19521    }
19522
19523    fn should_show_indent_guides(&self) -> Option<bool> {
19524        self.show_indent_guides
19525    }
19526
19527    pub fn toggle_line_numbers(
19528        &mut self,
19529        _: &ToggleLineNumbers,
19530        _: &mut Window,
19531        cx: &mut Context<Self>,
19532    ) {
19533        let mut editor_settings = EditorSettings::get_global(cx).clone();
19534        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
19535        EditorSettings::override_global(editor_settings, cx);
19536    }
19537
19538    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
19539        if let Some(show_line_numbers) = self.show_line_numbers {
19540            return show_line_numbers;
19541        }
19542        EditorSettings::get_global(cx).gutter.line_numbers
19543    }
19544
19545    pub fn should_use_relative_line_numbers(&self, cx: &mut App) -> bool {
19546        self.use_relative_line_numbers
19547            .unwrap_or(EditorSettings::get_global(cx).relative_line_numbers)
19548    }
19549
19550    pub fn toggle_relative_line_numbers(
19551        &mut self,
19552        _: &ToggleRelativeLineNumbers,
19553        _: &mut Window,
19554        cx: &mut Context<Self>,
19555    ) {
19556        let is_relative = self.should_use_relative_line_numbers(cx);
19557        self.set_relative_line_number(Some(!is_relative), cx)
19558    }
19559
19560    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
19561        self.use_relative_line_numbers = is_relative;
19562        cx.notify();
19563    }
19564
19565    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
19566        self.show_gutter = show_gutter;
19567        cx.notify();
19568    }
19569
19570    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
19571        self.show_scrollbars = ScrollbarAxes {
19572            horizontal: show,
19573            vertical: show,
19574        };
19575        cx.notify();
19576    }
19577
19578    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19579        self.show_scrollbars.vertical = show;
19580        cx.notify();
19581    }
19582
19583    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
19584        self.show_scrollbars.horizontal = show;
19585        cx.notify();
19586    }
19587
19588    pub fn set_minimap_visibility(
19589        &mut self,
19590        minimap_visibility: MinimapVisibility,
19591        window: &mut Window,
19592        cx: &mut Context<Self>,
19593    ) {
19594        if self.minimap_visibility != minimap_visibility {
19595            if minimap_visibility.visible() && self.minimap.is_none() {
19596                let minimap_settings = EditorSettings::get_global(cx).minimap;
19597                self.minimap =
19598                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
19599            }
19600            self.minimap_visibility = minimap_visibility;
19601            cx.notify();
19602        }
19603    }
19604
19605    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19606        self.set_show_scrollbars(false, cx);
19607        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
19608    }
19609
19610    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
19611        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
19612    }
19613
19614    /// Normally the text in full mode and auto height editors is padded on the
19615    /// left side by roughly half a character width for improved hit testing.
19616    ///
19617    /// Use this method to disable this for cases where this is not wanted (e.g.
19618    /// if you want to align the editor text with some other text above or below)
19619    /// or if you want to add this padding to single-line editors.
19620    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
19621        self.offset_content = offset_content;
19622        cx.notify();
19623    }
19624
19625    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
19626        self.show_line_numbers = Some(show_line_numbers);
19627        cx.notify();
19628    }
19629
19630    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
19631        self.disable_expand_excerpt_buttons = true;
19632        cx.notify();
19633    }
19634
19635    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
19636        self.show_git_diff_gutter = Some(show_git_diff_gutter);
19637        cx.notify();
19638    }
19639
19640    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
19641        self.show_code_actions = Some(show_code_actions);
19642        cx.notify();
19643    }
19644
19645    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
19646        self.show_runnables = Some(show_runnables);
19647        cx.notify();
19648    }
19649
19650    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
19651        self.show_breakpoints = Some(show_breakpoints);
19652        cx.notify();
19653    }
19654
19655    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
19656        if self.display_map.read(cx).masked != masked {
19657            self.display_map.update(cx, |map, _| map.masked = masked);
19658        }
19659        cx.notify()
19660    }
19661
19662    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
19663        self.show_wrap_guides = Some(show_wrap_guides);
19664        cx.notify();
19665    }
19666
19667    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
19668        self.show_indent_guides = Some(show_indent_guides);
19669        cx.notify();
19670    }
19671
19672    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
19673        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
19674            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
19675                && let Some(dir) = file.abs_path(cx).parent()
19676            {
19677                return Some(dir.to_owned());
19678            }
19679        }
19680
19681        None
19682    }
19683
19684    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
19685        self.active_excerpt(cx)?
19686            .1
19687            .read(cx)
19688            .file()
19689            .and_then(|f| f.as_local())
19690    }
19691
19692    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
19693        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19694            let buffer = buffer.read(cx);
19695            if let Some(project_path) = buffer.project_path(cx) {
19696                let project = self.project()?.read(cx);
19697                project.absolute_path(&project_path, cx)
19698            } else {
19699                buffer
19700                    .file()
19701                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
19702            }
19703        })
19704    }
19705
19706    pub fn reveal_in_finder(
19707        &mut self,
19708        _: &RevealInFileManager,
19709        _window: &mut Window,
19710        cx: &mut Context<Self>,
19711    ) {
19712        if let Some(target) = self.target_file(cx) {
19713            cx.reveal_path(&target.abs_path(cx));
19714        }
19715    }
19716
19717    pub fn copy_path(
19718        &mut self,
19719        _: &zed_actions::workspace::CopyPath,
19720        _window: &mut Window,
19721        cx: &mut Context<Self>,
19722    ) {
19723        if let Some(path) = self.target_file_abs_path(cx)
19724            && let Some(path) = path.to_str()
19725        {
19726            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19727        } else {
19728            cx.propagate();
19729        }
19730    }
19731
19732    pub fn copy_relative_path(
19733        &mut self,
19734        _: &zed_actions::workspace::CopyRelativePath,
19735        _window: &mut Window,
19736        cx: &mut Context<Self>,
19737    ) {
19738        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
19739            let project = self.project()?.read(cx);
19740            let path = buffer.read(cx).file()?.path();
19741            let path = path.display(project.path_style(cx));
19742            Some(path)
19743        }) {
19744            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
19745        } else {
19746            cx.propagate();
19747        }
19748    }
19749
19750    /// Returns the project path for the editor's buffer, if any buffer is
19751    /// opened in the editor.
19752    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
19753        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
19754            buffer.read(cx).project_path(cx)
19755        } else {
19756            None
19757        }
19758    }
19759
19760    // Returns true if the editor handled a go-to-line request
19761    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
19762        maybe!({
19763            let breakpoint_store = self.breakpoint_store.as_ref()?;
19764
19765            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
19766            else {
19767                self.clear_row_highlights::<ActiveDebugLine>();
19768                return None;
19769            };
19770
19771            let position = active_stack_frame.position;
19772            let buffer_id = position.buffer_id?;
19773            let snapshot = self
19774                .project
19775                .as_ref()?
19776                .read(cx)
19777                .buffer_for_id(buffer_id, cx)?
19778                .read(cx)
19779                .snapshot();
19780
19781            let mut handled = false;
19782            for (id, ExcerptRange { context, .. }) in
19783                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
19784            {
19785                if context.start.cmp(&position, &snapshot).is_ge()
19786                    || context.end.cmp(&position, &snapshot).is_lt()
19787                {
19788                    continue;
19789                }
19790                let snapshot = self.buffer.read(cx).snapshot(cx);
19791                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
19792
19793                handled = true;
19794                self.clear_row_highlights::<ActiveDebugLine>();
19795
19796                self.go_to_line::<ActiveDebugLine>(
19797                    multibuffer_anchor,
19798                    Some(cx.theme().colors().editor_debugger_active_line_background),
19799                    window,
19800                    cx,
19801                );
19802
19803                cx.notify();
19804            }
19805
19806            handled.then_some(())
19807        })
19808        .is_some()
19809    }
19810
19811    pub fn copy_file_name_without_extension(
19812        &mut self,
19813        _: &CopyFileNameWithoutExtension,
19814        _: &mut Window,
19815        cx: &mut Context<Self>,
19816    ) {
19817        if let Some(file) = self.target_file(cx)
19818            && let Some(file_stem) = file.path().file_stem()
19819        {
19820            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
19821        }
19822    }
19823
19824    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
19825        if let Some(file) = self.target_file(cx)
19826            && let Some(name) = file.path().file_name()
19827        {
19828            cx.write_to_clipboard(ClipboardItem::new_string(name.to_string()));
19829        }
19830    }
19831
19832    pub fn toggle_git_blame(
19833        &mut self,
19834        _: &::git::Blame,
19835        window: &mut Window,
19836        cx: &mut Context<Self>,
19837    ) {
19838        self.show_git_blame_gutter = !self.show_git_blame_gutter;
19839
19840        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
19841            self.start_git_blame(true, window, cx);
19842        }
19843
19844        cx.notify();
19845    }
19846
19847    pub fn toggle_git_blame_inline(
19848        &mut self,
19849        _: &ToggleGitBlameInline,
19850        window: &mut Window,
19851        cx: &mut Context<Self>,
19852    ) {
19853        self.toggle_git_blame_inline_internal(true, window, cx);
19854        cx.notify();
19855    }
19856
19857    pub fn open_git_blame_commit(
19858        &mut self,
19859        _: &OpenGitBlameCommit,
19860        window: &mut Window,
19861        cx: &mut Context<Self>,
19862    ) {
19863        self.open_git_blame_commit_internal(window, cx);
19864    }
19865
19866    fn open_git_blame_commit_internal(
19867        &mut self,
19868        window: &mut Window,
19869        cx: &mut Context<Self>,
19870    ) -> Option<()> {
19871        let blame = self.blame.as_ref()?;
19872        let snapshot = self.snapshot(window, cx);
19873        let cursor = self
19874            .selections
19875            .newest::<Point>(&snapshot.display_snapshot)
19876            .head();
19877        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
19878        let (_, blame_entry) = blame
19879            .update(cx, |blame, cx| {
19880                blame
19881                    .blame_for_rows(
19882                        &[RowInfo {
19883                            buffer_id: Some(buffer.remote_id()),
19884                            buffer_row: Some(point.row),
19885                            ..Default::default()
19886                        }],
19887                        cx,
19888                    )
19889                    .next()
19890            })
19891            .flatten()?;
19892        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
19893        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
19894        let workspace = self.workspace()?.downgrade();
19895        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
19896        None
19897    }
19898
19899    pub fn git_blame_inline_enabled(&self) -> bool {
19900        self.git_blame_inline_enabled
19901    }
19902
19903    pub fn toggle_selection_menu(
19904        &mut self,
19905        _: &ToggleSelectionMenu,
19906        _: &mut Window,
19907        cx: &mut Context<Self>,
19908    ) {
19909        self.show_selection_menu = self
19910            .show_selection_menu
19911            .map(|show_selections_menu| !show_selections_menu)
19912            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
19913
19914        cx.notify();
19915    }
19916
19917    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
19918        self.show_selection_menu
19919            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
19920    }
19921
19922    fn start_git_blame(
19923        &mut self,
19924        user_triggered: bool,
19925        window: &mut Window,
19926        cx: &mut Context<Self>,
19927    ) {
19928        if let Some(project) = self.project() {
19929            if let Some(buffer) = self.buffer().read(cx).as_singleton()
19930                && buffer.read(cx).file().is_none()
19931            {
19932                return;
19933            }
19934
19935            let focused = self.focus_handle(cx).contains_focused(window, cx);
19936
19937            let project = project.clone();
19938            let blame = cx
19939                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
19940            self.blame_subscription =
19941                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
19942            self.blame = Some(blame);
19943        }
19944    }
19945
19946    fn toggle_git_blame_inline_internal(
19947        &mut self,
19948        user_triggered: bool,
19949        window: &mut Window,
19950        cx: &mut Context<Self>,
19951    ) {
19952        if self.git_blame_inline_enabled {
19953            self.git_blame_inline_enabled = false;
19954            self.show_git_blame_inline = false;
19955            self.show_git_blame_inline_delay_task.take();
19956        } else {
19957            self.git_blame_inline_enabled = true;
19958            self.start_git_blame_inline(user_triggered, window, cx);
19959        }
19960
19961        cx.notify();
19962    }
19963
19964    fn start_git_blame_inline(
19965        &mut self,
19966        user_triggered: bool,
19967        window: &mut Window,
19968        cx: &mut Context<Self>,
19969    ) {
19970        self.start_git_blame(user_triggered, window, cx);
19971
19972        if ProjectSettings::get_global(cx)
19973            .git
19974            .inline_blame_delay()
19975            .is_some()
19976        {
19977            self.start_inline_blame_timer(window, cx);
19978        } else {
19979            self.show_git_blame_inline = true
19980        }
19981    }
19982
19983    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
19984        self.blame.as_ref()
19985    }
19986
19987    pub fn show_git_blame_gutter(&self) -> bool {
19988        self.show_git_blame_gutter
19989    }
19990
19991    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
19992        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
19993    }
19994
19995    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
19996        self.show_git_blame_inline
19997            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
19998            && !self.newest_selection_head_on_empty_line(cx)
19999            && self.has_blame_entries(cx)
20000    }
20001
20002    fn has_blame_entries(&self, cx: &App) -> bool {
20003        self.blame()
20004            .is_some_and(|blame| blame.read(cx).has_generated_entries())
20005    }
20006
20007    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
20008        let cursor_anchor = self.selections.newest_anchor().head();
20009
20010        let snapshot = self.buffer.read(cx).snapshot(cx);
20011        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
20012
20013        snapshot.line_len(buffer_row) == 0
20014    }
20015
20016    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
20017        let buffer_and_selection = maybe!({
20018            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20019            let selection_range = selection.range();
20020
20021            let multi_buffer = self.buffer().read(cx);
20022            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
20023            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
20024
20025            let (buffer, range, _) = if selection.reversed {
20026                buffer_ranges.first()
20027            } else {
20028                buffer_ranges.last()
20029            }?;
20030
20031            let selection = text::ToPoint::to_point(&range.start, buffer).row
20032                ..text::ToPoint::to_point(&range.end, buffer).row;
20033            Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection))
20034        });
20035
20036        let Some((buffer, selection)) = buffer_and_selection else {
20037            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
20038        };
20039
20040        let Some(project) = self.project() else {
20041            return Task::ready(Err(anyhow!("editor does not have project")));
20042        };
20043
20044        project.update(cx, |project, cx| {
20045            project.get_permalink_to_line(&buffer, selection, cx)
20046        })
20047    }
20048
20049    pub fn copy_permalink_to_line(
20050        &mut self,
20051        _: &CopyPermalinkToLine,
20052        window: &mut Window,
20053        cx: &mut Context<Self>,
20054    ) {
20055        let permalink_task = self.get_permalink_to_line(cx);
20056        let workspace = self.workspace();
20057
20058        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20059            Ok(permalink) => {
20060                cx.update(|_, cx| {
20061                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
20062                })
20063                .ok();
20064            }
20065            Err(err) => {
20066                let message = format!("Failed to copy permalink: {err}");
20067
20068                anyhow::Result::<()>::Err(err).log_err();
20069
20070                if let Some(workspace) = workspace {
20071                    workspace
20072                        .update_in(cx, |workspace, _, cx| {
20073                            struct CopyPermalinkToLine;
20074
20075                            workspace.show_toast(
20076                                Toast::new(
20077                                    NotificationId::unique::<CopyPermalinkToLine>(),
20078                                    message,
20079                                ),
20080                                cx,
20081                            )
20082                        })
20083                        .ok();
20084                }
20085            }
20086        })
20087        .detach();
20088    }
20089
20090    pub fn copy_file_location(
20091        &mut self,
20092        _: &CopyFileLocation,
20093        _: &mut Window,
20094        cx: &mut Context<Self>,
20095    ) {
20096        let selection = self
20097            .selections
20098            .newest::<Point>(&self.display_snapshot(cx))
20099            .start
20100            .row
20101            + 1;
20102        if let Some(file) = self.target_file(cx) {
20103            let path = file.path().display(file.path_style(cx));
20104            cx.write_to_clipboard(ClipboardItem::new_string(format!("{path}:{selection}")));
20105        }
20106    }
20107
20108    pub fn open_permalink_to_line(
20109        &mut self,
20110        _: &OpenPermalinkToLine,
20111        window: &mut Window,
20112        cx: &mut Context<Self>,
20113    ) {
20114        let permalink_task = self.get_permalink_to_line(cx);
20115        let workspace = self.workspace();
20116
20117        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
20118            Ok(permalink) => {
20119                cx.update(|_, cx| {
20120                    cx.open_url(permalink.as_ref());
20121                })
20122                .ok();
20123            }
20124            Err(err) => {
20125                let message = format!("Failed to open permalink: {err}");
20126
20127                anyhow::Result::<()>::Err(err).log_err();
20128
20129                if let Some(workspace) = workspace {
20130                    workspace
20131                        .update(cx, |workspace, cx| {
20132                            struct OpenPermalinkToLine;
20133
20134                            workspace.show_toast(
20135                                Toast::new(
20136                                    NotificationId::unique::<OpenPermalinkToLine>(),
20137                                    message,
20138                                ),
20139                                cx,
20140                            )
20141                        })
20142                        .ok();
20143                }
20144            }
20145        })
20146        .detach();
20147    }
20148
20149    pub fn insert_uuid_v4(
20150        &mut self,
20151        _: &InsertUuidV4,
20152        window: &mut Window,
20153        cx: &mut Context<Self>,
20154    ) {
20155        self.insert_uuid(UuidVersion::V4, window, cx);
20156    }
20157
20158    pub fn insert_uuid_v7(
20159        &mut self,
20160        _: &InsertUuidV7,
20161        window: &mut Window,
20162        cx: &mut Context<Self>,
20163    ) {
20164        self.insert_uuid(UuidVersion::V7, window, cx);
20165    }
20166
20167    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
20168        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20169        self.transact(window, cx, |this, window, cx| {
20170            let edits = this
20171                .selections
20172                .all::<Point>(&this.display_snapshot(cx))
20173                .into_iter()
20174                .map(|selection| {
20175                    let uuid = match version {
20176                        UuidVersion::V4 => uuid::Uuid::new_v4(),
20177                        UuidVersion::V7 => uuid::Uuid::now_v7(),
20178                    };
20179
20180                    (selection.range(), uuid.to_string())
20181                });
20182            this.edit(edits, cx);
20183            this.refresh_edit_prediction(true, false, window, cx);
20184        });
20185    }
20186
20187    pub fn open_selections_in_multibuffer(
20188        &mut self,
20189        _: &OpenSelectionsInMultibuffer,
20190        window: &mut Window,
20191        cx: &mut Context<Self>,
20192    ) {
20193        let multibuffer = self.buffer.read(cx);
20194
20195        let Some(buffer) = multibuffer.as_singleton() else {
20196            return;
20197        };
20198
20199        let Some(workspace) = self.workspace() else {
20200            return;
20201        };
20202
20203        let title = multibuffer.title(cx).to_string();
20204
20205        let locations = self
20206            .selections
20207            .all_anchors(cx)
20208            .iter()
20209            .map(|selection| {
20210                (
20211                    buffer.clone(),
20212                    (selection.start.text_anchor..selection.end.text_anchor)
20213                        .to_point(buffer.read(cx)),
20214                )
20215            })
20216            .into_group_map();
20217
20218        cx.spawn_in(window, async move |_, cx| {
20219            workspace.update_in(cx, |workspace, window, cx| {
20220                Self::open_locations_in_multibuffer(
20221                    workspace,
20222                    locations,
20223                    format!("Selections for '{title}'"),
20224                    false,
20225                    MultibufferSelectionMode::All,
20226                    window,
20227                    cx,
20228                );
20229            })
20230        })
20231        .detach();
20232    }
20233
20234    /// Adds a row highlight for the given range. If a row has multiple highlights, the
20235    /// last highlight added will be used.
20236    ///
20237    /// If the range ends at the beginning of a line, then that line will not be highlighted.
20238    pub fn highlight_rows<T: 'static>(
20239        &mut self,
20240        range: Range<Anchor>,
20241        color: Hsla,
20242        options: RowHighlightOptions,
20243        cx: &mut Context<Self>,
20244    ) {
20245        let snapshot = self.buffer().read(cx).snapshot(cx);
20246        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20247        let ix = row_highlights.binary_search_by(|highlight| {
20248            Ordering::Equal
20249                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
20250                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
20251        });
20252
20253        if let Err(mut ix) = ix {
20254            let index = post_inc(&mut self.highlight_order);
20255
20256            // If this range intersects with the preceding highlight, then merge it with
20257            // the preceding highlight. Otherwise insert a new highlight.
20258            let mut merged = false;
20259            if ix > 0 {
20260                let prev_highlight = &mut row_highlights[ix - 1];
20261                if prev_highlight
20262                    .range
20263                    .end
20264                    .cmp(&range.start, &snapshot)
20265                    .is_ge()
20266                {
20267                    ix -= 1;
20268                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
20269                        prev_highlight.range.end = range.end;
20270                    }
20271                    merged = true;
20272                    prev_highlight.index = index;
20273                    prev_highlight.color = color;
20274                    prev_highlight.options = options;
20275                }
20276            }
20277
20278            if !merged {
20279                row_highlights.insert(
20280                    ix,
20281                    RowHighlight {
20282                        range,
20283                        index,
20284                        color,
20285                        options,
20286                        type_id: TypeId::of::<T>(),
20287                    },
20288                );
20289            }
20290
20291            // If any of the following highlights intersect with this one, merge them.
20292            while let Some(next_highlight) = row_highlights.get(ix + 1) {
20293                let highlight = &row_highlights[ix];
20294                if next_highlight
20295                    .range
20296                    .start
20297                    .cmp(&highlight.range.end, &snapshot)
20298                    .is_le()
20299                {
20300                    if next_highlight
20301                        .range
20302                        .end
20303                        .cmp(&highlight.range.end, &snapshot)
20304                        .is_gt()
20305                    {
20306                        row_highlights[ix].range.end = next_highlight.range.end;
20307                    }
20308                    row_highlights.remove(ix + 1);
20309                } else {
20310                    break;
20311                }
20312            }
20313        }
20314    }
20315
20316    /// Remove any highlighted row ranges of the given type that intersect the
20317    /// given ranges.
20318    pub fn remove_highlighted_rows<T: 'static>(
20319        &mut self,
20320        ranges_to_remove: Vec<Range<Anchor>>,
20321        cx: &mut Context<Self>,
20322    ) {
20323        let snapshot = self.buffer().read(cx).snapshot(cx);
20324        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
20325        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20326        row_highlights.retain(|highlight| {
20327            while let Some(range_to_remove) = ranges_to_remove.peek() {
20328                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
20329                    Ordering::Less | Ordering::Equal => {
20330                        ranges_to_remove.next();
20331                    }
20332                    Ordering::Greater => {
20333                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
20334                            Ordering::Less | Ordering::Equal => {
20335                                return false;
20336                            }
20337                            Ordering::Greater => break,
20338                        }
20339                    }
20340                }
20341            }
20342
20343            true
20344        })
20345    }
20346
20347    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
20348    pub fn clear_row_highlights<T: 'static>(&mut self) {
20349        self.highlighted_rows.remove(&TypeId::of::<T>());
20350    }
20351
20352    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
20353    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
20354        self.highlighted_rows
20355            .get(&TypeId::of::<T>())
20356            .map_or(&[] as &[_], |vec| vec.as_slice())
20357            .iter()
20358            .map(|highlight| (highlight.range.clone(), highlight.color))
20359    }
20360
20361    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
20362    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
20363    /// Allows to ignore certain kinds of highlights.
20364    pub fn highlighted_display_rows(
20365        &self,
20366        window: &mut Window,
20367        cx: &mut App,
20368    ) -> BTreeMap<DisplayRow, LineHighlight> {
20369        let snapshot = self.snapshot(window, cx);
20370        let mut used_highlight_orders = HashMap::default();
20371        self.highlighted_rows
20372            .iter()
20373            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
20374            .fold(
20375                BTreeMap::<DisplayRow, LineHighlight>::new(),
20376                |mut unique_rows, highlight| {
20377                    let start = highlight.range.start.to_display_point(&snapshot);
20378                    let end = highlight.range.end.to_display_point(&snapshot);
20379                    let start_row = start.row().0;
20380                    let end_row = if highlight.range.end.text_anchor != text::Anchor::MAX
20381                        && end.column() == 0
20382                    {
20383                        end.row().0.saturating_sub(1)
20384                    } else {
20385                        end.row().0
20386                    };
20387                    for row in start_row..=end_row {
20388                        let used_index =
20389                            used_highlight_orders.entry(row).or_insert(highlight.index);
20390                        if highlight.index >= *used_index {
20391                            *used_index = highlight.index;
20392                            unique_rows.insert(
20393                                DisplayRow(row),
20394                                LineHighlight {
20395                                    include_gutter: highlight.options.include_gutter,
20396                                    border: None,
20397                                    background: highlight.color.into(),
20398                                    type_id: Some(highlight.type_id),
20399                                },
20400                            );
20401                        }
20402                    }
20403                    unique_rows
20404                },
20405            )
20406    }
20407
20408    pub fn highlighted_display_row_for_autoscroll(
20409        &self,
20410        snapshot: &DisplaySnapshot,
20411    ) -> Option<DisplayRow> {
20412        self.highlighted_rows
20413            .values()
20414            .flat_map(|highlighted_rows| highlighted_rows.iter())
20415            .filter_map(|highlight| {
20416                if highlight.options.autoscroll {
20417                    Some(highlight.range.start.to_display_point(snapshot).row())
20418                } else {
20419                    None
20420                }
20421            })
20422            .min()
20423    }
20424
20425    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
20426        self.highlight_background::<SearchWithinRange>(
20427            ranges,
20428            |colors| colors.colors().editor_document_highlight_read_background,
20429            cx,
20430        )
20431    }
20432
20433    pub fn set_breadcrumb_header(&mut self, new_header: String) {
20434        self.breadcrumb_header = Some(new_header);
20435    }
20436
20437    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
20438        self.clear_background_highlights::<SearchWithinRange>(cx);
20439    }
20440
20441    pub fn highlight_background<T: 'static>(
20442        &mut self,
20443        ranges: &[Range<Anchor>],
20444        color_fetcher: fn(&Theme) -> Hsla,
20445        cx: &mut Context<Self>,
20446    ) {
20447        self.background_highlights.insert(
20448            HighlightKey::Type(TypeId::of::<T>()),
20449            (color_fetcher, Arc::from(ranges)),
20450        );
20451        self.scrollbar_marker_state.dirty = true;
20452        cx.notify();
20453    }
20454
20455    pub fn highlight_background_key<T: 'static>(
20456        &mut self,
20457        key: usize,
20458        ranges: &[Range<Anchor>],
20459        color_fetcher: fn(&Theme) -> Hsla,
20460        cx: &mut Context<Self>,
20461    ) {
20462        self.background_highlights.insert(
20463            HighlightKey::TypePlus(TypeId::of::<T>(), key),
20464            (color_fetcher, Arc::from(ranges)),
20465        );
20466        self.scrollbar_marker_state.dirty = true;
20467        cx.notify();
20468    }
20469
20470    pub fn clear_background_highlights<T: 'static>(
20471        &mut self,
20472        cx: &mut Context<Self>,
20473    ) -> Option<BackgroundHighlight> {
20474        let text_highlights = self
20475            .background_highlights
20476            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
20477        if !text_highlights.1.is_empty() {
20478            self.scrollbar_marker_state.dirty = true;
20479            cx.notify();
20480        }
20481        Some(text_highlights)
20482    }
20483
20484    pub fn highlight_gutter<T: 'static>(
20485        &mut self,
20486        ranges: impl Into<Vec<Range<Anchor>>>,
20487        color_fetcher: fn(&App) -> Hsla,
20488        cx: &mut Context<Self>,
20489    ) {
20490        self.gutter_highlights
20491            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
20492        cx.notify();
20493    }
20494
20495    pub fn clear_gutter_highlights<T: 'static>(
20496        &mut self,
20497        cx: &mut Context<Self>,
20498    ) -> Option<GutterHighlight> {
20499        cx.notify();
20500        self.gutter_highlights.remove(&TypeId::of::<T>())
20501    }
20502
20503    pub fn insert_gutter_highlight<T: 'static>(
20504        &mut self,
20505        range: Range<Anchor>,
20506        color_fetcher: fn(&App) -> Hsla,
20507        cx: &mut Context<Self>,
20508    ) {
20509        let snapshot = self.buffer().read(cx).snapshot(cx);
20510        let mut highlights = self
20511            .gutter_highlights
20512            .remove(&TypeId::of::<T>())
20513            .map(|(_, highlights)| highlights)
20514            .unwrap_or_default();
20515        let ix = highlights.binary_search_by(|highlight| {
20516            Ordering::Equal
20517                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
20518                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
20519        });
20520        if let Err(ix) = ix {
20521            highlights.insert(ix, range);
20522        }
20523        self.gutter_highlights
20524            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
20525    }
20526
20527    pub fn remove_gutter_highlights<T: 'static>(
20528        &mut self,
20529        ranges_to_remove: Vec<Range<Anchor>>,
20530        cx: &mut Context<Self>,
20531    ) {
20532        let snapshot = self.buffer().read(cx).snapshot(cx);
20533        let Some((color_fetcher, mut gutter_highlights)) =
20534            self.gutter_highlights.remove(&TypeId::of::<T>())
20535        else {
20536            return;
20537        };
20538        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
20539        gutter_highlights.retain(|highlight| {
20540            while let Some(range_to_remove) = ranges_to_remove.peek() {
20541                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
20542                    Ordering::Less | Ordering::Equal => {
20543                        ranges_to_remove.next();
20544                    }
20545                    Ordering::Greater => {
20546                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
20547                            Ordering::Less | Ordering::Equal => {
20548                                return false;
20549                            }
20550                            Ordering::Greater => break,
20551                        }
20552                    }
20553                }
20554            }
20555
20556            true
20557        });
20558        self.gutter_highlights
20559            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
20560    }
20561
20562    #[cfg(feature = "test-support")]
20563    pub fn all_text_highlights(
20564        &self,
20565        window: &mut Window,
20566        cx: &mut Context<Self>,
20567    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
20568        let snapshot = self.snapshot(window, cx);
20569        self.display_map.update(cx, |display_map, _| {
20570            display_map
20571                .all_text_highlights()
20572                .map(|highlight| {
20573                    let (style, ranges) = highlight.as_ref();
20574                    (
20575                        *style,
20576                        ranges
20577                            .iter()
20578                            .map(|range| range.clone().to_display_points(&snapshot))
20579                            .collect(),
20580                    )
20581                })
20582                .collect()
20583        })
20584    }
20585
20586    #[cfg(feature = "test-support")]
20587    pub fn all_text_background_highlights(
20588        &self,
20589        window: &mut Window,
20590        cx: &mut Context<Self>,
20591    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20592        let snapshot = self.snapshot(window, cx);
20593        let buffer = &snapshot.buffer_snapshot();
20594        let start = buffer.anchor_before(0);
20595        let end = buffer.anchor_after(buffer.len());
20596        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
20597    }
20598
20599    #[cfg(any(test, feature = "test-support"))]
20600    pub fn sorted_background_highlights_in_range(
20601        &self,
20602        search_range: Range<Anchor>,
20603        display_snapshot: &DisplaySnapshot,
20604        theme: &Theme,
20605    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20606        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
20607        res.sort_by(|a, b| {
20608            a.0.start
20609                .cmp(&b.0.start)
20610                .then_with(|| a.0.end.cmp(&b.0.end))
20611                .then_with(|| a.1.cmp(&b.1))
20612        });
20613        res
20614    }
20615
20616    #[cfg(feature = "test-support")]
20617    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
20618        let snapshot = self.buffer().read(cx).snapshot(cx);
20619
20620        let highlights = self
20621            .background_highlights
20622            .get(&HighlightKey::Type(TypeId::of::<
20623                items::BufferSearchHighlights,
20624            >()));
20625
20626        if let Some((_color, ranges)) = highlights {
20627            ranges
20628                .iter()
20629                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
20630                .collect_vec()
20631        } else {
20632            vec![]
20633        }
20634    }
20635
20636    fn document_highlights_for_position<'a>(
20637        &'a self,
20638        position: Anchor,
20639        buffer: &'a MultiBufferSnapshot,
20640    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
20641        let read_highlights = self
20642            .background_highlights
20643            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
20644            .map(|h| &h.1);
20645        let write_highlights = self
20646            .background_highlights
20647            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
20648            .map(|h| &h.1);
20649        let left_position = position.bias_left(buffer);
20650        let right_position = position.bias_right(buffer);
20651        read_highlights
20652            .into_iter()
20653            .chain(write_highlights)
20654            .flat_map(move |ranges| {
20655                let start_ix = match ranges.binary_search_by(|probe| {
20656                    let cmp = probe.end.cmp(&left_position, buffer);
20657                    if cmp.is_ge() {
20658                        Ordering::Greater
20659                    } else {
20660                        Ordering::Less
20661                    }
20662                }) {
20663                    Ok(i) | Err(i) => i,
20664                };
20665
20666                ranges[start_ix..]
20667                    .iter()
20668                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
20669            })
20670    }
20671
20672    pub fn has_background_highlights<T: 'static>(&self) -> bool {
20673        self.background_highlights
20674            .get(&HighlightKey::Type(TypeId::of::<T>()))
20675            .is_some_and(|(_, highlights)| !highlights.is_empty())
20676    }
20677
20678    /// Returns all background highlights for a given range.
20679    ///
20680    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
20681    pub fn background_highlights_in_range(
20682        &self,
20683        search_range: Range<Anchor>,
20684        display_snapshot: &DisplaySnapshot,
20685        theme: &Theme,
20686    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20687        let mut results = Vec::new();
20688        for (color_fetcher, ranges) in self.background_highlights.values() {
20689            let color = color_fetcher(theme);
20690            let start_ix = match ranges.binary_search_by(|probe| {
20691                let cmp = probe
20692                    .end
20693                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20694                if cmp.is_gt() {
20695                    Ordering::Greater
20696                } else {
20697                    Ordering::Less
20698                }
20699            }) {
20700                Ok(i) | Err(i) => i,
20701            };
20702            for range in &ranges[start_ix..] {
20703                if range
20704                    .start
20705                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20706                    .is_ge()
20707                {
20708                    break;
20709                }
20710
20711                let start = range.start.to_display_point(display_snapshot);
20712                let end = range.end.to_display_point(display_snapshot);
20713                results.push((start..end, color))
20714            }
20715        }
20716        results
20717    }
20718
20719    pub fn gutter_highlights_in_range(
20720        &self,
20721        search_range: Range<Anchor>,
20722        display_snapshot: &DisplaySnapshot,
20723        cx: &App,
20724    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
20725        let mut results = Vec::new();
20726        for (color_fetcher, ranges) in self.gutter_highlights.values() {
20727            let color = color_fetcher(cx);
20728            let start_ix = match ranges.binary_search_by(|probe| {
20729                let cmp = probe
20730                    .end
20731                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
20732                if cmp.is_gt() {
20733                    Ordering::Greater
20734                } else {
20735                    Ordering::Less
20736                }
20737            }) {
20738                Ok(i) | Err(i) => i,
20739            };
20740            for range in &ranges[start_ix..] {
20741                if range
20742                    .start
20743                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
20744                    .is_ge()
20745                {
20746                    break;
20747                }
20748
20749                let start = range.start.to_display_point(display_snapshot);
20750                let end = range.end.to_display_point(display_snapshot);
20751                results.push((start..end, color))
20752            }
20753        }
20754        results
20755    }
20756
20757    /// Get the text ranges corresponding to the redaction query
20758    pub fn redacted_ranges(
20759        &self,
20760        search_range: Range<Anchor>,
20761        display_snapshot: &DisplaySnapshot,
20762        cx: &App,
20763    ) -> Vec<Range<DisplayPoint>> {
20764        display_snapshot
20765            .buffer_snapshot()
20766            .redacted_ranges(search_range, |file| {
20767                if let Some(file) = file {
20768                    file.is_private()
20769                        && EditorSettings::get(
20770                            Some(SettingsLocation {
20771                                worktree_id: file.worktree_id(cx),
20772                                path: file.path().as_ref(),
20773                            }),
20774                            cx,
20775                        )
20776                        .redact_private_values
20777                } else {
20778                    false
20779                }
20780            })
20781            .map(|range| {
20782                range.start.to_display_point(display_snapshot)
20783                    ..range.end.to_display_point(display_snapshot)
20784            })
20785            .collect()
20786    }
20787
20788    pub fn highlight_text_key<T: 'static>(
20789        &mut self,
20790        key: usize,
20791        ranges: Vec<Range<Anchor>>,
20792        style: HighlightStyle,
20793        cx: &mut Context<Self>,
20794    ) {
20795        self.display_map.update(cx, |map, _| {
20796            map.highlight_text(
20797                HighlightKey::TypePlus(TypeId::of::<T>(), key),
20798                ranges,
20799                style,
20800            );
20801        });
20802        cx.notify();
20803    }
20804
20805    pub fn highlight_text<T: 'static>(
20806        &mut self,
20807        ranges: Vec<Range<Anchor>>,
20808        style: HighlightStyle,
20809        cx: &mut Context<Self>,
20810    ) {
20811        self.display_map.update(cx, |map, _| {
20812            map.highlight_text(HighlightKey::Type(TypeId::of::<T>()), ranges, style)
20813        });
20814        cx.notify();
20815    }
20816
20817    pub fn text_highlights<'a, T: 'static>(
20818        &'a self,
20819        cx: &'a App,
20820    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
20821        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
20822    }
20823
20824    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
20825        let cleared = self
20826            .display_map
20827            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
20828        if cleared {
20829            cx.notify();
20830        }
20831    }
20832
20833    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
20834        (self.read_only(cx) || self.blink_manager.read(cx).visible())
20835            && self.focus_handle.is_focused(window)
20836    }
20837
20838    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
20839        self.show_cursor_when_unfocused = is_enabled;
20840        cx.notify();
20841    }
20842
20843    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
20844        cx.notify();
20845    }
20846
20847    fn on_debug_session_event(
20848        &mut self,
20849        _session: Entity<Session>,
20850        event: &SessionEvent,
20851        cx: &mut Context<Self>,
20852    ) {
20853        if let SessionEvent::InvalidateInlineValue = event {
20854            self.refresh_inline_values(cx);
20855        }
20856    }
20857
20858    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
20859        let Some(project) = self.project.clone() else {
20860            return;
20861        };
20862
20863        if !self.inline_value_cache.enabled {
20864            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
20865            self.splice_inlays(&inlays, Vec::new(), cx);
20866            return;
20867        }
20868
20869        let current_execution_position = self
20870            .highlighted_rows
20871            .get(&TypeId::of::<ActiveDebugLine>())
20872            .and_then(|lines| lines.last().map(|line| line.range.end));
20873
20874        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
20875            let inline_values = editor
20876                .update(cx, |editor, cx| {
20877                    let Some(current_execution_position) = current_execution_position else {
20878                        return Some(Task::ready(Ok(Vec::new())));
20879                    };
20880
20881                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
20882                        let snapshot = buffer.snapshot(cx);
20883
20884                        let excerpt = snapshot.excerpt_containing(
20885                            current_execution_position..current_execution_position,
20886                        )?;
20887
20888                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
20889                    })?;
20890
20891                    let range =
20892                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
20893
20894                    project.inline_values(buffer, range, cx)
20895                })
20896                .ok()
20897                .flatten()?
20898                .await
20899                .context("refreshing debugger inlays")
20900                .log_err()?;
20901
20902            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
20903
20904            for (buffer_id, inline_value) in inline_values
20905                .into_iter()
20906                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
20907            {
20908                buffer_inline_values
20909                    .entry(buffer_id)
20910                    .or_default()
20911                    .push(inline_value);
20912            }
20913
20914            editor
20915                .update(cx, |editor, cx| {
20916                    let snapshot = editor.buffer.read(cx).snapshot(cx);
20917                    let mut new_inlays = Vec::default();
20918
20919                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
20920                        let buffer_id = buffer_snapshot.remote_id();
20921                        buffer_inline_values
20922                            .get(&buffer_id)
20923                            .into_iter()
20924                            .flatten()
20925                            .for_each(|hint| {
20926                                let inlay = Inlay::debugger(
20927                                    post_inc(&mut editor.next_inlay_id),
20928                                    Anchor::in_buffer(excerpt_id, buffer_id, hint.position),
20929                                    hint.text(),
20930                                );
20931                                if !inlay.text().chars().contains(&'\n') {
20932                                    new_inlays.push(inlay);
20933                                }
20934                            });
20935                    }
20936
20937                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
20938                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
20939
20940                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
20941                })
20942                .ok()?;
20943            Some(())
20944        });
20945    }
20946
20947    fn on_buffer_event(
20948        &mut self,
20949        multibuffer: &Entity<MultiBuffer>,
20950        event: &multi_buffer::Event,
20951        window: &mut Window,
20952        cx: &mut Context<Self>,
20953    ) {
20954        match event {
20955            multi_buffer::Event::Edited { edited_buffer } => {
20956                self.scrollbar_marker_state.dirty = true;
20957                self.active_indent_guides_state.dirty = true;
20958                self.refresh_active_diagnostics(cx);
20959                self.refresh_code_actions(window, cx);
20960                self.refresh_selected_text_highlights(true, window, cx);
20961                self.refresh_single_line_folds(window, cx);
20962                self.refresh_matching_bracket_highlights(window, cx);
20963                if self.has_active_edit_prediction() {
20964                    self.update_visible_edit_prediction(window, cx);
20965                }
20966
20967                if let Some(buffer) = edited_buffer {
20968                    if buffer.read(cx).file().is_none() {
20969                        cx.emit(EditorEvent::TitleChanged);
20970                    }
20971
20972                    if self.project.is_some() {
20973                        let buffer_id = buffer.read(cx).remote_id();
20974                        self.register_buffer(buffer_id, cx);
20975                        self.update_lsp_data(Some(buffer_id), window, cx);
20976                        self.refresh_inlay_hints(
20977                            InlayHintRefreshReason::BufferEdited(buffer_id),
20978                            cx,
20979                        );
20980                    }
20981                }
20982
20983                cx.emit(EditorEvent::BufferEdited);
20984                cx.emit(SearchEvent::MatchesInvalidated);
20985
20986                let Some(project) = &self.project else { return };
20987                let (telemetry, is_via_ssh) = {
20988                    let project = project.read(cx);
20989                    let telemetry = project.client().telemetry().clone();
20990                    let is_via_ssh = project.is_via_remote_server();
20991                    (telemetry, is_via_ssh)
20992                };
20993                telemetry.log_edit_event("editor", is_via_ssh);
20994            }
20995            multi_buffer::Event::ExcerptsAdded {
20996                buffer,
20997                predecessor,
20998                excerpts,
20999            } => {
21000                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21001                let buffer_id = buffer.read(cx).remote_id();
21002                if self.buffer.read(cx).diff_for(buffer_id).is_none()
21003                    && let Some(project) = &self.project
21004                {
21005                    update_uncommitted_diff_for_buffer(
21006                        cx.entity(),
21007                        project,
21008                        [buffer.clone()],
21009                        self.buffer.clone(),
21010                        cx,
21011                    )
21012                    .detach();
21013                }
21014                self.update_lsp_data(Some(buffer_id), window, cx);
21015                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21016                cx.emit(EditorEvent::ExcerptsAdded {
21017                    buffer: buffer.clone(),
21018                    predecessor: *predecessor,
21019                    excerpts: excerpts.clone(),
21020                });
21021            }
21022            multi_buffer::Event::ExcerptsRemoved {
21023                ids,
21024                removed_buffer_ids,
21025            } => {
21026                if let Some(inlay_hints) = &mut self.inlay_hints {
21027                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
21028                }
21029                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
21030                for buffer_id in removed_buffer_ids {
21031                    self.registered_buffers.remove(buffer_id);
21032                }
21033                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21034                cx.emit(EditorEvent::ExcerptsRemoved {
21035                    ids: ids.clone(),
21036                    removed_buffer_ids: removed_buffer_ids.clone(),
21037                });
21038            }
21039            multi_buffer::Event::ExcerptsEdited {
21040                excerpt_ids,
21041                buffer_ids,
21042            } => {
21043                self.display_map.update(cx, |map, cx| {
21044                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
21045                });
21046                cx.emit(EditorEvent::ExcerptsEdited {
21047                    ids: excerpt_ids.clone(),
21048                });
21049            }
21050            multi_buffer::Event::ExcerptsExpanded { ids } => {
21051                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
21052                self.refresh_document_highlights(cx);
21053                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
21054            }
21055            multi_buffer::Event::Reparsed(buffer_id) => {
21056                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21057                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21058
21059                cx.emit(EditorEvent::Reparsed(*buffer_id));
21060            }
21061            multi_buffer::Event::DiffHunksToggled => {
21062                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21063            }
21064            multi_buffer::Event::LanguageChanged(buffer_id) => {
21065                self.registered_buffers.remove(&buffer_id);
21066                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
21067                cx.emit(EditorEvent::Reparsed(*buffer_id));
21068                cx.notify();
21069            }
21070            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
21071            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
21072            multi_buffer::Event::FileHandleChanged
21073            | multi_buffer::Event::Reloaded
21074            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
21075            multi_buffer::Event::DiagnosticsUpdated => {
21076                self.update_diagnostics_state(window, cx);
21077            }
21078            _ => {}
21079        };
21080    }
21081
21082    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
21083        if !self.diagnostics_enabled() {
21084            return;
21085        }
21086        self.refresh_active_diagnostics(cx);
21087        self.refresh_inline_diagnostics(true, window, cx);
21088        self.scrollbar_marker_state.dirty = true;
21089        cx.notify();
21090    }
21091
21092    pub fn start_temporary_diff_override(&mut self) {
21093        self.load_diff_task.take();
21094        self.temporary_diff_override = true;
21095    }
21096
21097    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
21098        self.temporary_diff_override = false;
21099        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
21100        self.buffer.update(cx, |buffer, cx| {
21101            buffer.set_all_diff_hunks_collapsed(cx);
21102        });
21103
21104        if let Some(project) = self.project.clone() {
21105            self.load_diff_task = Some(
21106                update_uncommitted_diff_for_buffer(
21107                    cx.entity(),
21108                    &project,
21109                    self.buffer.read(cx).all_buffers(),
21110                    self.buffer.clone(),
21111                    cx,
21112                )
21113                .shared(),
21114            );
21115        }
21116    }
21117
21118    fn on_display_map_changed(
21119        &mut self,
21120        _: Entity<DisplayMap>,
21121        _: &mut Window,
21122        cx: &mut Context<Self>,
21123    ) {
21124        cx.notify();
21125    }
21126
21127    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21128        if self.diagnostics_enabled() {
21129            let new_severity = EditorSettings::get_global(cx)
21130                .diagnostics_max_severity
21131                .unwrap_or(DiagnosticSeverity::Hint);
21132            self.set_max_diagnostics_severity(new_severity, cx);
21133        }
21134        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
21135        self.update_edit_prediction_settings(cx);
21136        self.refresh_edit_prediction(true, false, window, cx);
21137        self.refresh_inline_values(cx);
21138        self.refresh_inlay_hints(
21139            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
21140                self.selections.newest_anchor().head(),
21141                &self.buffer.read(cx).snapshot(cx),
21142                cx,
21143            )),
21144            cx,
21145        );
21146
21147        let old_cursor_shape = self.cursor_shape;
21148        let old_show_breadcrumbs = self.show_breadcrumbs;
21149
21150        {
21151            let editor_settings = EditorSettings::get_global(cx);
21152            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
21153            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
21154            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
21155            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
21156        }
21157
21158        if old_cursor_shape != self.cursor_shape {
21159            cx.emit(EditorEvent::CursorShapeChanged);
21160        }
21161
21162        if old_show_breadcrumbs != self.show_breadcrumbs {
21163            cx.emit(EditorEvent::BreadcrumbsChanged);
21164        }
21165
21166        let project_settings = ProjectSettings::get_global(cx);
21167        self.serialize_dirty_buffers =
21168            !self.mode.is_minimap() && project_settings.session.restore_unsaved_buffers;
21169
21170        if self.mode.is_full() {
21171            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
21172            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
21173            if self.show_inline_diagnostics != show_inline_diagnostics {
21174                self.show_inline_diagnostics = show_inline_diagnostics;
21175                self.refresh_inline_diagnostics(false, window, cx);
21176            }
21177
21178            if self.git_blame_inline_enabled != inline_blame_enabled {
21179                self.toggle_git_blame_inline_internal(false, window, cx);
21180            }
21181
21182            let minimap_settings = EditorSettings::get_global(cx).minimap;
21183            if self.minimap_visibility != MinimapVisibility::Disabled {
21184                if self.minimap_visibility.settings_visibility()
21185                    != minimap_settings.minimap_enabled()
21186                {
21187                    self.set_minimap_visibility(
21188                        MinimapVisibility::for_mode(self.mode(), cx),
21189                        window,
21190                        cx,
21191                    );
21192                } else if let Some(minimap_entity) = self.minimap.as_ref() {
21193                    minimap_entity.update(cx, |minimap_editor, cx| {
21194                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
21195                    })
21196                }
21197            }
21198        }
21199
21200        if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
21201            colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
21202        }) {
21203            if !inlay_splice.is_empty() {
21204                self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
21205            }
21206            self.refresh_colors_for_visible_range(None, window, cx);
21207        }
21208
21209        cx.notify();
21210    }
21211
21212    pub fn set_searchable(&mut self, searchable: bool) {
21213        self.searchable = searchable;
21214    }
21215
21216    pub fn searchable(&self) -> bool {
21217        self.searchable
21218    }
21219
21220    pub fn open_excerpts_in_split(
21221        &mut self,
21222        _: &OpenExcerptsSplit,
21223        window: &mut Window,
21224        cx: &mut Context<Self>,
21225    ) {
21226        self.open_excerpts_common(None, true, window, cx)
21227    }
21228
21229    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
21230        self.open_excerpts_common(None, false, window, cx)
21231    }
21232
21233    fn open_excerpts_common(
21234        &mut self,
21235        jump_data: Option<JumpData>,
21236        split: bool,
21237        window: &mut Window,
21238        cx: &mut Context<Self>,
21239    ) {
21240        let Some(workspace) = self.workspace() else {
21241            cx.propagate();
21242            return;
21243        };
21244
21245        if self.buffer.read(cx).is_singleton() {
21246            cx.propagate();
21247            return;
21248        }
21249
21250        let mut new_selections_by_buffer = HashMap::default();
21251        match &jump_data {
21252            Some(JumpData::MultiBufferPoint {
21253                excerpt_id,
21254                position,
21255                anchor,
21256                line_offset_from_top,
21257            }) => {
21258                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21259                if let Some(buffer) = multi_buffer_snapshot
21260                    .buffer_id_for_excerpt(*excerpt_id)
21261                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
21262                {
21263                    let buffer_snapshot = buffer.read(cx).snapshot();
21264                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
21265                        language::ToPoint::to_point(anchor, &buffer_snapshot)
21266                    } else {
21267                        buffer_snapshot.clip_point(*position, Bias::Left)
21268                    };
21269                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
21270                    new_selections_by_buffer.insert(
21271                        buffer,
21272                        (
21273                            vec![jump_to_offset..jump_to_offset],
21274                            Some(*line_offset_from_top),
21275                        ),
21276                    );
21277                }
21278            }
21279            Some(JumpData::MultiBufferRow {
21280                row,
21281                line_offset_from_top,
21282            }) => {
21283                let point = MultiBufferPoint::new(row.0, 0);
21284                if let Some((buffer, buffer_point, _)) =
21285                    self.buffer.read(cx).point_to_buffer_point(point, cx)
21286                {
21287                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
21288                    new_selections_by_buffer
21289                        .entry(buffer)
21290                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
21291                        .0
21292                        .push(buffer_offset..buffer_offset)
21293                }
21294            }
21295            None => {
21296                let selections = self.selections.all::<usize>(&self.display_snapshot(cx));
21297                let multi_buffer = self.buffer.read(cx);
21298                for selection in selections {
21299                    for (snapshot, range, _, anchor) in multi_buffer
21300                        .snapshot(cx)
21301                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
21302                    {
21303                        if let Some(anchor) = anchor {
21304                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
21305                            else {
21306                                continue;
21307                            };
21308                            let offset = text::ToOffset::to_offset(
21309                                &anchor.text_anchor,
21310                                &buffer_handle.read(cx).snapshot(),
21311                            );
21312                            let range = offset..offset;
21313                            new_selections_by_buffer
21314                                .entry(buffer_handle)
21315                                .or_insert((Vec::new(), None))
21316                                .0
21317                                .push(range)
21318                        } else {
21319                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
21320                            else {
21321                                continue;
21322                            };
21323                            new_selections_by_buffer
21324                                .entry(buffer_handle)
21325                                .or_insert((Vec::new(), None))
21326                                .0
21327                                .push(range)
21328                        }
21329                    }
21330                }
21331            }
21332        }
21333
21334        new_selections_by_buffer
21335            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
21336
21337        if new_selections_by_buffer.is_empty() {
21338            return;
21339        }
21340
21341        // We defer the pane interaction because we ourselves are a workspace item
21342        // and activating a new item causes the pane to call a method on us reentrantly,
21343        // which panics if we're on the stack.
21344        window.defer(cx, move |window, cx| {
21345            workspace.update(cx, |workspace, cx| {
21346                let pane = if split {
21347                    workspace.adjacent_pane(window, cx)
21348                } else {
21349                    workspace.active_pane().clone()
21350                };
21351
21352                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
21353                    let editor = buffer
21354                        .read(cx)
21355                        .file()
21356                        .is_none()
21357                        .then(|| {
21358                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
21359                            // so `workspace.open_project_item` will never find them, always opening a new editor.
21360                            // Instead, we try to activate the existing editor in the pane first.
21361                            let (editor, pane_item_index) =
21362                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
21363                                    let editor = item.downcast::<Editor>()?;
21364                                    let singleton_buffer =
21365                                        editor.read(cx).buffer().read(cx).as_singleton()?;
21366                                    if singleton_buffer == buffer {
21367                                        Some((editor, i))
21368                                    } else {
21369                                        None
21370                                    }
21371                                })?;
21372                            pane.update(cx, |pane, cx| {
21373                                pane.activate_item(pane_item_index, true, true, window, cx)
21374                            });
21375                            Some(editor)
21376                        })
21377                        .flatten()
21378                        .unwrap_or_else(|| {
21379                            workspace.open_project_item::<Self>(
21380                                pane.clone(),
21381                                buffer,
21382                                true,
21383                                true,
21384                                window,
21385                                cx,
21386                            )
21387                        });
21388
21389                    editor.update(cx, |editor, cx| {
21390                        let autoscroll = match scroll_offset {
21391                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
21392                            None => Autoscroll::newest(),
21393                        };
21394                        let nav_history = editor.nav_history.take();
21395                        editor.change_selections(
21396                            SelectionEffects::scroll(autoscroll),
21397                            window,
21398                            cx,
21399                            |s| {
21400                                s.select_ranges(ranges);
21401                            },
21402                        );
21403                        editor.nav_history = nav_history;
21404                    });
21405                }
21406            })
21407        });
21408    }
21409
21410    // For now, don't allow opening excerpts in buffers that aren't backed by
21411    // regular project files.
21412    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
21413        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some())
21414    }
21415
21416    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<OffsetUtf16>>> {
21417        let snapshot = self.buffer.read(cx).read(cx);
21418        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
21419        Some(
21420            ranges
21421                .iter()
21422                .map(move |range| {
21423                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
21424                })
21425                .collect(),
21426        )
21427    }
21428
21429    fn selection_replacement_ranges(
21430        &self,
21431        range: Range<OffsetUtf16>,
21432        cx: &mut App,
21433    ) -> Vec<Range<OffsetUtf16>> {
21434        let selections = self
21435            .selections
21436            .all::<OffsetUtf16>(&self.display_snapshot(cx));
21437        let newest_selection = selections
21438            .iter()
21439            .max_by_key(|selection| selection.id)
21440            .unwrap();
21441        let start_delta = range.start.0 as isize - newest_selection.start.0 as isize;
21442        let end_delta = range.end.0 as isize - newest_selection.end.0 as isize;
21443        let snapshot = self.buffer.read(cx).read(cx);
21444        selections
21445            .into_iter()
21446            .map(|mut selection| {
21447                selection.start.0 =
21448                    (selection.start.0 as isize).saturating_add(start_delta) as usize;
21449                selection.end.0 = (selection.end.0 as isize).saturating_add(end_delta) as usize;
21450                snapshot.clip_offset_utf16(selection.start, Bias::Left)
21451                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
21452            })
21453            .collect()
21454    }
21455
21456    fn report_editor_event(
21457        &self,
21458        reported_event: ReportEditorEvent,
21459        file_extension: Option<String>,
21460        cx: &App,
21461    ) {
21462        if cfg!(any(test, feature = "test-support")) {
21463            return;
21464        }
21465
21466        let Some(project) = &self.project else { return };
21467
21468        // If None, we are in a file without an extension
21469        let file = self
21470            .buffer
21471            .read(cx)
21472            .as_singleton()
21473            .and_then(|b| b.read(cx).file());
21474        let file_extension = file_extension.or(file
21475            .as_ref()
21476            .and_then(|file| Path::new(file.file_name(cx)).extension())
21477            .and_then(|e| e.to_str())
21478            .map(|a| a.to_string()));
21479
21480        let vim_mode = vim_flavor(cx).is_some();
21481
21482        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
21483        let copilot_enabled = edit_predictions_provider
21484            == language::language_settings::EditPredictionProvider::Copilot;
21485        let copilot_enabled_for_language = self
21486            .buffer
21487            .read(cx)
21488            .language_settings(cx)
21489            .show_edit_predictions;
21490
21491        let project = project.read(cx);
21492        let event_type = reported_event.event_type();
21493
21494        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
21495            telemetry::event!(
21496                event_type,
21497                type = if auto_saved {"autosave"} else {"manual"},
21498                file_extension,
21499                vim_mode,
21500                copilot_enabled,
21501                copilot_enabled_for_language,
21502                edit_predictions_provider,
21503                is_via_ssh = project.is_via_remote_server(),
21504            );
21505        } else {
21506            telemetry::event!(
21507                event_type,
21508                file_extension,
21509                vim_mode,
21510                copilot_enabled,
21511                copilot_enabled_for_language,
21512                edit_predictions_provider,
21513                is_via_ssh = project.is_via_remote_server(),
21514            );
21515        };
21516    }
21517
21518    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
21519    /// with each line being an array of {text, highlight} objects.
21520    fn copy_highlight_json(
21521        &mut self,
21522        _: &CopyHighlightJson,
21523        window: &mut Window,
21524        cx: &mut Context<Self>,
21525    ) {
21526        #[derive(Serialize)]
21527        struct Chunk<'a> {
21528            text: String,
21529            highlight: Option<&'a str>,
21530        }
21531
21532        let snapshot = self.buffer.read(cx).snapshot(cx);
21533        let range = self
21534            .selected_text_range(false, window, cx)
21535            .and_then(|selection| {
21536                if selection.range.is_empty() {
21537                    None
21538                } else {
21539                    Some(
21540                        snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.start))
21541                            ..snapshot.offset_utf16_to_offset(OffsetUtf16(selection.range.end)),
21542                    )
21543                }
21544            })
21545            .unwrap_or_else(|| 0..snapshot.len());
21546
21547        let chunks = snapshot.chunks(range, true);
21548        let mut lines = Vec::new();
21549        let mut line: VecDeque<Chunk> = VecDeque::new();
21550
21551        let Some(style) = self.style.as_ref() else {
21552            return;
21553        };
21554
21555        for chunk in chunks {
21556            let highlight = chunk
21557                .syntax_highlight_id
21558                .and_then(|id| id.name(&style.syntax));
21559            let mut chunk_lines = chunk.text.split('\n').peekable();
21560            while let Some(text) = chunk_lines.next() {
21561                let mut merged_with_last_token = false;
21562                if let Some(last_token) = line.back_mut()
21563                    && last_token.highlight == highlight
21564                {
21565                    last_token.text.push_str(text);
21566                    merged_with_last_token = true;
21567                }
21568
21569                if !merged_with_last_token {
21570                    line.push_back(Chunk {
21571                        text: text.into(),
21572                        highlight,
21573                    });
21574                }
21575
21576                if chunk_lines.peek().is_some() {
21577                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
21578                        line.pop_front();
21579                    }
21580                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
21581                        line.pop_back();
21582                    }
21583
21584                    lines.push(mem::take(&mut line));
21585                }
21586            }
21587        }
21588
21589        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
21590            return;
21591        };
21592        cx.write_to_clipboard(ClipboardItem::new_string(lines));
21593    }
21594
21595    pub fn open_context_menu(
21596        &mut self,
21597        _: &OpenContextMenu,
21598        window: &mut Window,
21599        cx: &mut Context<Self>,
21600    ) {
21601        self.request_autoscroll(Autoscroll::newest(), cx);
21602        let position = self
21603            .selections
21604            .newest_display(&self.display_snapshot(cx))
21605            .start;
21606        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
21607    }
21608
21609    pub fn replay_insert_event(
21610        &mut self,
21611        text: &str,
21612        relative_utf16_range: Option<Range<isize>>,
21613        window: &mut Window,
21614        cx: &mut Context<Self>,
21615    ) {
21616        if !self.input_enabled {
21617            cx.emit(EditorEvent::InputIgnored { text: text.into() });
21618            return;
21619        }
21620        if let Some(relative_utf16_range) = relative_utf16_range {
21621            let selections = self
21622                .selections
21623                .all::<OffsetUtf16>(&self.display_snapshot(cx));
21624            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21625                let new_ranges = selections.into_iter().map(|range| {
21626                    let start = OffsetUtf16(
21627                        range
21628                            .head()
21629                            .0
21630                            .saturating_add_signed(relative_utf16_range.start),
21631                    );
21632                    let end = OffsetUtf16(
21633                        range
21634                            .head()
21635                            .0
21636                            .saturating_add_signed(relative_utf16_range.end),
21637                    );
21638                    start..end
21639                });
21640                s.select_ranges(new_ranges);
21641            });
21642        }
21643
21644        self.handle_input(text, window, cx);
21645    }
21646
21647    pub fn is_focused(&self, window: &Window) -> bool {
21648        self.focus_handle.is_focused(window)
21649    }
21650
21651    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21652        cx.emit(EditorEvent::Focused);
21653
21654        if let Some(descendant) = self
21655            .last_focused_descendant
21656            .take()
21657            .and_then(|descendant| descendant.upgrade())
21658        {
21659            window.focus(&descendant);
21660        } else {
21661            if let Some(blame) = self.blame.as_ref() {
21662                blame.update(cx, GitBlame::focus)
21663            }
21664
21665            self.blink_manager.update(cx, BlinkManager::enable);
21666            self.show_cursor_names(window, cx);
21667            self.buffer.update(cx, |buffer, cx| {
21668                buffer.finalize_last_transaction(cx);
21669                if self.leader_id.is_none() {
21670                    buffer.set_active_selections(
21671                        &self.selections.disjoint_anchors_arc(),
21672                        self.selections.line_mode(),
21673                        self.cursor_shape,
21674                        cx,
21675                    );
21676                }
21677            });
21678        }
21679    }
21680
21681    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
21682        cx.emit(EditorEvent::FocusedIn)
21683    }
21684
21685    fn handle_focus_out(
21686        &mut self,
21687        event: FocusOutEvent,
21688        _window: &mut Window,
21689        cx: &mut Context<Self>,
21690    ) {
21691        if event.blurred != self.focus_handle {
21692            self.last_focused_descendant = Some(event.blurred);
21693        }
21694        self.selection_drag_state = SelectionDragState::None;
21695        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
21696    }
21697
21698    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21699        self.blink_manager.update(cx, BlinkManager::disable);
21700        self.buffer
21701            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
21702
21703        if let Some(blame) = self.blame.as_ref() {
21704            blame.update(cx, GitBlame::blur)
21705        }
21706        if !self.hover_state.focused(window, cx) {
21707            hide_hover(self, cx);
21708        }
21709        if !self
21710            .context_menu
21711            .borrow()
21712            .as_ref()
21713            .is_some_and(|context_menu| context_menu.focused(window, cx))
21714        {
21715            self.hide_context_menu(window, cx);
21716        }
21717        self.take_active_edit_prediction(cx);
21718        cx.emit(EditorEvent::Blurred);
21719        cx.notify();
21720    }
21721
21722    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21723        let mut pending: String = window
21724            .pending_input_keystrokes()
21725            .into_iter()
21726            .flatten()
21727            .filter_map(|keystroke| {
21728                if keystroke.modifiers.is_subset_of(&Modifiers::shift()) {
21729                    keystroke.key_char.clone()
21730                } else {
21731                    None
21732                }
21733            })
21734            .collect();
21735
21736        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
21737            pending = "".to_string();
21738        }
21739
21740        let existing_pending = self
21741            .text_highlights::<PendingInput>(cx)
21742            .map(|(_, ranges)| ranges.to_vec());
21743        if existing_pending.is_none() && pending.is_empty() {
21744            return;
21745        }
21746        let transaction =
21747            self.transact(window, cx, |this, window, cx| {
21748                let selections = this.selections.all::<usize>(&this.display_snapshot(cx));
21749                let edits = selections
21750                    .iter()
21751                    .map(|selection| (selection.end..selection.end, pending.clone()));
21752                this.edit(edits, cx);
21753                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
21754                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
21755                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
21756                    }));
21757                });
21758                if let Some(existing_ranges) = existing_pending {
21759                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
21760                    this.edit(edits, cx);
21761                }
21762            });
21763
21764        let snapshot = self.snapshot(window, cx);
21765        let ranges = self
21766            .selections
21767            .all::<usize>(&snapshot.display_snapshot)
21768            .into_iter()
21769            .map(|selection| {
21770                snapshot.buffer_snapshot().anchor_after(selection.end)
21771                    ..snapshot
21772                        .buffer_snapshot()
21773                        .anchor_before(selection.end + pending.len())
21774            })
21775            .collect();
21776
21777        if pending.is_empty() {
21778            self.clear_highlights::<PendingInput>(cx);
21779        } else {
21780            self.highlight_text::<PendingInput>(
21781                ranges,
21782                HighlightStyle {
21783                    underline: Some(UnderlineStyle {
21784                        thickness: px(1.),
21785                        color: None,
21786                        wavy: false,
21787                    }),
21788                    ..Default::default()
21789                },
21790                cx,
21791            );
21792        }
21793
21794        self.ime_transaction = self.ime_transaction.or(transaction);
21795        if let Some(transaction) = self.ime_transaction {
21796            self.buffer.update(cx, |buffer, cx| {
21797                buffer.group_until_transaction(transaction, cx);
21798            });
21799        }
21800
21801        if self.text_highlights::<PendingInput>(cx).is_none() {
21802            self.ime_transaction.take();
21803        }
21804    }
21805
21806    pub fn register_action_renderer(
21807        &mut self,
21808        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
21809    ) -> Subscription {
21810        let id = self.next_editor_action_id.post_inc();
21811        self.editor_actions
21812            .borrow_mut()
21813            .insert(id, Box::new(listener));
21814
21815        let editor_actions = self.editor_actions.clone();
21816        Subscription::new(move || {
21817            editor_actions.borrow_mut().remove(&id);
21818        })
21819    }
21820
21821    pub fn register_action<A: Action>(
21822        &mut self,
21823        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
21824    ) -> Subscription {
21825        let id = self.next_editor_action_id.post_inc();
21826        let listener = Arc::new(listener);
21827        self.editor_actions.borrow_mut().insert(
21828            id,
21829            Box::new(move |_, window, _| {
21830                let listener = listener.clone();
21831                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
21832                    let action = action.downcast_ref().unwrap();
21833                    if phase == DispatchPhase::Bubble {
21834                        listener(action, window, cx)
21835                    }
21836                })
21837            }),
21838        );
21839
21840        let editor_actions = self.editor_actions.clone();
21841        Subscription::new(move || {
21842            editor_actions.borrow_mut().remove(&id);
21843        })
21844    }
21845
21846    pub fn file_header_size(&self) -> u32 {
21847        FILE_HEADER_HEIGHT
21848    }
21849
21850    pub fn restore(
21851        &mut self,
21852        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
21853        window: &mut Window,
21854        cx: &mut Context<Self>,
21855    ) {
21856        let workspace = self.workspace();
21857        let project = self.project();
21858        let save_tasks = self.buffer().update(cx, |multi_buffer, cx| {
21859            let mut tasks = Vec::new();
21860            for (buffer_id, changes) in revert_changes {
21861                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
21862                    buffer.update(cx, |buffer, cx| {
21863                        buffer.edit(
21864                            changes
21865                                .into_iter()
21866                                .map(|(range, text)| (range, text.to_string())),
21867                            None,
21868                            cx,
21869                        );
21870                    });
21871
21872                    if let Some(project) =
21873                        project.filter(|_| multi_buffer.all_diff_hunks_expanded())
21874                    {
21875                        project.update(cx, |project, cx| {
21876                            tasks.push((buffer.clone(), project.save_buffer(buffer, cx)));
21877                        })
21878                    }
21879                }
21880            }
21881            tasks
21882        });
21883        cx.spawn_in(window, async move |_, cx| {
21884            for (buffer, task) in save_tasks {
21885                let result = task.await;
21886                if result.is_err() {
21887                    let Some(path) = buffer
21888                        .read_with(cx, |buffer, cx| buffer.project_path(cx))
21889                        .ok()
21890                    else {
21891                        continue;
21892                    };
21893                    if let Some((workspace, path)) = workspace.as_ref().zip(path) {
21894                        let Some(task) = cx
21895                            .update_window_entity(workspace, |workspace, window, cx| {
21896                                workspace
21897                                    .open_path_preview(path, None, false, false, false, window, cx)
21898                            })
21899                            .ok()
21900                        else {
21901                            continue;
21902                        };
21903                        task.await.log_err();
21904                    }
21905                }
21906            }
21907        })
21908        .detach();
21909        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
21910            selections.refresh()
21911        });
21912    }
21913
21914    pub fn to_pixel_point(
21915        &self,
21916        source: multi_buffer::Anchor,
21917        editor_snapshot: &EditorSnapshot,
21918        window: &mut Window,
21919    ) -> Option<gpui::Point<Pixels>> {
21920        let source_point = source.to_display_point(editor_snapshot);
21921        self.display_to_pixel_point(source_point, editor_snapshot, window)
21922    }
21923
21924    pub fn display_to_pixel_point(
21925        &self,
21926        source: DisplayPoint,
21927        editor_snapshot: &EditorSnapshot,
21928        window: &mut Window,
21929    ) -> Option<gpui::Point<Pixels>> {
21930        let line_height = self.style()?.text.line_height_in_pixels(window.rem_size());
21931        let text_layout_details = self.text_layout_details(window);
21932        let scroll_top = text_layout_details
21933            .scroll_anchor
21934            .scroll_position(editor_snapshot)
21935            .y;
21936
21937        if source.row().as_f64() < scroll_top.floor() {
21938            return None;
21939        }
21940        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
21941        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
21942        Some(gpui::Point::new(source_x, source_y))
21943    }
21944
21945    pub fn has_visible_completions_menu(&self) -> bool {
21946        !self.edit_prediction_preview_is_active()
21947            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
21948                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
21949            })
21950    }
21951
21952    pub fn register_addon<T: Addon>(&mut self, instance: T) {
21953        if self.mode.is_minimap() {
21954            return;
21955        }
21956        self.addons
21957            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
21958    }
21959
21960    pub fn unregister_addon<T: Addon>(&mut self) {
21961        self.addons.remove(&std::any::TypeId::of::<T>());
21962    }
21963
21964    pub fn addon<T: Addon>(&self) -> Option<&T> {
21965        let type_id = std::any::TypeId::of::<T>();
21966        self.addons
21967            .get(&type_id)
21968            .and_then(|item| item.to_any().downcast_ref::<T>())
21969    }
21970
21971    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
21972        let type_id = std::any::TypeId::of::<T>();
21973        self.addons
21974            .get_mut(&type_id)
21975            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
21976    }
21977
21978    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
21979        let text_layout_details = self.text_layout_details(window);
21980        let style = &text_layout_details.editor_style;
21981        let font_id = window.text_system().resolve_font(&style.text.font());
21982        let font_size = style.text.font_size.to_pixels(window.rem_size());
21983        let line_height = style.text.line_height_in_pixels(window.rem_size());
21984        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
21985        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
21986
21987        CharacterDimensions {
21988            em_width,
21989            em_advance,
21990            line_height,
21991        }
21992    }
21993
21994    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
21995        self.load_diff_task.clone()
21996    }
21997
21998    fn read_metadata_from_db(
21999        &mut self,
22000        item_id: u64,
22001        workspace_id: WorkspaceId,
22002        window: &mut Window,
22003        cx: &mut Context<Editor>,
22004    ) {
22005        if self.buffer_kind(cx) == ItemBufferKind::Singleton
22006            && !self.mode.is_minimap()
22007            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
22008        {
22009            let buffer_snapshot = OnceCell::new();
22010
22011            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
22012                && !folds.is_empty()
22013            {
22014                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22015                self.fold_ranges(
22016                    folds
22017                        .into_iter()
22018                        .map(|(start, end)| {
22019                            snapshot.clip_offset(start, Bias::Left)
22020                                ..snapshot.clip_offset(end, Bias::Right)
22021                        })
22022                        .collect(),
22023                    false,
22024                    window,
22025                    cx,
22026                );
22027            }
22028
22029            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
22030                && !selections.is_empty()
22031            {
22032                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
22033                // skip adding the initial selection to selection history
22034                self.selection_history.mode = SelectionHistoryMode::Skipping;
22035                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22036                    s.select_ranges(selections.into_iter().map(|(start, end)| {
22037                        snapshot.clip_offset(start, Bias::Left)
22038                            ..snapshot.clip_offset(end, Bias::Right)
22039                    }));
22040                });
22041                self.selection_history.mode = SelectionHistoryMode::Normal;
22042            };
22043        }
22044
22045        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
22046    }
22047
22048    fn update_lsp_data(
22049        &mut self,
22050        for_buffer: Option<BufferId>,
22051        window: &mut Window,
22052        cx: &mut Context<'_, Self>,
22053    ) {
22054        self.pull_diagnostics(for_buffer, window, cx);
22055        self.refresh_colors_for_visible_range(for_buffer, window, cx);
22056    }
22057
22058    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
22059        if self.ignore_lsp_data() {
22060            return;
22061        }
22062        for (_, (visible_buffer, _, _)) in self.visible_excerpts(cx) {
22063            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
22064        }
22065    }
22066
22067    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
22068        if !self.registered_buffers.contains_key(&buffer_id)
22069            && let Some(project) = self.project.as_ref()
22070        {
22071            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
22072                project.update(cx, |project, cx| {
22073                    self.registered_buffers.insert(
22074                        buffer_id,
22075                        project.register_buffer_with_language_servers(&buffer, cx),
22076                    );
22077                });
22078            } else {
22079                self.registered_buffers.remove(&buffer_id);
22080            }
22081        }
22082    }
22083
22084    fn ignore_lsp_data(&self) -> bool {
22085        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
22086        // skip any LSP updates for it.
22087        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
22088    }
22089}
22090
22091fn edit_for_markdown_paste<'a>(
22092    buffer: &MultiBufferSnapshot,
22093    range: Range<usize>,
22094    to_insert: &'a str,
22095    url: Option<url::Url>,
22096) -> (Range<usize>, Cow<'a, str>) {
22097    if url.is_none() {
22098        return (range, Cow::Borrowed(to_insert));
22099    };
22100
22101    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
22102
22103    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
22104        Cow::Borrowed(to_insert)
22105    } else {
22106        Cow::Owned(format!("[{old_text}]({to_insert})"))
22107    };
22108    (range, new_text)
22109}
22110
22111#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
22112pub enum VimFlavor {
22113    Vim,
22114    Helix,
22115}
22116
22117pub fn vim_flavor(cx: &App) -> Option<VimFlavor> {
22118    if vim_mode_setting::HelixModeSetting::try_get(cx)
22119        .map(|helix_mode| helix_mode.0)
22120        .unwrap_or(false)
22121    {
22122        Some(VimFlavor::Helix)
22123    } else if vim_mode_setting::VimModeSetting::try_get(cx)
22124        .map(|vim_mode| vim_mode.0)
22125        .unwrap_or(false)
22126    {
22127        Some(VimFlavor::Vim)
22128    } else {
22129        None // neither vim nor helix mode
22130    }
22131}
22132
22133fn process_completion_for_edit(
22134    completion: &Completion,
22135    intent: CompletionIntent,
22136    buffer: &Entity<Buffer>,
22137    cursor_position: &text::Anchor,
22138    cx: &mut Context<Editor>,
22139) -> CompletionEdit {
22140    let buffer = buffer.read(cx);
22141    let buffer_snapshot = buffer.snapshot();
22142    let (snippet, new_text) = if completion.is_snippet() {
22143        let mut snippet_source = completion.new_text.clone();
22144        // Workaround for typescript language server issues so that methods don't expand within
22145        // strings and functions with type expressions. The previous point is used because the query
22146        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
22147        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
22148        let previous_point = if previous_point.column > 0 {
22149            cursor_position.to_previous_offset(&buffer_snapshot)
22150        } else {
22151            cursor_position.to_offset(&buffer_snapshot)
22152        };
22153        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
22154            && scope.prefers_label_for_snippet_in_completion()
22155            && let Some(label) = completion.label()
22156            && matches!(
22157                completion.kind(),
22158                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
22159            )
22160        {
22161            snippet_source = label;
22162        }
22163        match Snippet::parse(&snippet_source).log_err() {
22164            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
22165            None => (None, completion.new_text.clone()),
22166        }
22167    } else {
22168        (None, completion.new_text.clone())
22169    };
22170
22171    let mut range_to_replace = {
22172        let replace_range = &completion.replace_range;
22173        if let CompletionSource::Lsp {
22174            insert_range: Some(insert_range),
22175            ..
22176        } = &completion.source
22177        {
22178            debug_assert_eq!(
22179                insert_range.start, replace_range.start,
22180                "insert_range and replace_range should start at the same position"
22181            );
22182            debug_assert!(
22183                insert_range
22184                    .start
22185                    .cmp(cursor_position, &buffer_snapshot)
22186                    .is_le(),
22187                "insert_range should start before or at cursor position"
22188            );
22189            debug_assert!(
22190                replace_range
22191                    .start
22192                    .cmp(cursor_position, &buffer_snapshot)
22193                    .is_le(),
22194                "replace_range should start before or at cursor position"
22195            );
22196
22197            let should_replace = match intent {
22198                CompletionIntent::CompleteWithInsert => false,
22199                CompletionIntent::CompleteWithReplace => true,
22200                CompletionIntent::Complete | CompletionIntent::Compose => {
22201                    let insert_mode =
22202                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
22203                            .completions
22204                            .lsp_insert_mode;
22205                    match insert_mode {
22206                        LspInsertMode::Insert => false,
22207                        LspInsertMode::Replace => true,
22208                        LspInsertMode::ReplaceSubsequence => {
22209                            let mut text_to_replace = buffer.chars_for_range(
22210                                buffer.anchor_before(replace_range.start)
22211                                    ..buffer.anchor_after(replace_range.end),
22212                            );
22213                            let mut current_needle = text_to_replace.next();
22214                            for haystack_ch in completion.label.text.chars() {
22215                                if let Some(needle_ch) = current_needle
22216                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
22217                                {
22218                                    current_needle = text_to_replace.next();
22219                                }
22220                            }
22221                            current_needle.is_none()
22222                        }
22223                        LspInsertMode::ReplaceSuffix => {
22224                            if replace_range
22225                                .end
22226                                .cmp(cursor_position, &buffer_snapshot)
22227                                .is_gt()
22228                            {
22229                                let range_after_cursor = *cursor_position..replace_range.end;
22230                                let text_after_cursor = buffer
22231                                    .text_for_range(
22232                                        buffer.anchor_before(range_after_cursor.start)
22233                                            ..buffer.anchor_after(range_after_cursor.end),
22234                                    )
22235                                    .collect::<String>()
22236                                    .to_ascii_lowercase();
22237                                completion
22238                                    .label
22239                                    .text
22240                                    .to_ascii_lowercase()
22241                                    .ends_with(&text_after_cursor)
22242                            } else {
22243                                true
22244                            }
22245                        }
22246                    }
22247                }
22248            };
22249
22250            if should_replace {
22251                replace_range.clone()
22252            } else {
22253                insert_range.clone()
22254            }
22255        } else {
22256            replace_range.clone()
22257        }
22258    };
22259
22260    if range_to_replace
22261        .end
22262        .cmp(cursor_position, &buffer_snapshot)
22263        .is_lt()
22264    {
22265        range_to_replace.end = *cursor_position;
22266    }
22267
22268    CompletionEdit {
22269        new_text,
22270        replace_range: range_to_replace.to_offset(buffer),
22271        snippet,
22272    }
22273}
22274
22275struct CompletionEdit {
22276    new_text: String,
22277    replace_range: Range<usize>,
22278    snippet: Option<Snippet>,
22279}
22280
22281fn insert_extra_newline_brackets(
22282    buffer: &MultiBufferSnapshot,
22283    range: Range<usize>,
22284    language: &language::LanguageScope,
22285) -> bool {
22286    let leading_whitespace_len = buffer
22287        .reversed_chars_at(range.start)
22288        .take_while(|c| c.is_whitespace() && *c != '\n')
22289        .map(|c| c.len_utf8())
22290        .sum::<usize>();
22291    let trailing_whitespace_len = buffer
22292        .chars_at(range.end)
22293        .take_while(|c| c.is_whitespace() && *c != '\n')
22294        .map(|c| c.len_utf8())
22295        .sum::<usize>();
22296    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
22297
22298    language.brackets().any(|(pair, enabled)| {
22299        let pair_start = pair.start.trim_end();
22300        let pair_end = pair.end.trim_start();
22301
22302        enabled
22303            && pair.newline
22304            && buffer.contains_str_at(range.end, pair_end)
22305            && buffer.contains_str_at(range.start.saturating_sub(pair_start.len()), pair_start)
22306    })
22307}
22308
22309fn insert_extra_newline_tree_sitter(buffer: &MultiBufferSnapshot, range: Range<usize>) -> bool {
22310    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
22311        [(buffer, range, _)] => (*buffer, range.clone()),
22312        _ => return false,
22313    };
22314    let pair = {
22315        let mut result: Option<BracketMatch> = None;
22316
22317        for pair in buffer
22318            .all_bracket_ranges(range.clone())
22319            .filter(move |pair| {
22320                pair.open_range.start <= range.start && pair.close_range.end >= range.end
22321            })
22322        {
22323            let len = pair.close_range.end - pair.open_range.start;
22324
22325            if let Some(existing) = &result {
22326                let existing_len = existing.close_range.end - existing.open_range.start;
22327                if len > existing_len {
22328                    continue;
22329                }
22330            }
22331
22332            result = Some(pair);
22333        }
22334
22335        result
22336    };
22337    let Some(pair) = pair else {
22338        return false;
22339    };
22340    pair.newline_only
22341        && buffer
22342            .chars_for_range(pair.open_range.end..range.start)
22343            .chain(buffer.chars_for_range(range.end..pair.close_range.start))
22344            .all(|c| c.is_whitespace() && c != '\n')
22345}
22346
22347fn update_uncommitted_diff_for_buffer(
22348    editor: Entity<Editor>,
22349    project: &Entity<Project>,
22350    buffers: impl IntoIterator<Item = Entity<Buffer>>,
22351    buffer: Entity<MultiBuffer>,
22352    cx: &mut App,
22353) -> Task<()> {
22354    let mut tasks = Vec::new();
22355    project.update(cx, |project, cx| {
22356        for buffer in buffers {
22357            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
22358                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
22359            }
22360        }
22361    });
22362    cx.spawn(async move |cx| {
22363        let diffs = future::join_all(tasks).await;
22364        if editor
22365            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
22366            .unwrap_or(false)
22367        {
22368            return;
22369        }
22370
22371        buffer
22372            .update(cx, |buffer, cx| {
22373                for diff in diffs.into_iter().flatten() {
22374                    buffer.add_diff(diff, cx);
22375                }
22376            })
22377            .ok();
22378    })
22379}
22380
22381fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
22382    let tab_size = tab_size.get() as usize;
22383    let mut width = offset;
22384
22385    for ch in text.chars() {
22386        width += if ch == '\t' {
22387            tab_size - (width % tab_size)
22388        } else {
22389            1
22390        };
22391    }
22392
22393    width - offset
22394}
22395
22396#[cfg(test)]
22397mod tests {
22398    use super::*;
22399
22400    #[test]
22401    fn test_string_size_with_expanded_tabs() {
22402        let nz = |val| NonZeroU32::new(val).unwrap();
22403        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
22404        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
22405        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
22406        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
22407        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
22408        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
22409        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
22410        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
22411    }
22412}
22413
22414/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
22415struct WordBreakingTokenizer<'a> {
22416    input: &'a str,
22417}
22418
22419impl<'a> WordBreakingTokenizer<'a> {
22420    fn new(input: &'a str) -> Self {
22421        Self { input }
22422    }
22423}
22424
22425fn is_char_ideographic(ch: char) -> bool {
22426    use unicode_script::Script::*;
22427    use unicode_script::UnicodeScript;
22428    matches!(ch.script(), Han | Tangut | Yi)
22429}
22430
22431fn is_grapheme_ideographic(text: &str) -> bool {
22432    text.chars().any(is_char_ideographic)
22433}
22434
22435fn is_grapheme_whitespace(text: &str) -> bool {
22436    text.chars().any(|x| x.is_whitespace())
22437}
22438
22439fn should_stay_with_preceding_ideograph(text: &str) -> bool {
22440    text.chars()
22441        .next()
22442        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
22443}
22444
22445#[derive(PartialEq, Eq, Debug, Clone, Copy)]
22446enum WordBreakToken<'a> {
22447    Word { token: &'a str, grapheme_len: usize },
22448    InlineWhitespace { token: &'a str, grapheme_len: usize },
22449    Newline,
22450}
22451
22452impl<'a> Iterator for WordBreakingTokenizer<'a> {
22453    /// Yields a span, the count of graphemes in the token, and whether it was
22454    /// whitespace. Note that it also breaks at word boundaries.
22455    type Item = WordBreakToken<'a>;
22456
22457    fn next(&mut self) -> Option<Self::Item> {
22458        use unicode_segmentation::UnicodeSegmentation;
22459        if self.input.is_empty() {
22460            return None;
22461        }
22462
22463        let mut iter = self.input.graphemes(true).peekable();
22464        let mut offset = 0;
22465        let mut grapheme_len = 0;
22466        if let Some(first_grapheme) = iter.next() {
22467            let is_newline = first_grapheme == "\n";
22468            let is_whitespace = is_grapheme_whitespace(first_grapheme);
22469            offset += first_grapheme.len();
22470            grapheme_len += 1;
22471            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
22472                if let Some(grapheme) = iter.peek().copied()
22473                    && should_stay_with_preceding_ideograph(grapheme)
22474                {
22475                    offset += grapheme.len();
22476                    grapheme_len += 1;
22477                }
22478            } else {
22479                let mut words = self.input[offset..].split_word_bound_indices().peekable();
22480                let mut next_word_bound = words.peek().copied();
22481                if next_word_bound.is_some_and(|(i, _)| i == 0) {
22482                    next_word_bound = words.next();
22483                }
22484                while let Some(grapheme) = iter.peek().copied() {
22485                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
22486                        break;
22487                    };
22488                    if is_grapheme_whitespace(grapheme) != is_whitespace
22489                        || (grapheme == "\n") != is_newline
22490                    {
22491                        break;
22492                    };
22493                    offset += grapheme.len();
22494                    grapheme_len += 1;
22495                    iter.next();
22496                }
22497            }
22498            let token = &self.input[..offset];
22499            self.input = &self.input[offset..];
22500            if token == "\n" {
22501                Some(WordBreakToken::Newline)
22502            } else if is_whitespace {
22503                Some(WordBreakToken::InlineWhitespace {
22504                    token,
22505                    grapheme_len,
22506                })
22507            } else {
22508                Some(WordBreakToken::Word {
22509                    token,
22510                    grapheme_len,
22511                })
22512            }
22513        } else {
22514            None
22515        }
22516    }
22517}
22518
22519#[test]
22520fn test_word_breaking_tokenizer() {
22521    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
22522        ("", &[]),
22523        ("  ", &[whitespace("  ", 2)]),
22524        ("Ʒ", &[word("Ʒ", 1)]),
22525        ("Ǽ", &[word("Ǽ", 1)]),
22526        ("", &[word("", 1)]),
22527        ("⋑⋑", &[word("⋑⋑", 2)]),
22528        (
22529            "原理,进而",
22530            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
22531        ),
22532        (
22533            "hello world",
22534            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
22535        ),
22536        (
22537            "hello, world",
22538            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
22539        ),
22540        (
22541            "  hello world",
22542            &[
22543                whitespace("  ", 2),
22544                word("hello", 5),
22545                whitespace(" ", 1),
22546                word("world", 5),
22547            ],
22548        ),
22549        (
22550            "这是什么 \n 钢笔",
22551            &[
22552                word("", 1),
22553                word("", 1),
22554                word("", 1),
22555                word("", 1),
22556                whitespace(" ", 1),
22557                newline(),
22558                whitespace(" ", 1),
22559                word("", 1),
22560                word("", 1),
22561            ],
22562        ),
22563        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
22564    ];
22565
22566    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22567        WordBreakToken::Word {
22568            token,
22569            grapheme_len,
22570        }
22571    }
22572
22573    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
22574        WordBreakToken::InlineWhitespace {
22575            token,
22576            grapheme_len,
22577        }
22578    }
22579
22580    fn newline() -> WordBreakToken<'static> {
22581        WordBreakToken::Newline
22582    }
22583
22584    for (input, result) in tests {
22585        assert_eq!(
22586            WordBreakingTokenizer::new(input)
22587                .collect::<Vec<_>>()
22588                .as_slice(),
22589            *result,
22590        );
22591    }
22592}
22593
22594fn wrap_with_prefix(
22595    first_line_prefix: String,
22596    subsequent_lines_prefix: String,
22597    unwrapped_text: String,
22598    wrap_column: usize,
22599    tab_size: NonZeroU32,
22600    preserve_existing_whitespace: bool,
22601) -> String {
22602    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
22603    let subsequent_lines_prefix_len =
22604        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
22605    let mut wrapped_text = String::new();
22606    let mut current_line = first_line_prefix;
22607    let mut is_first_line = true;
22608
22609    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
22610    let mut current_line_len = first_line_prefix_len;
22611    let mut in_whitespace = false;
22612    for token in tokenizer {
22613        let have_preceding_whitespace = in_whitespace;
22614        match token {
22615            WordBreakToken::Word {
22616                token,
22617                grapheme_len,
22618            } => {
22619                in_whitespace = false;
22620                let current_prefix_len = if is_first_line {
22621                    first_line_prefix_len
22622                } else {
22623                    subsequent_lines_prefix_len
22624                };
22625                if current_line_len + grapheme_len > wrap_column
22626                    && current_line_len != current_prefix_len
22627                {
22628                    wrapped_text.push_str(current_line.trim_end());
22629                    wrapped_text.push('\n');
22630                    is_first_line = false;
22631                    current_line = subsequent_lines_prefix.clone();
22632                    current_line_len = subsequent_lines_prefix_len;
22633                }
22634                current_line.push_str(token);
22635                current_line_len += grapheme_len;
22636            }
22637            WordBreakToken::InlineWhitespace {
22638                mut token,
22639                mut grapheme_len,
22640            } => {
22641                in_whitespace = true;
22642                if have_preceding_whitespace && !preserve_existing_whitespace {
22643                    continue;
22644                }
22645                if !preserve_existing_whitespace {
22646                    // Keep a single whitespace grapheme as-is
22647                    if let Some(first) =
22648                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
22649                    {
22650                        token = first;
22651                    } else {
22652                        token = " ";
22653                    }
22654                    grapheme_len = 1;
22655                }
22656                let current_prefix_len = if is_first_line {
22657                    first_line_prefix_len
22658                } else {
22659                    subsequent_lines_prefix_len
22660                };
22661                if current_line_len + grapheme_len > wrap_column {
22662                    wrapped_text.push_str(current_line.trim_end());
22663                    wrapped_text.push('\n');
22664                    is_first_line = false;
22665                    current_line = subsequent_lines_prefix.clone();
22666                    current_line_len = subsequent_lines_prefix_len;
22667                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
22668                    current_line.push_str(token);
22669                    current_line_len += grapheme_len;
22670                }
22671            }
22672            WordBreakToken::Newline => {
22673                in_whitespace = true;
22674                let current_prefix_len = if is_first_line {
22675                    first_line_prefix_len
22676                } else {
22677                    subsequent_lines_prefix_len
22678                };
22679                if preserve_existing_whitespace {
22680                    wrapped_text.push_str(current_line.trim_end());
22681                    wrapped_text.push('\n');
22682                    is_first_line = false;
22683                    current_line = subsequent_lines_prefix.clone();
22684                    current_line_len = subsequent_lines_prefix_len;
22685                } else if have_preceding_whitespace {
22686                    continue;
22687                } else if current_line_len + 1 > wrap_column
22688                    && current_line_len != current_prefix_len
22689                {
22690                    wrapped_text.push_str(current_line.trim_end());
22691                    wrapped_text.push('\n');
22692                    is_first_line = false;
22693                    current_line = subsequent_lines_prefix.clone();
22694                    current_line_len = subsequent_lines_prefix_len;
22695                } else if current_line_len != current_prefix_len {
22696                    current_line.push(' ');
22697                    current_line_len += 1;
22698                }
22699            }
22700        }
22701    }
22702
22703    if !current_line.is_empty() {
22704        wrapped_text.push_str(&current_line);
22705    }
22706    wrapped_text
22707}
22708
22709#[test]
22710fn test_wrap_with_prefix() {
22711    assert_eq!(
22712        wrap_with_prefix(
22713            "# ".to_string(),
22714            "# ".to_string(),
22715            "abcdefg".to_string(),
22716            4,
22717            NonZeroU32::new(4).unwrap(),
22718            false,
22719        ),
22720        "# abcdefg"
22721    );
22722    assert_eq!(
22723        wrap_with_prefix(
22724            "".to_string(),
22725            "".to_string(),
22726            "\thello world".to_string(),
22727            8,
22728            NonZeroU32::new(4).unwrap(),
22729            false,
22730        ),
22731        "hello\nworld"
22732    );
22733    assert_eq!(
22734        wrap_with_prefix(
22735            "// ".to_string(),
22736            "// ".to_string(),
22737            "xx \nyy zz aa bb cc".to_string(),
22738            12,
22739            NonZeroU32::new(4).unwrap(),
22740            false,
22741        ),
22742        "// xx yy zz\n// aa bb cc"
22743    );
22744    assert_eq!(
22745        wrap_with_prefix(
22746            String::new(),
22747            String::new(),
22748            "这是什么 \n 钢笔".to_string(),
22749            3,
22750            NonZeroU32::new(4).unwrap(),
22751            false,
22752        ),
22753        "这是什\n么 钢\n"
22754    );
22755    assert_eq!(
22756        wrap_with_prefix(
22757            String::new(),
22758            String::new(),
22759            format!("foo{}bar", '\u{2009}'), // thin space
22760            80,
22761            NonZeroU32::new(4).unwrap(),
22762            false,
22763        ),
22764        format!("foo{}bar", '\u{2009}')
22765    );
22766}
22767
22768pub trait CollaborationHub {
22769    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
22770    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
22771    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
22772}
22773
22774impl CollaborationHub for Entity<Project> {
22775    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
22776        self.read(cx).collaborators()
22777    }
22778
22779    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
22780        self.read(cx).user_store().read(cx).participant_indices()
22781    }
22782
22783    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
22784        let this = self.read(cx);
22785        let user_ids = this.collaborators().values().map(|c| c.user_id);
22786        this.user_store().read(cx).participant_names(user_ids, cx)
22787    }
22788}
22789
22790pub trait SemanticsProvider {
22791    fn hover(
22792        &self,
22793        buffer: &Entity<Buffer>,
22794        position: text::Anchor,
22795        cx: &mut App,
22796    ) -> Option<Task<Option<Vec<project::Hover>>>>;
22797
22798    fn inline_values(
22799        &self,
22800        buffer_handle: Entity<Buffer>,
22801        range: Range<text::Anchor>,
22802        cx: &mut App,
22803    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
22804
22805    fn applicable_inlay_chunks(
22806        &self,
22807        buffer: &Entity<Buffer>,
22808        ranges: &[Range<text::Anchor>],
22809        cx: &mut App,
22810    ) -> Vec<Range<BufferRow>>;
22811
22812    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
22813
22814    fn inlay_hints(
22815        &self,
22816        invalidate: InvalidationStrategy,
22817        buffer: Entity<Buffer>,
22818        ranges: Vec<Range<text::Anchor>>,
22819        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
22820        cx: &mut App,
22821    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
22822
22823    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
22824
22825    fn document_highlights(
22826        &self,
22827        buffer: &Entity<Buffer>,
22828        position: text::Anchor,
22829        cx: &mut App,
22830    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
22831
22832    fn definitions(
22833        &self,
22834        buffer: &Entity<Buffer>,
22835        position: text::Anchor,
22836        kind: GotoDefinitionKind,
22837        cx: &mut App,
22838    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
22839
22840    fn range_for_rename(
22841        &self,
22842        buffer: &Entity<Buffer>,
22843        position: text::Anchor,
22844        cx: &mut App,
22845    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
22846
22847    fn perform_rename(
22848        &self,
22849        buffer: &Entity<Buffer>,
22850        position: text::Anchor,
22851        new_name: String,
22852        cx: &mut App,
22853    ) -> Option<Task<Result<ProjectTransaction>>>;
22854}
22855
22856pub trait CompletionProvider {
22857    fn completions(
22858        &self,
22859        excerpt_id: ExcerptId,
22860        buffer: &Entity<Buffer>,
22861        buffer_position: text::Anchor,
22862        trigger: CompletionContext,
22863        window: &mut Window,
22864        cx: &mut Context<Editor>,
22865    ) -> Task<Result<Vec<CompletionResponse>>>;
22866
22867    fn resolve_completions(
22868        &self,
22869        _buffer: Entity<Buffer>,
22870        _completion_indices: Vec<usize>,
22871        _completions: Rc<RefCell<Box<[Completion]>>>,
22872        _cx: &mut Context<Editor>,
22873    ) -> Task<Result<bool>> {
22874        Task::ready(Ok(false))
22875    }
22876
22877    fn apply_additional_edits_for_completion(
22878        &self,
22879        _buffer: Entity<Buffer>,
22880        _completions: Rc<RefCell<Box<[Completion]>>>,
22881        _completion_index: usize,
22882        _push_to_history: bool,
22883        _cx: &mut Context<Editor>,
22884    ) -> Task<Result<Option<language::Transaction>>> {
22885        Task::ready(Ok(None))
22886    }
22887
22888    fn is_completion_trigger(
22889        &self,
22890        buffer: &Entity<Buffer>,
22891        position: language::Anchor,
22892        text: &str,
22893        trigger_in_words: bool,
22894        menu_is_open: bool,
22895        cx: &mut Context<Editor>,
22896    ) -> bool;
22897
22898    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
22899
22900    fn sort_completions(&self) -> bool {
22901        true
22902    }
22903
22904    fn filter_completions(&self) -> bool {
22905        true
22906    }
22907}
22908
22909pub trait CodeActionProvider {
22910    fn id(&self) -> Arc<str>;
22911
22912    fn code_actions(
22913        &self,
22914        buffer: &Entity<Buffer>,
22915        range: Range<text::Anchor>,
22916        window: &mut Window,
22917        cx: &mut App,
22918    ) -> Task<Result<Vec<CodeAction>>>;
22919
22920    fn apply_code_action(
22921        &self,
22922        buffer_handle: Entity<Buffer>,
22923        action: CodeAction,
22924        excerpt_id: ExcerptId,
22925        push_to_history: bool,
22926        window: &mut Window,
22927        cx: &mut App,
22928    ) -> Task<Result<ProjectTransaction>>;
22929}
22930
22931impl CodeActionProvider for Entity<Project> {
22932    fn id(&self) -> Arc<str> {
22933        "project".into()
22934    }
22935
22936    fn code_actions(
22937        &self,
22938        buffer: &Entity<Buffer>,
22939        range: Range<text::Anchor>,
22940        _window: &mut Window,
22941        cx: &mut App,
22942    ) -> Task<Result<Vec<CodeAction>>> {
22943        self.update(cx, |project, cx| {
22944            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
22945            let code_actions = project.code_actions(buffer, range, None, cx);
22946            cx.background_spawn(async move {
22947                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
22948                Ok(code_lens_actions
22949                    .context("code lens fetch")?
22950                    .into_iter()
22951                    .flatten()
22952                    .chain(
22953                        code_actions
22954                            .context("code action fetch")?
22955                            .into_iter()
22956                            .flatten(),
22957                    )
22958                    .collect())
22959            })
22960        })
22961    }
22962
22963    fn apply_code_action(
22964        &self,
22965        buffer_handle: Entity<Buffer>,
22966        action: CodeAction,
22967        _excerpt_id: ExcerptId,
22968        push_to_history: bool,
22969        _window: &mut Window,
22970        cx: &mut App,
22971    ) -> Task<Result<ProjectTransaction>> {
22972        self.update(cx, |project, cx| {
22973            project.apply_code_action(buffer_handle, action, push_to_history, cx)
22974        })
22975    }
22976}
22977
22978fn snippet_completions(
22979    project: &Project,
22980    buffer: &Entity<Buffer>,
22981    buffer_position: text::Anchor,
22982    cx: &mut App,
22983) -> Task<Result<CompletionResponse>> {
22984    let languages = buffer.read(cx).languages_at(buffer_position);
22985    let snippet_store = project.snippets().read(cx);
22986
22987    let scopes: Vec<_> = languages
22988        .iter()
22989        .filter_map(|language| {
22990            let language_name = language.lsp_id();
22991            let snippets = snippet_store.snippets_for(Some(language_name), cx);
22992
22993            if snippets.is_empty() {
22994                None
22995            } else {
22996                Some((language.default_scope(), snippets))
22997            }
22998        })
22999        .collect();
23000
23001    if scopes.is_empty() {
23002        return Task::ready(Ok(CompletionResponse {
23003            completions: vec![],
23004            display_options: CompletionDisplayOptions::default(),
23005            is_incomplete: false,
23006        }));
23007    }
23008
23009    let snapshot = buffer.read(cx).text_snapshot();
23010    let executor = cx.background_executor().clone();
23011
23012    cx.background_spawn(async move {
23013        let mut is_incomplete = false;
23014        let mut completions: Vec<Completion> = Vec::new();
23015        for (scope, snippets) in scopes.into_iter() {
23016            let classifier =
23017                CharClassifier::new(Some(scope)).scope_context(Some(CharScopeContext::Completion));
23018
23019            const MAX_WORD_PREFIX_LEN: usize = 128;
23020            let last_word: String = snapshot
23021                .reversed_chars_for_range(text::Anchor::MIN..buffer_position)
23022                .take(MAX_WORD_PREFIX_LEN)
23023                .take_while(|c| classifier.is_word(*c))
23024                .collect::<String>()
23025                .chars()
23026                .rev()
23027                .collect();
23028
23029            if last_word.is_empty() {
23030                return Ok(CompletionResponse {
23031                    completions: vec![],
23032                    display_options: CompletionDisplayOptions::default(),
23033                    is_incomplete: true,
23034                });
23035            }
23036
23037            let as_offset = text::ToOffset::to_offset(&buffer_position, &snapshot);
23038            let to_lsp = |point: &text::Anchor| {
23039                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
23040                point_to_lsp(end)
23041            };
23042            let lsp_end = to_lsp(&buffer_position);
23043
23044            let candidates = snippets
23045                .iter()
23046                .enumerate()
23047                .flat_map(|(ix, snippet)| {
23048                    snippet
23049                        .prefix
23050                        .iter()
23051                        .map(move |prefix| StringMatchCandidate::new(ix, prefix))
23052                })
23053                .collect::<Vec<StringMatchCandidate>>();
23054
23055            const MAX_RESULTS: usize = 100;
23056            let mut matches = fuzzy::match_strings(
23057                &candidates,
23058                &last_word,
23059                last_word.chars().any(|c| c.is_uppercase()),
23060                true,
23061                MAX_RESULTS,
23062                &Default::default(),
23063                executor.clone(),
23064            )
23065            .await;
23066
23067            if matches.len() >= MAX_RESULTS {
23068                is_incomplete = true;
23069            }
23070
23071            // Remove all candidates where the query's start does not match the start of any word in the candidate
23072            if let Some(query_start) = last_word.chars().next() {
23073                matches.retain(|string_match| {
23074                    split_words(&string_match.string).any(|word| {
23075                        // Check that the first codepoint of the word as lowercase matches the first
23076                        // codepoint of the query as lowercase
23077                        word.chars()
23078                            .flat_map(|codepoint| codepoint.to_lowercase())
23079                            .zip(query_start.to_lowercase())
23080                            .all(|(word_cp, query_cp)| word_cp == query_cp)
23081                    })
23082                });
23083            }
23084
23085            let matched_strings = matches
23086                .into_iter()
23087                .map(|m| m.string)
23088                .collect::<HashSet<_>>();
23089
23090            completions.extend(snippets.iter().filter_map(|snippet| {
23091                let matching_prefix = snippet
23092                    .prefix
23093                    .iter()
23094                    .find(|prefix| matched_strings.contains(*prefix))?;
23095                let start = as_offset - last_word.len();
23096                let start = snapshot.anchor_before(start);
23097                let range = start..buffer_position;
23098                let lsp_start = to_lsp(&start);
23099                let lsp_range = lsp::Range {
23100                    start: lsp_start,
23101                    end: lsp_end,
23102                };
23103                Some(Completion {
23104                    replace_range: range,
23105                    new_text: snippet.body.clone(),
23106                    source: CompletionSource::Lsp {
23107                        insert_range: None,
23108                        server_id: LanguageServerId(usize::MAX),
23109                        resolved: true,
23110                        lsp_completion: Box::new(lsp::CompletionItem {
23111                            label: snippet.prefix.first().unwrap().clone(),
23112                            kind: Some(CompletionItemKind::SNIPPET),
23113                            label_details: snippet.description.as_ref().map(|description| {
23114                                lsp::CompletionItemLabelDetails {
23115                                    detail: Some(description.clone()),
23116                                    description: None,
23117                                }
23118                            }),
23119                            insert_text_format: Some(InsertTextFormat::SNIPPET),
23120                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
23121                                lsp::InsertReplaceEdit {
23122                                    new_text: snippet.body.clone(),
23123                                    insert: lsp_range,
23124                                    replace: lsp_range,
23125                                },
23126                            )),
23127                            filter_text: Some(snippet.body.clone()),
23128                            sort_text: Some(char::MAX.to_string()),
23129                            ..lsp::CompletionItem::default()
23130                        }),
23131                        lsp_defaults: None,
23132                    },
23133                    label: CodeLabel::plain(matching_prefix.clone(), None),
23134                    icon_path: None,
23135                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
23136                        single_line: snippet.name.clone().into(),
23137                        plain_text: snippet
23138                            .description
23139                            .clone()
23140                            .map(|description| description.into()),
23141                    }),
23142                    insert_text_mode: None,
23143                    confirm: None,
23144                })
23145            }))
23146        }
23147
23148        Ok(CompletionResponse {
23149            completions,
23150            display_options: CompletionDisplayOptions::default(),
23151            is_incomplete,
23152        })
23153    })
23154}
23155
23156impl CompletionProvider for Entity<Project> {
23157    fn completions(
23158        &self,
23159        _excerpt_id: ExcerptId,
23160        buffer: &Entity<Buffer>,
23161        buffer_position: text::Anchor,
23162        options: CompletionContext,
23163        _window: &mut Window,
23164        cx: &mut Context<Editor>,
23165    ) -> Task<Result<Vec<CompletionResponse>>> {
23166        self.update(cx, |project, cx| {
23167            let snippets = snippet_completions(project, buffer, buffer_position, cx);
23168            let project_completions = project.completions(buffer, buffer_position, options, cx);
23169            cx.background_spawn(async move {
23170                let mut responses = project_completions.await?;
23171                let snippets = snippets.await?;
23172                if !snippets.completions.is_empty() {
23173                    responses.push(snippets);
23174                }
23175                Ok(responses)
23176            })
23177        })
23178    }
23179
23180    fn resolve_completions(
23181        &self,
23182        buffer: Entity<Buffer>,
23183        completion_indices: Vec<usize>,
23184        completions: Rc<RefCell<Box<[Completion]>>>,
23185        cx: &mut Context<Editor>,
23186    ) -> Task<Result<bool>> {
23187        self.update(cx, |project, cx| {
23188            project.lsp_store().update(cx, |lsp_store, cx| {
23189                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
23190            })
23191        })
23192    }
23193
23194    fn apply_additional_edits_for_completion(
23195        &self,
23196        buffer: Entity<Buffer>,
23197        completions: Rc<RefCell<Box<[Completion]>>>,
23198        completion_index: usize,
23199        push_to_history: bool,
23200        cx: &mut Context<Editor>,
23201    ) -> Task<Result<Option<language::Transaction>>> {
23202        self.update(cx, |project, cx| {
23203            project.lsp_store().update(cx, |lsp_store, cx| {
23204                lsp_store.apply_additional_edits_for_completion(
23205                    buffer,
23206                    completions,
23207                    completion_index,
23208                    push_to_history,
23209                    cx,
23210                )
23211            })
23212        })
23213    }
23214
23215    fn is_completion_trigger(
23216        &self,
23217        buffer: &Entity<Buffer>,
23218        position: language::Anchor,
23219        text: &str,
23220        trigger_in_words: bool,
23221        menu_is_open: bool,
23222        cx: &mut Context<Editor>,
23223    ) -> bool {
23224        let mut chars = text.chars();
23225        let char = if let Some(char) = chars.next() {
23226            char
23227        } else {
23228            return false;
23229        };
23230        if chars.next().is_some() {
23231            return false;
23232        }
23233
23234        let buffer = buffer.read(cx);
23235        let snapshot = buffer.snapshot();
23236        if !menu_is_open && !snapshot.settings_at(position, cx).show_completions_on_input {
23237            return false;
23238        }
23239        let classifier = snapshot
23240            .char_classifier_at(position)
23241            .scope_context(Some(CharScopeContext::Completion));
23242        if trigger_in_words && classifier.is_word(char) {
23243            return true;
23244        }
23245
23246        buffer.completion_triggers().contains(text)
23247    }
23248}
23249
23250impl SemanticsProvider for Entity<Project> {
23251    fn hover(
23252        &self,
23253        buffer: &Entity<Buffer>,
23254        position: text::Anchor,
23255        cx: &mut App,
23256    ) -> Option<Task<Option<Vec<project::Hover>>>> {
23257        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
23258    }
23259
23260    fn document_highlights(
23261        &self,
23262        buffer: &Entity<Buffer>,
23263        position: text::Anchor,
23264        cx: &mut App,
23265    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
23266        Some(self.update(cx, |project, cx| {
23267            project.document_highlights(buffer, position, cx)
23268        }))
23269    }
23270
23271    fn definitions(
23272        &self,
23273        buffer: &Entity<Buffer>,
23274        position: text::Anchor,
23275        kind: GotoDefinitionKind,
23276        cx: &mut App,
23277    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
23278        Some(self.update(cx, |project, cx| match kind {
23279            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
23280            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
23281            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
23282            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
23283        }))
23284    }
23285
23286    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
23287        self.update(cx, |project, cx| {
23288            if project
23289                .active_debug_session(cx)
23290                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
23291            {
23292                return true;
23293            }
23294
23295            buffer.update(cx, |buffer, cx| {
23296                project.any_language_server_supports_inlay_hints(buffer, cx)
23297            })
23298        })
23299    }
23300
23301    fn inline_values(
23302        &self,
23303        buffer_handle: Entity<Buffer>,
23304        range: Range<text::Anchor>,
23305        cx: &mut App,
23306    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
23307        self.update(cx, |project, cx| {
23308            let (session, active_stack_frame) = project.active_debug_session(cx)?;
23309
23310            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
23311        })
23312    }
23313
23314    fn applicable_inlay_chunks(
23315        &self,
23316        buffer: &Entity<Buffer>,
23317        ranges: &[Range<text::Anchor>],
23318        cx: &mut App,
23319    ) -> Vec<Range<BufferRow>> {
23320        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23321            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
23322        })
23323    }
23324
23325    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
23326        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
23327            lsp_store.invalidate_inlay_hints(for_buffers)
23328        });
23329    }
23330
23331    fn inlay_hints(
23332        &self,
23333        invalidate: InvalidationStrategy,
23334        buffer: Entity<Buffer>,
23335        ranges: Vec<Range<text::Anchor>>,
23336        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23337        cx: &mut App,
23338    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
23339        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
23340            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
23341        }))
23342    }
23343
23344    fn range_for_rename(
23345        &self,
23346        buffer: &Entity<Buffer>,
23347        position: text::Anchor,
23348        cx: &mut App,
23349    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
23350        Some(self.update(cx, |project, cx| {
23351            let buffer = buffer.clone();
23352            let task = project.prepare_rename(buffer.clone(), position, cx);
23353            cx.spawn(async move |_, cx| {
23354                Ok(match task.await? {
23355                    PrepareRenameResponse::Success(range) => Some(range),
23356                    PrepareRenameResponse::InvalidPosition => None,
23357                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
23358                        // Fallback on using TreeSitter info to determine identifier range
23359                        buffer.read_with(cx, |buffer, _| {
23360                            let snapshot = buffer.snapshot();
23361                            let (range, kind) = snapshot.surrounding_word(position, None);
23362                            if kind != Some(CharKind::Word) {
23363                                return None;
23364                            }
23365                            Some(
23366                                snapshot.anchor_before(range.start)
23367                                    ..snapshot.anchor_after(range.end),
23368                            )
23369                        })?
23370                    }
23371                })
23372            })
23373        }))
23374    }
23375
23376    fn perform_rename(
23377        &self,
23378        buffer: &Entity<Buffer>,
23379        position: text::Anchor,
23380        new_name: String,
23381        cx: &mut App,
23382    ) -> Option<Task<Result<ProjectTransaction>>> {
23383        Some(self.update(cx, |project, cx| {
23384            project.perform_rename(buffer.clone(), position, new_name, cx)
23385        }))
23386    }
23387}
23388
23389fn consume_contiguous_rows(
23390    contiguous_row_selections: &mut Vec<Selection<Point>>,
23391    selection: &Selection<Point>,
23392    display_map: &DisplaySnapshot,
23393    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
23394) -> (MultiBufferRow, MultiBufferRow) {
23395    contiguous_row_selections.push(selection.clone());
23396    let start_row = starting_row(selection, display_map);
23397    let mut end_row = ending_row(selection, display_map);
23398
23399    while let Some(next_selection) = selections.peek() {
23400        if next_selection.start.row <= end_row.0 {
23401            end_row = ending_row(next_selection, display_map);
23402            contiguous_row_selections.push(selections.next().unwrap().clone());
23403        } else {
23404            break;
23405        }
23406    }
23407    (start_row, end_row)
23408}
23409
23410fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23411    if selection.start.column > 0 {
23412        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
23413    } else {
23414        MultiBufferRow(selection.start.row)
23415    }
23416}
23417
23418fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
23419    if next_selection.end.column > 0 || next_selection.is_empty() {
23420        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
23421    } else {
23422        MultiBufferRow(next_selection.end.row)
23423    }
23424}
23425
23426impl EditorSnapshot {
23427    pub fn remote_selections_in_range<'a>(
23428        &'a self,
23429        range: &'a Range<Anchor>,
23430        collaboration_hub: &dyn CollaborationHub,
23431        cx: &'a App,
23432    ) -> impl 'a + Iterator<Item = RemoteSelection> {
23433        let participant_names = collaboration_hub.user_names(cx);
23434        let participant_indices = collaboration_hub.user_participant_indices(cx);
23435        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
23436        let collaborators_by_replica_id = collaborators_by_peer_id
23437            .values()
23438            .map(|collaborator| (collaborator.replica_id, collaborator))
23439            .collect::<HashMap<_, _>>();
23440        self.buffer_snapshot()
23441            .selections_in_range(range, false)
23442            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
23443                if replica_id == ReplicaId::AGENT {
23444                    Some(RemoteSelection {
23445                        replica_id,
23446                        selection,
23447                        cursor_shape,
23448                        line_mode,
23449                        collaborator_id: CollaboratorId::Agent,
23450                        user_name: Some("Agent".into()),
23451                        color: cx.theme().players().agent(),
23452                    })
23453                } else {
23454                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
23455                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
23456                    let user_name = participant_names.get(&collaborator.user_id).cloned();
23457                    Some(RemoteSelection {
23458                        replica_id,
23459                        selection,
23460                        cursor_shape,
23461                        line_mode,
23462                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
23463                        user_name,
23464                        color: if let Some(index) = participant_index {
23465                            cx.theme().players().color_for_participant(index.0)
23466                        } else {
23467                            cx.theme().players().absent()
23468                        },
23469                    })
23470                }
23471            })
23472    }
23473
23474    pub fn hunks_for_ranges(
23475        &self,
23476        ranges: impl IntoIterator<Item = Range<Point>>,
23477    ) -> Vec<MultiBufferDiffHunk> {
23478        let mut hunks = Vec::new();
23479        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
23480            HashMap::default();
23481        for query_range in ranges {
23482            let query_rows =
23483                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
23484            for hunk in self.buffer_snapshot().diff_hunks_in_range(
23485                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
23486            ) {
23487                // Include deleted hunks that are adjacent to the query range, because
23488                // otherwise they would be missed.
23489                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
23490                if hunk.status().is_deleted() {
23491                    intersects_range |= hunk.row_range.start == query_rows.end;
23492                    intersects_range |= hunk.row_range.end == query_rows.start;
23493                }
23494                if intersects_range {
23495                    if !processed_buffer_rows
23496                        .entry(hunk.buffer_id)
23497                        .or_default()
23498                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
23499                    {
23500                        continue;
23501                    }
23502                    hunks.push(hunk);
23503                }
23504            }
23505        }
23506
23507        hunks
23508    }
23509
23510    fn display_diff_hunks_for_rows<'a>(
23511        &'a self,
23512        display_rows: Range<DisplayRow>,
23513        folded_buffers: &'a HashSet<BufferId>,
23514    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
23515        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
23516        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
23517
23518        self.buffer_snapshot()
23519            .diff_hunks_in_range(buffer_start..buffer_end)
23520            .filter_map(|hunk| {
23521                if folded_buffers.contains(&hunk.buffer_id) {
23522                    return None;
23523                }
23524
23525                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
23526                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
23527
23528                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
23529                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
23530
23531                let display_hunk = if hunk_display_start.column() != 0 {
23532                    DisplayDiffHunk::Folded {
23533                        display_row: hunk_display_start.row(),
23534                    }
23535                } else {
23536                    let mut end_row = hunk_display_end.row();
23537                    if hunk_display_end.column() > 0 {
23538                        end_row.0 += 1;
23539                    }
23540                    let is_created_file = hunk.is_created_file();
23541                    DisplayDiffHunk::Unfolded {
23542                        status: hunk.status(),
23543                        diff_base_byte_range: hunk.diff_base_byte_range,
23544                        display_row_range: hunk_display_start.row()..end_row,
23545                        multi_buffer_range: Anchor::range_in_buffer(
23546                            hunk.excerpt_id,
23547                            hunk.buffer_id,
23548                            hunk.buffer_range,
23549                        ),
23550                        is_created_file,
23551                    }
23552                };
23553
23554                Some(display_hunk)
23555            })
23556    }
23557
23558    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
23559        self.display_snapshot
23560            .buffer_snapshot()
23561            .language_at(position)
23562    }
23563
23564    pub fn is_focused(&self) -> bool {
23565        self.is_focused
23566    }
23567
23568    pub fn placeholder_text(&self) -> Option<String> {
23569        self.placeholder_display_snapshot
23570            .as_ref()
23571            .map(|display_map| display_map.text())
23572    }
23573
23574    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
23575        self.scroll_anchor.scroll_position(&self.display_snapshot)
23576    }
23577
23578    fn gutter_dimensions(
23579        &self,
23580        font_id: FontId,
23581        font_size: Pixels,
23582        max_line_number_width: Pixels,
23583        cx: &App,
23584    ) -> Option<GutterDimensions> {
23585        if !self.show_gutter {
23586            return None;
23587        }
23588
23589        let ch_width = cx.text_system().ch_width(font_id, font_size).log_err()?;
23590        let ch_advance = cx.text_system().ch_advance(font_id, font_size).log_err()?;
23591
23592        let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
23593            matches!(
23594                ProjectSettings::get_global(cx).git.git_gutter,
23595                GitGutterSetting::TrackedFiles
23596            )
23597        });
23598        let gutter_settings = EditorSettings::get_global(cx).gutter;
23599        let show_line_numbers = self
23600            .show_line_numbers
23601            .unwrap_or(gutter_settings.line_numbers);
23602        let line_gutter_width = if show_line_numbers {
23603            // Avoid flicker-like gutter resizes when the line number gains another digit by
23604            // only resizing the gutter on files with > 10**min_line_number_digits lines.
23605            let min_width_for_number_on_gutter =
23606                ch_advance * gutter_settings.min_line_number_digits as f32;
23607            max_line_number_width.max(min_width_for_number_on_gutter)
23608        } else {
23609            0.0.into()
23610        };
23611
23612        let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
23613        let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
23614
23615        let git_blame_entries_width =
23616            self.git_blame_gutter_max_author_length
23617                .map(|max_author_length| {
23618                    let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23619                    const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
23620
23621                    /// The number of characters to dedicate to gaps and margins.
23622                    const SPACING_WIDTH: usize = 4;
23623
23624                    let max_char_count = max_author_length.min(renderer.max_author_length())
23625                        + ::git::SHORT_SHA_LENGTH
23626                        + MAX_RELATIVE_TIMESTAMP.len()
23627                        + SPACING_WIDTH;
23628
23629                    ch_advance * max_char_count
23630                });
23631
23632        let is_singleton = self.buffer_snapshot().is_singleton();
23633
23634        let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
23635        left_padding += if !is_singleton {
23636            ch_width * 4.0
23637        } else if show_runnables || show_breakpoints {
23638            ch_width * 3.0
23639        } else if show_git_gutter && show_line_numbers {
23640            ch_width * 2.0
23641        } else if show_git_gutter || show_line_numbers {
23642            ch_width
23643        } else {
23644            px(0.)
23645        };
23646
23647        let shows_folds = is_singleton && gutter_settings.folds;
23648
23649        let right_padding = if shows_folds && show_line_numbers {
23650            ch_width * 4.0
23651        } else if shows_folds || (!is_singleton && show_line_numbers) {
23652            ch_width * 3.0
23653        } else if show_line_numbers {
23654            ch_width
23655        } else {
23656            px(0.)
23657        };
23658
23659        Some(GutterDimensions {
23660            left_padding,
23661            right_padding,
23662            width: line_gutter_width + left_padding + right_padding,
23663            margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
23664            git_blame_entries_width,
23665        })
23666    }
23667
23668    pub fn render_crease_toggle(
23669        &self,
23670        buffer_row: MultiBufferRow,
23671        row_contains_cursor: bool,
23672        editor: Entity<Editor>,
23673        window: &mut Window,
23674        cx: &mut App,
23675    ) -> Option<AnyElement> {
23676        let folded = self.is_line_folded(buffer_row);
23677        let mut is_foldable = false;
23678
23679        if let Some(crease) = self
23680            .crease_snapshot
23681            .query_row(buffer_row, self.buffer_snapshot())
23682        {
23683            is_foldable = true;
23684            match crease {
23685                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
23686                    if let Some(render_toggle) = render_toggle {
23687                        let toggle_callback =
23688                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
23689                                if folded {
23690                                    editor.update(cx, |editor, cx| {
23691                                        editor.fold_at(buffer_row, window, cx)
23692                                    });
23693                                } else {
23694                                    editor.update(cx, |editor, cx| {
23695                                        editor.unfold_at(buffer_row, window, cx)
23696                                    });
23697                                }
23698                            });
23699                        return Some((render_toggle)(
23700                            buffer_row,
23701                            folded,
23702                            toggle_callback,
23703                            window,
23704                            cx,
23705                        ));
23706                    }
23707                }
23708            }
23709        }
23710
23711        is_foldable |= self.starts_indent(buffer_row);
23712
23713        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
23714            Some(
23715                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
23716                    .toggle_state(folded)
23717                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
23718                        if folded {
23719                            this.unfold_at(buffer_row, window, cx);
23720                        } else {
23721                            this.fold_at(buffer_row, window, cx);
23722                        }
23723                    }))
23724                    .into_any_element(),
23725            )
23726        } else {
23727            None
23728        }
23729    }
23730
23731    pub fn render_crease_trailer(
23732        &self,
23733        buffer_row: MultiBufferRow,
23734        window: &mut Window,
23735        cx: &mut App,
23736    ) -> Option<AnyElement> {
23737        let folded = self.is_line_folded(buffer_row);
23738        if let Crease::Inline { render_trailer, .. } = self
23739            .crease_snapshot
23740            .query_row(buffer_row, self.buffer_snapshot())?
23741        {
23742            let render_trailer = render_trailer.as_ref()?;
23743            Some(render_trailer(buffer_row, folded, window, cx))
23744        } else {
23745            None
23746        }
23747    }
23748}
23749
23750impl Deref for EditorSnapshot {
23751    type Target = DisplaySnapshot;
23752
23753    fn deref(&self) -> &Self::Target {
23754        &self.display_snapshot
23755    }
23756}
23757
23758#[derive(Clone, Debug, PartialEq, Eq)]
23759pub enum EditorEvent {
23760    InputIgnored {
23761        text: Arc<str>,
23762    },
23763    InputHandled {
23764        utf16_range_to_replace: Option<Range<isize>>,
23765        text: Arc<str>,
23766    },
23767    ExcerptsAdded {
23768        buffer: Entity<Buffer>,
23769        predecessor: ExcerptId,
23770        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
23771    },
23772    ExcerptsRemoved {
23773        ids: Vec<ExcerptId>,
23774        removed_buffer_ids: Vec<BufferId>,
23775    },
23776    BufferFoldToggled {
23777        ids: Vec<ExcerptId>,
23778        folded: bool,
23779    },
23780    ExcerptsEdited {
23781        ids: Vec<ExcerptId>,
23782    },
23783    ExcerptsExpanded {
23784        ids: Vec<ExcerptId>,
23785    },
23786    BufferEdited,
23787    Edited {
23788        transaction_id: clock::Lamport,
23789    },
23790    Reparsed(BufferId),
23791    Focused,
23792    FocusedIn,
23793    Blurred,
23794    DirtyChanged,
23795    Saved,
23796    TitleChanged,
23797    SelectionsChanged {
23798        local: bool,
23799    },
23800    ScrollPositionChanged {
23801        local: bool,
23802        autoscroll: bool,
23803    },
23804    TransactionUndone {
23805        transaction_id: clock::Lamport,
23806    },
23807    TransactionBegun {
23808        transaction_id: clock::Lamport,
23809    },
23810    CursorShapeChanged,
23811    BreadcrumbsChanged,
23812    PushedToNavHistory {
23813        anchor: Anchor,
23814        is_deactivate: bool,
23815    },
23816}
23817
23818impl EventEmitter<EditorEvent> for Editor {}
23819
23820impl Focusable for Editor {
23821    fn focus_handle(&self, _cx: &App) -> FocusHandle {
23822        self.focus_handle.clone()
23823    }
23824}
23825
23826impl Render for Editor {
23827    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
23828        let settings = ThemeSettings::get_global(cx);
23829
23830        let mut text_style = match self.mode {
23831            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23832                color: cx.theme().colors().editor_foreground,
23833                font_family: settings.ui_font.family.clone(),
23834                font_features: settings.ui_font.features.clone(),
23835                font_fallbacks: settings.ui_font.fallbacks.clone(),
23836                font_size: rems(0.875).into(),
23837                font_weight: settings.ui_font.weight,
23838                line_height: relative(settings.buffer_line_height.value()),
23839                ..Default::default()
23840            },
23841            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23842                color: cx.theme().colors().editor_foreground,
23843                font_family: settings.buffer_font.family.clone(),
23844                font_features: settings.buffer_font.features.clone(),
23845                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23846                font_size: settings.buffer_font_size(cx).into(),
23847                font_weight: settings.buffer_font.weight,
23848                line_height: relative(settings.buffer_line_height.value()),
23849                ..Default::default()
23850            },
23851        };
23852        if let Some(text_style_refinement) = &self.text_style_refinement {
23853            text_style.refine(text_style_refinement)
23854        }
23855
23856        let background = match self.mode {
23857            EditorMode::SingleLine => cx.theme().system().transparent,
23858            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23859            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23860            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23861        };
23862
23863        EditorElement::new(
23864            &cx.entity(),
23865            EditorStyle {
23866                background,
23867                border: cx.theme().colors().border,
23868                local_player: cx.theme().players().local(),
23869                text: text_style,
23870                scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23871                syntax: cx.theme().syntax().clone(),
23872                status: cx.theme().status().clone(),
23873                inlay_hints_style: make_inlay_hints_style(cx),
23874                edit_prediction_styles: make_suggestion_styles(cx),
23875                unnecessary_code_fade: ThemeSettings::get_global(cx).unnecessary_code_fade,
23876                show_underlines: self.diagnostics_enabled(),
23877            },
23878        )
23879    }
23880}
23881
23882impl EntityInputHandler for Editor {
23883    fn text_for_range(
23884        &mut self,
23885        range_utf16: Range<usize>,
23886        adjusted_range: &mut Option<Range<usize>>,
23887        _: &mut Window,
23888        cx: &mut Context<Self>,
23889    ) -> Option<String> {
23890        let snapshot = self.buffer.read(cx).read(cx);
23891        let start = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.start), Bias::Left);
23892        let end = snapshot.clip_offset_utf16(OffsetUtf16(range_utf16.end), Bias::Right);
23893        if (start.0..end.0) != range_utf16 {
23894            adjusted_range.replace(start.0..end.0);
23895        }
23896        Some(snapshot.text_for_range(start..end).collect())
23897    }
23898
23899    fn selected_text_range(
23900        &mut self,
23901        ignore_disabled_input: bool,
23902        _: &mut Window,
23903        cx: &mut Context<Self>,
23904    ) -> Option<UTF16Selection> {
23905        // Prevent the IME menu from appearing when holding down an alphabetic key
23906        // while input is disabled.
23907        if !ignore_disabled_input && !self.input_enabled {
23908            return None;
23909        }
23910
23911        let selection = self
23912            .selections
23913            .newest::<OffsetUtf16>(&self.display_snapshot(cx));
23914        let range = selection.range();
23915
23916        Some(UTF16Selection {
23917            range: range.start.0..range.end.0,
23918            reversed: selection.reversed,
23919        })
23920    }
23921
23922    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
23923        let snapshot = self.buffer.read(cx).read(cx);
23924        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
23925        Some(range.start.to_offset_utf16(&snapshot).0..range.end.to_offset_utf16(&snapshot).0)
23926    }
23927
23928    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
23929        self.clear_highlights::<InputComposition>(cx);
23930        self.ime_transaction.take();
23931    }
23932
23933    fn replace_text_in_range(
23934        &mut self,
23935        range_utf16: Option<Range<usize>>,
23936        text: &str,
23937        window: &mut Window,
23938        cx: &mut Context<Self>,
23939    ) {
23940        if !self.input_enabled {
23941            cx.emit(EditorEvent::InputIgnored { text: text.into() });
23942            return;
23943        }
23944
23945        self.transact(window, cx, |this, window, cx| {
23946            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
23947                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
23948                Some(this.selection_replacement_ranges(range_utf16, cx))
23949            } else {
23950                this.marked_text_ranges(cx)
23951            };
23952
23953            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
23954                let newest_selection_id = this.selections.newest_anchor().id;
23955                this.selections
23956                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
23957                    .iter()
23958                    .zip(ranges_to_replace.iter())
23959                    .find_map(|(selection, range)| {
23960                        if selection.id == newest_selection_id {
23961                            Some(
23962                                (range.start.0 as isize - selection.head().0 as isize)
23963                                    ..(range.end.0 as isize - selection.head().0 as isize),
23964                            )
23965                        } else {
23966                            None
23967                        }
23968                    })
23969            });
23970
23971            cx.emit(EditorEvent::InputHandled {
23972                utf16_range_to_replace: range_to_replace,
23973                text: text.into(),
23974            });
23975
23976            if let Some(new_selected_ranges) = new_selected_ranges {
23977                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23978                    selections.select_ranges(new_selected_ranges)
23979                });
23980                this.backspace(&Default::default(), window, cx);
23981            }
23982
23983            this.handle_input(text, window, cx);
23984        });
23985
23986        if let Some(transaction) = self.ime_transaction {
23987            self.buffer.update(cx, |buffer, cx| {
23988                buffer.group_until_transaction(transaction, cx);
23989            });
23990        }
23991
23992        self.unmark_text(window, cx);
23993    }
23994
23995    fn replace_and_mark_text_in_range(
23996        &mut self,
23997        range_utf16: Option<Range<usize>>,
23998        text: &str,
23999        new_selected_range_utf16: Option<Range<usize>>,
24000        window: &mut Window,
24001        cx: &mut Context<Self>,
24002    ) {
24003        if !self.input_enabled {
24004            return;
24005        }
24006
24007        let transaction = self.transact(window, cx, |this, window, cx| {
24008            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
24009                let snapshot = this.buffer.read(cx).read(cx);
24010                if let Some(relative_range_utf16) = range_utf16.as_ref() {
24011                    for marked_range in &mut marked_ranges {
24012                        marked_range.end.0 = marked_range.start.0 + relative_range_utf16.end;
24013                        marked_range.start.0 += relative_range_utf16.start;
24014                        marked_range.start =
24015                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
24016                        marked_range.end =
24017                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
24018                    }
24019                }
24020                Some(marked_ranges)
24021            } else if let Some(range_utf16) = range_utf16 {
24022                let range_utf16 = OffsetUtf16(range_utf16.start)..OffsetUtf16(range_utf16.end);
24023                Some(this.selection_replacement_ranges(range_utf16, cx))
24024            } else {
24025                None
24026            };
24027
24028            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
24029                let newest_selection_id = this.selections.newest_anchor().id;
24030                this.selections
24031                    .all::<OffsetUtf16>(&this.display_snapshot(cx))
24032                    .iter()
24033                    .zip(ranges_to_replace.iter())
24034                    .find_map(|(selection, range)| {
24035                        if selection.id == newest_selection_id {
24036                            Some(
24037                                (range.start.0 as isize - selection.head().0 as isize)
24038                                    ..(range.end.0 as isize - selection.head().0 as isize),
24039                            )
24040                        } else {
24041                            None
24042                        }
24043                    })
24044            });
24045
24046            cx.emit(EditorEvent::InputHandled {
24047                utf16_range_to_replace: range_to_replace,
24048                text: text.into(),
24049            });
24050
24051            if let Some(ranges) = ranges_to_replace {
24052                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24053                    s.select_ranges(ranges)
24054                });
24055            }
24056
24057            let marked_ranges = {
24058                let snapshot = this.buffer.read(cx).read(cx);
24059                this.selections
24060                    .disjoint_anchors_arc()
24061                    .iter()
24062                    .map(|selection| {
24063                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
24064                    })
24065                    .collect::<Vec<_>>()
24066            };
24067
24068            if text.is_empty() {
24069                this.unmark_text(window, cx);
24070            } else {
24071                this.highlight_text::<InputComposition>(
24072                    marked_ranges.clone(),
24073                    HighlightStyle {
24074                        underline: Some(UnderlineStyle {
24075                            thickness: px(1.),
24076                            color: None,
24077                            wavy: false,
24078                        }),
24079                        ..Default::default()
24080                    },
24081                    cx,
24082                );
24083            }
24084
24085            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
24086            let use_autoclose = this.use_autoclose;
24087            let use_auto_surround = this.use_auto_surround;
24088            this.set_use_autoclose(false);
24089            this.set_use_auto_surround(false);
24090            this.handle_input(text, window, cx);
24091            this.set_use_autoclose(use_autoclose);
24092            this.set_use_auto_surround(use_auto_surround);
24093
24094            if let Some(new_selected_range) = new_selected_range_utf16 {
24095                let snapshot = this.buffer.read(cx).read(cx);
24096                let new_selected_ranges = marked_ranges
24097                    .into_iter()
24098                    .map(|marked_range| {
24099                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
24100                        let new_start = OffsetUtf16(new_selected_range.start + insertion_start);
24101                        let new_end = OffsetUtf16(new_selected_range.end + insertion_start);
24102                        snapshot.clip_offset_utf16(new_start, Bias::Left)
24103                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
24104                    })
24105                    .collect::<Vec<_>>();
24106
24107                drop(snapshot);
24108                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24109                    selections.select_ranges(new_selected_ranges)
24110                });
24111            }
24112        });
24113
24114        self.ime_transaction = self.ime_transaction.or(transaction);
24115        if let Some(transaction) = self.ime_transaction {
24116            self.buffer.update(cx, |buffer, cx| {
24117                buffer.group_until_transaction(transaction, cx);
24118            });
24119        }
24120
24121        if self.text_highlights::<InputComposition>(cx).is_none() {
24122            self.ime_transaction.take();
24123        }
24124    }
24125
24126    fn bounds_for_range(
24127        &mut self,
24128        range_utf16: Range<usize>,
24129        element_bounds: gpui::Bounds<Pixels>,
24130        window: &mut Window,
24131        cx: &mut Context<Self>,
24132    ) -> Option<gpui::Bounds<Pixels>> {
24133        let text_layout_details = self.text_layout_details(window);
24134        let CharacterDimensions {
24135            em_width,
24136            em_advance,
24137            line_height,
24138        } = self.character_dimensions(window);
24139
24140        let snapshot = self.snapshot(window, cx);
24141        let scroll_position = snapshot.scroll_position();
24142        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
24143
24144        let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
24145        let x = Pixels::from(
24146            ScrollOffset::from(
24147                snapshot.x_for_display_point(start, &text_layout_details)
24148                    + self.gutter_dimensions.full_width(),
24149            ) - scroll_left,
24150        );
24151        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
24152
24153        Some(Bounds {
24154            origin: element_bounds.origin + point(x, y),
24155            size: size(em_width, line_height),
24156        })
24157    }
24158
24159    fn character_index_for_point(
24160        &mut self,
24161        point: gpui::Point<Pixels>,
24162        _window: &mut Window,
24163        _cx: &mut Context<Self>,
24164    ) -> Option<usize> {
24165        let position_map = self.last_position_map.as_ref()?;
24166        if !position_map.text_hitbox.contains(&point) {
24167            return None;
24168        }
24169        let display_point = position_map.point_for_position(point).previous_valid;
24170        let anchor = position_map
24171            .snapshot
24172            .display_point_to_anchor(display_point, Bias::Left);
24173        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
24174        Some(utf16_offset.0)
24175    }
24176}
24177
24178trait SelectionExt {
24179    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
24180    fn spanned_rows(
24181        &self,
24182        include_end_if_at_line_start: bool,
24183        map: &DisplaySnapshot,
24184    ) -> Range<MultiBufferRow>;
24185}
24186
24187impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
24188    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
24189        let start = self
24190            .start
24191            .to_point(map.buffer_snapshot())
24192            .to_display_point(map);
24193        let end = self
24194            .end
24195            .to_point(map.buffer_snapshot())
24196            .to_display_point(map);
24197        if self.reversed {
24198            end..start
24199        } else {
24200            start..end
24201        }
24202    }
24203
24204    fn spanned_rows(
24205        &self,
24206        include_end_if_at_line_start: bool,
24207        map: &DisplaySnapshot,
24208    ) -> Range<MultiBufferRow> {
24209        let start = self.start.to_point(map.buffer_snapshot());
24210        let mut end = self.end.to_point(map.buffer_snapshot());
24211        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
24212            end.row -= 1;
24213        }
24214
24215        let buffer_start = map.prev_line_boundary(start).0;
24216        let buffer_end = map.next_line_boundary(end).0;
24217        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
24218    }
24219}
24220
24221impl<T: InvalidationRegion> InvalidationStack<T> {
24222    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
24223    where
24224        S: Clone + ToOffset,
24225    {
24226        while let Some(region) = self.last() {
24227            let all_selections_inside_invalidation_ranges =
24228                if selections.len() == region.ranges().len() {
24229                    selections
24230                        .iter()
24231                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
24232                        .all(|(selection, invalidation_range)| {
24233                            let head = selection.head().to_offset(buffer);
24234                            invalidation_range.start <= head && invalidation_range.end >= head
24235                        })
24236                } else {
24237                    false
24238                };
24239
24240            if all_selections_inside_invalidation_ranges {
24241                break;
24242            } else {
24243                self.pop();
24244            }
24245        }
24246    }
24247}
24248
24249impl<T> Default for InvalidationStack<T> {
24250    fn default() -> Self {
24251        Self(Default::default())
24252    }
24253}
24254
24255impl<T> Deref for InvalidationStack<T> {
24256    type Target = Vec<T>;
24257
24258    fn deref(&self) -> &Self::Target {
24259        &self.0
24260    }
24261}
24262
24263impl<T> DerefMut for InvalidationStack<T> {
24264    fn deref_mut(&mut self) -> &mut Self::Target {
24265        &mut self.0
24266    }
24267}
24268
24269impl InvalidationRegion for SnippetState {
24270    fn ranges(&self) -> &[Range<Anchor>] {
24271        &self.ranges[self.active_index]
24272    }
24273}
24274
24275fn edit_prediction_edit_text(
24276    current_snapshot: &BufferSnapshot,
24277    edits: &[(Range<Anchor>, String)],
24278    edit_preview: &EditPreview,
24279    include_deletions: bool,
24280    cx: &App,
24281) -> HighlightedText {
24282    let edits = edits
24283        .iter()
24284        .map(|(anchor, text)| {
24285            (
24286                anchor.start.text_anchor..anchor.end.text_anchor,
24287                text.clone(),
24288            )
24289        })
24290        .collect::<Vec<_>>();
24291
24292    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
24293}
24294
24295fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, String)], cx: &App) -> HighlightedText {
24296    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
24297    // Just show the raw edit text with basic styling
24298    let mut text = String::new();
24299    let mut highlights = Vec::new();
24300
24301    let insertion_highlight_style = HighlightStyle {
24302        color: Some(cx.theme().colors().text),
24303        ..Default::default()
24304    };
24305
24306    for (_, edit_text) in edits {
24307        let start_offset = text.len();
24308        text.push_str(edit_text);
24309        let end_offset = text.len();
24310
24311        if start_offset < end_offset {
24312            highlights.push((start_offset..end_offset, insertion_highlight_style));
24313        }
24314    }
24315
24316    HighlightedText {
24317        text: text.into(),
24318        highlights,
24319    }
24320}
24321
24322pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
24323    match severity {
24324        lsp::DiagnosticSeverity::ERROR => colors.error,
24325        lsp::DiagnosticSeverity::WARNING => colors.warning,
24326        lsp::DiagnosticSeverity::INFORMATION => colors.info,
24327        lsp::DiagnosticSeverity::HINT => colors.info,
24328        _ => colors.ignored,
24329    }
24330}
24331
24332pub fn styled_runs_for_code_label<'a>(
24333    label: &'a CodeLabel,
24334    syntax_theme: &'a theme::SyntaxTheme,
24335) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
24336    let fade_out = HighlightStyle {
24337        fade_out: Some(0.35),
24338        ..Default::default()
24339    };
24340
24341    let mut prev_end = label.filter_range.end;
24342    label
24343        .runs
24344        .iter()
24345        .enumerate()
24346        .flat_map(move |(ix, (range, highlight_id))| {
24347            let style = if let Some(style) = highlight_id.style(syntax_theme) {
24348                style
24349            } else {
24350                return Default::default();
24351            };
24352            let muted_style = style.highlight(fade_out);
24353
24354            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
24355            if range.start >= label.filter_range.end {
24356                if range.start > prev_end {
24357                    runs.push((prev_end..range.start, fade_out));
24358                }
24359                runs.push((range.clone(), muted_style));
24360            } else if range.end <= label.filter_range.end {
24361                runs.push((range.clone(), style));
24362            } else {
24363                runs.push((range.start..label.filter_range.end, style));
24364                runs.push((label.filter_range.end..range.end, muted_style));
24365            }
24366            prev_end = cmp::max(prev_end, range.end);
24367
24368            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
24369                runs.push((prev_end..label.text.len(), fade_out));
24370            }
24371
24372            runs
24373        })
24374}
24375
24376pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
24377    let mut prev_index = 0;
24378    let mut prev_codepoint: Option<char> = None;
24379    text.char_indices()
24380        .chain([(text.len(), '\0')])
24381        .filter_map(move |(index, codepoint)| {
24382            let prev_codepoint = prev_codepoint.replace(codepoint)?;
24383            let is_boundary = index == text.len()
24384                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
24385                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
24386            if is_boundary {
24387                let chunk = &text[prev_index..index];
24388                prev_index = index;
24389                Some(chunk)
24390            } else {
24391                None
24392            }
24393        })
24394}
24395
24396pub trait RangeToAnchorExt: Sized {
24397    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
24398
24399    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
24400        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
24401        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
24402    }
24403}
24404
24405impl<T: ToOffset> RangeToAnchorExt for Range<T> {
24406    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
24407        let start_offset = self.start.to_offset(snapshot);
24408        let end_offset = self.end.to_offset(snapshot);
24409        if start_offset == end_offset {
24410            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
24411        } else {
24412            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
24413        }
24414    }
24415}
24416
24417pub trait RowExt {
24418    fn as_f64(&self) -> f64;
24419
24420    fn next_row(&self) -> Self;
24421
24422    fn previous_row(&self) -> Self;
24423
24424    fn minus(&self, other: Self) -> u32;
24425}
24426
24427impl RowExt for DisplayRow {
24428    fn as_f64(&self) -> f64 {
24429        self.0 as _
24430    }
24431
24432    fn next_row(&self) -> Self {
24433        Self(self.0 + 1)
24434    }
24435
24436    fn previous_row(&self) -> Self {
24437        Self(self.0.saturating_sub(1))
24438    }
24439
24440    fn minus(&self, other: Self) -> u32 {
24441        self.0 - other.0
24442    }
24443}
24444
24445impl RowExt for MultiBufferRow {
24446    fn as_f64(&self) -> f64 {
24447        self.0 as _
24448    }
24449
24450    fn next_row(&self) -> Self {
24451        Self(self.0 + 1)
24452    }
24453
24454    fn previous_row(&self) -> Self {
24455        Self(self.0.saturating_sub(1))
24456    }
24457
24458    fn minus(&self, other: Self) -> u32 {
24459        self.0 - other.0
24460    }
24461}
24462
24463trait RowRangeExt {
24464    type Row;
24465
24466    fn len(&self) -> usize;
24467
24468    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
24469}
24470
24471impl RowRangeExt for Range<MultiBufferRow> {
24472    type Row = MultiBufferRow;
24473
24474    fn len(&self) -> usize {
24475        (self.end.0 - self.start.0) as usize
24476    }
24477
24478    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
24479        (self.start.0..self.end.0).map(MultiBufferRow)
24480    }
24481}
24482
24483impl RowRangeExt for Range<DisplayRow> {
24484    type Row = DisplayRow;
24485
24486    fn len(&self) -> usize {
24487        (self.end.0 - self.start.0) as usize
24488    }
24489
24490    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
24491        (self.start.0..self.end.0).map(DisplayRow)
24492    }
24493}
24494
24495/// If select range has more than one line, we
24496/// just point the cursor to range.start.
24497fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
24498    if range.start.row == range.end.row {
24499        range
24500    } else {
24501        range.start..range.start
24502    }
24503}
24504pub struct KillRing(ClipboardItem);
24505impl Global for KillRing {}
24506
24507const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
24508
24509enum BreakpointPromptEditAction {
24510    Log,
24511    Condition,
24512    HitCondition,
24513}
24514
24515struct BreakpointPromptEditor {
24516    pub(crate) prompt: Entity<Editor>,
24517    editor: WeakEntity<Editor>,
24518    breakpoint_anchor: Anchor,
24519    breakpoint: Breakpoint,
24520    edit_action: BreakpointPromptEditAction,
24521    block_ids: HashSet<CustomBlockId>,
24522    editor_margins: Arc<Mutex<EditorMargins>>,
24523    _subscriptions: Vec<Subscription>,
24524}
24525
24526impl BreakpointPromptEditor {
24527    const MAX_LINES: u8 = 4;
24528
24529    fn new(
24530        editor: WeakEntity<Editor>,
24531        breakpoint_anchor: Anchor,
24532        breakpoint: Breakpoint,
24533        edit_action: BreakpointPromptEditAction,
24534        window: &mut Window,
24535        cx: &mut Context<Self>,
24536    ) -> Self {
24537        let base_text = match edit_action {
24538            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
24539            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
24540            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
24541        }
24542        .map(|msg| msg.to_string())
24543        .unwrap_or_default();
24544
24545        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
24546        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
24547
24548        let prompt = cx.new(|cx| {
24549            let mut prompt = Editor::new(
24550                EditorMode::AutoHeight {
24551                    min_lines: 1,
24552                    max_lines: Some(Self::MAX_LINES as usize),
24553                },
24554                buffer,
24555                None,
24556                window,
24557                cx,
24558            );
24559            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
24560            prompt.set_show_cursor_when_unfocused(false, cx);
24561            prompt.set_placeholder_text(
24562                match edit_action {
24563                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
24564                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
24565                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
24566                },
24567                window,
24568                cx,
24569            );
24570
24571            prompt
24572        });
24573
24574        Self {
24575            prompt,
24576            editor,
24577            breakpoint_anchor,
24578            breakpoint,
24579            edit_action,
24580            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
24581            block_ids: Default::default(),
24582            _subscriptions: vec![],
24583        }
24584    }
24585
24586    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
24587        self.block_ids.extend(block_ids)
24588    }
24589
24590    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
24591        if let Some(editor) = self.editor.upgrade() {
24592            let message = self
24593                .prompt
24594                .read(cx)
24595                .buffer
24596                .read(cx)
24597                .as_singleton()
24598                .expect("A multi buffer in breakpoint prompt isn't possible")
24599                .read(cx)
24600                .as_rope()
24601                .to_string();
24602
24603            editor.update(cx, |editor, cx| {
24604                editor.edit_breakpoint_at_anchor(
24605                    self.breakpoint_anchor,
24606                    self.breakpoint.clone(),
24607                    match self.edit_action {
24608                        BreakpointPromptEditAction::Log => {
24609                            BreakpointEditAction::EditLogMessage(message.into())
24610                        }
24611                        BreakpointPromptEditAction::Condition => {
24612                            BreakpointEditAction::EditCondition(message.into())
24613                        }
24614                        BreakpointPromptEditAction::HitCondition => {
24615                            BreakpointEditAction::EditHitCondition(message.into())
24616                        }
24617                    },
24618                    cx,
24619                );
24620
24621                editor.remove_blocks(self.block_ids.clone(), None, cx);
24622                cx.focus_self(window);
24623            });
24624        }
24625    }
24626
24627    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
24628        self.editor
24629            .update(cx, |editor, cx| {
24630                editor.remove_blocks(self.block_ids.clone(), None, cx);
24631                window.focus(&editor.focus_handle);
24632            })
24633            .log_err();
24634    }
24635
24636    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
24637        let settings = ThemeSettings::get_global(cx);
24638        let text_style = TextStyle {
24639            color: if self.prompt.read(cx).read_only(cx) {
24640                cx.theme().colors().text_disabled
24641            } else {
24642                cx.theme().colors().text
24643            },
24644            font_family: settings.buffer_font.family.clone(),
24645            font_fallbacks: settings.buffer_font.fallbacks.clone(),
24646            font_size: settings.buffer_font_size(cx).into(),
24647            font_weight: settings.buffer_font.weight,
24648            line_height: relative(settings.buffer_line_height.value()),
24649            ..Default::default()
24650        };
24651        EditorElement::new(
24652            &self.prompt,
24653            EditorStyle {
24654                background: cx.theme().colors().editor_background,
24655                local_player: cx.theme().players().local(),
24656                text: text_style,
24657                ..Default::default()
24658            },
24659        )
24660    }
24661}
24662
24663impl Render for BreakpointPromptEditor {
24664    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24665        let editor_margins = *self.editor_margins.lock();
24666        let gutter_dimensions = editor_margins.gutter;
24667        h_flex()
24668            .key_context("Editor")
24669            .bg(cx.theme().colors().editor_background)
24670            .border_y_1()
24671            .border_color(cx.theme().status().info_border)
24672            .size_full()
24673            .py(window.line_height() / 2.5)
24674            .on_action(cx.listener(Self::confirm))
24675            .on_action(cx.listener(Self::cancel))
24676            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
24677            .child(div().flex_1().child(self.render_prompt_editor(cx)))
24678    }
24679}
24680
24681impl Focusable for BreakpointPromptEditor {
24682    fn focus_handle(&self, cx: &App) -> FocusHandle {
24683        self.prompt.focus_handle(cx)
24684    }
24685}
24686
24687fn all_edits_insertions_or_deletions(
24688    edits: &Vec<(Range<Anchor>, String)>,
24689    snapshot: &MultiBufferSnapshot,
24690) -> bool {
24691    let mut all_insertions = true;
24692    let mut all_deletions = true;
24693
24694    for (range, new_text) in edits.iter() {
24695        let range_is_empty = range.to_offset(snapshot).is_empty();
24696        let text_is_empty = new_text.is_empty();
24697
24698        if range_is_empty != text_is_empty {
24699            if range_is_empty {
24700                all_deletions = false;
24701            } else {
24702                all_insertions = false;
24703            }
24704        } else {
24705            return false;
24706        }
24707
24708        if !all_insertions && !all_deletions {
24709            return false;
24710        }
24711    }
24712    all_insertions || all_deletions
24713}
24714
24715struct MissingEditPredictionKeybindingTooltip;
24716
24717impl Render for MissingEditPredictionKeybindingTooltip {
24718    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
24719        ui::tooltip_container(cx, |container, cx| {
24720            container
24721                .flex_shrink_0()
24722                .max_w_80()
24723                .min_h(rems_from_px(124.))
24724                .justify_between()
24725                .child(
24726                    v_flex()
24727                        .flex_1()
24728                        .text_ui_sm(cx)
24729                        .child(Label::new("Conflict with Accept Keybinding"))
24730                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
24731                )
24732                .child(
24733                    h_flex()
24734                        .pb_1()
24735                        .gap_1()
24736                        .items_end()
24737                        .w_full()
24738                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
24739                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
24740                        }))
24741                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
24742                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
24743                        })),
24744                )
24745        })
24746    }
24747}
24748
24749#[derive(Debug, Clone, Copy, PartialEq)]
24750pub struct LineHighlight {
24751    pub background: Background,
24752    pub border: Option<gpui::Hsla>,
24753    pub include_gutter: bool,
24754    pub type_id: Option<TypeId>,
24755}
24756
24757struct LineManipulationResult {
24758    pub new_text: String,
24759    pub line_count_before: usize,
24760    pub line_count_after: usize,
24761}
24762
24763fn render_diff_hunk_controls(
24764    row: u32,
24765    status: &DiffHunkStatus,
24766    hunk_range: Range<Anchor>,
24767    is_created_file: bool,
24768    line_height: Pixels,
24769    editor: &Entity<Editor>,
24770    _window: &mut Window,
24771    cx: &mut App,
24772) -> AnyElement {
24773    h_flex()
24774        .h(line_height)
24775        .mr_1()
24776        .gap_1()
24777        .px_0p5()
24778        .pb_1()
24779        .border_x_1()
24780        .border_b_1()
24781        .border_color(cx.theme().colors().border_variant)
24782        .rounded_b_lg()
24783        .bg(cx.theme().colors().editor_background)
24784        .gap_1()
24785        .block_mouse_except_scroll()
24786        .shadow_md()
24787        .child(if status.has_secondary_hunk() {
24788            Button::new(("stage", row as u64), "Stage")
24789                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24790                .tooltip({
24791                    let focus_handle = editor.focus_handle(cx);
24792                    move |_window, cx| {
24793                        Tooltip::for_action_in(
24794                            "Stage Hunk",
24795                            &::git::ToggleStaged,
24796                            &focus_handle,
24797                            cx,
24798                        )
24799                    }
24800                })
24801                .on_click({
24802                    let editor = editor.clone();
24803                    move |_event, _window, cx| {
24804                        editor.update(cx, |editor, cx| {
24805                            editor.stage_or_unstage_diff_hunks(
24806                                true,
24807                                vec![hunk_range.start..hunk_range.start],
24808                                cx,
24809                            );
24810                        });
24811                    }
24812                })
24813        } else {
24814            Button::new(("unstage", row as u64), "Unstage")
24815                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
24816                .tooltip({
24817                    let focus_handle = editor.focus_handle(cx);
24818                    move |_window, cx| {
24819                        Tooltip::for_action_in(
24820                            "Unstage Hunk",
24821                            &::git::ToggleStaged,
24822                            &focus_handle,
24823                            cx,
24824                        )
24825                    }
24826                })
24827                .on_click({
24828                    let editor = editor.clone();
24829                    move |_event, _window, cx| {
24830                        editor.update(cx, |editor, cx| {
24831                            editor.stage_or_unstage_diff_hunks(
24832                                false,
24833                                vec![hunk_range.start..hunk_range.start],
24834                                cx,
24835                            );
24836                        });
24837                    }
24838                })
24839        })
24840        .child(
24841            Button::new(("restore", row as u64), "Restore")
24842                .tooltip({
24843                    let focus_handle = editor.focus_handle(cx);
24844                    move |_window, cx| {
24845                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
24846                    }
24847                })
24848                .on_click({
24849                    let editor = editor.clone();
24850                    move |_event, window, cx| {
24851                        editor.update(cx, |editor, cx| {
24852                            let snapshot = editor.snapshot(window, cx);
24853                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
24854                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
24855                        });
24856                    }
24857                })
24858                .disabled(is_created_file),
24859        )
24860        .when(
24861            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
24862            |el| {
24863                el.child(
24864                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
24865                        .shape(IconButtonShape::Square)
24866                        .icon_size(IconSize::Small)
24867                        // .disabled(!has_multiple_hunks)
24868                        .tooltip({
24869                            let focus_handle = editor.focus_handle(cx);
24870                            move |_window, cx| {
24871                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
24872                            }
24873                        })
24874                        .on_click({
24875                            let editor = editor.clone();
24876                            move |_event, window, cx| {
24877                                editor.update(cx, |editor, cx| {
24878                                    let snapshot = editor.snapshot(window, cx);
24879                                    let position =
24880                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
24881                                    editor.go_to_hunk_before_or_after_position(
24882                                        &snapshot,
24883                                        position,
24884                                        Direction::Next,
24885                                        window,
24886                                        cx,
24887                                    );
24888                                    editor.expand_selected_diff_hunks(cx);
24889                                });
24890                            }
24891                        }),
24892                )
24893                .child(
24894                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
24895                        .shape(IconButtonShape::Square)
24896                        .icon_size(IconSize::Small)
24897                        // .disabled(!has_multiple_hunks)
24898                        .tooltip({
24899                            let focus_handle = editor.focus_handle(cx);
24900                            move |_window, cx| {
24901                                Tooltip::for_action_in(
24902                                    "Previous Hunk",
24903                                    &GoToPreviousHunk,
24904                                    &focus_handle,
24905                                    cx,
24906                                )
24907                            }
24908                        })
24909                        .on_click({
24910                            let editor = editor.clone();
24911                            move |_event, window, cx| {
24912                                editor.update(cx, |editor, cx| {
24913                                    let snapshot = editor.snapshot(window, cx);
24914                                    let point =
24915                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
24916                                    editor.go_to_hunk_before_or_after_position(
24917                                        &snapshot,
24918                                        point,
24919                                        Direction::Prev,
24920                                        window,
24921                                        cx,
24922                                    );
24923                                    editor.expand_selected_diff_hunks(cx);
24924                                });
24925                            }
24926                        }),
24927                )
24928            },
24929        )
24930        .into_any_element()
24931}
24932
24933pub fn multibuffer_context_lines(cx: &App) -> u32 {
24934    EditorSettings::try_get(cx)
24935        .map(|settings| settings.excerpt_context_lines)
24936        .unwrap_or(2)
24937        .min(32)
24938}