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;
   15pub mod blink_manager;
   16mod bracket_colorization;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod editor_settings;
   21mod element;
   22mod git;
   23mod highlight_matching_bracket;
   24mod hover_links;
   25pub mod hover_popover;
   26mod indent_guides;
   27mod inlays;
   28pub mod items;
   29mod jsx_tag_auto_close;
   30mod linked_editing_ranges;
   31mod lsp_colors;
   32mod lsp_ext;
   33mod mouse_context_menu;
   34pub mod movement;
   35mod persistence;
   36mod rust_analyzer_ext;
   37pub mod scroll;
   38mod selections_collection;
   39mod split;
   40pub mod tasks;
   41
   42#[cfg(test)]
   43mod code_completion_tests;
   44#[cfg(test)]
   45mod edit_prediction_tests;
   46#[cfg(test)]
   47mod editor_tests;
   48mod signature_help;
   49#[cfg(any(test, feature = "test-support"))]
   50pub mod test;
   51
   52pub(crate) use actions::*;
   53pub use display_map::{ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder};
   54pub use edit_prediction_types::Direction;
   55pub use editor_settings::{
   56    CurrentLineHighlight, DocumentColorsRenderMode, EditorSettings, HideMouseMode,
   57    ScrollBeyondLastLine, ScrollbarAxes, SearchSettings, ShowMinimap,
   58};
   59pub use element::{
   60    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   61};
   62pub use git::blame::BlameRenderer;
   63pub use hover_popover::hover_markdown_style;
   64pub use inlays::Inlay;
   65pub use items::MAX_TAB_TITLE_LEN;
   66pub use lsp::CompletionContext;
   67pub use lsp_ext::lsp_tasks;
   68pub use multi_buffer::{
   69    Anchor, AnchorRangeExt, BufferOffset, ExcerptId, ExcerptRange, MBTextSummary, MultiBuffer,
   70    MultiBufferOffset, MultiBufferOffsetUtf16, MultiBufferSnapshot, PathKey, RowInfo, ToOffset,
   71    ToPoint,
   72};
   73pub use split::SplittableEditor;
   74pub use text::Bias;
   75
   76use ::git::{
   77    Restore,
   78    blame::{BlameEntry, ParsedCommitMessage},
   79    status::FileStatus,
   80};
   81use aho_corasick::{AhoCorasick, AhoCorasickBuilder, BuildError};
   82use anyhow::{Context as _, Result, anyhow, bail};
   83use blink_manager::BlinkManager;
   84use buffer_diff::DiffHunkStatus;
   85use client::{Collaborator, ParticipantIndex, parse_zed_link};
   86use clock::ReplicaId;
   87use code_context_menus::{
   88    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   89    CompletionsMenu, ContextMenuOrigin,
   90};
   91use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   92use convert_case::{Case, Casing};
   93use dap::TelemetrySpawnLocation;
   94use display_map::*;
   95use edit_prediction_types::{
   96    EditPredictionDelegate, EditPredictionDelegateHandle, EditPredictionGranularity,
   97};
   98use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
   99use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
  100use futures::{
  101    FutureExt, StreamExt as _,
  102    future::{self, Shared, join},
  103    stream::FuturesUnordered,
  104};
  105use fuzzy::{StringMatch, StringMatchCandidate};
  106use git::blame::{GitBlame, GlobalBlameRenderer};
  107use gpui::{
  108    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  109    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  110    DispatchPhase, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent,
  111    Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla, KeyContext, Modifiers,
  112    MouseButton, MouseDownEvent, MouseMoveEvent, PaintQuad, ParentElement, Pixels, PressureStage,
  113    Render, ScrollHandle, SharedString, Size, Stateful, Styled, Subscription, Task, TextRun,
  114    TextStyle, TextStyleRefinement, UTF16Selection, UnderlineStyle, UniformListScrollHandle,
  115    WeakEntity, WeakFocusHandle, Window, div, point, prelude::*, pulsating_between, px, relative,
  116    size,
  117};
  118use hover_links::{HoverLink, HoveredLinkState, find_file};
  119use hover_popover::{HoverState, hide_hover};
  120use indent_guides::ActiveIndentGuidesState;
  121use inlays::{InlaySplice, inlay_hints::InlayHintRefreshReason};
  122use itertools::{Either, Itertools};
  123use language::{
  124    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  125    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  126    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  127    IndentSize, Language, LanguageName, LanguageRegistry, OffsetRangeExt, OutlineItem, Point,
  128    Runnable, Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions, WordsQuery,
  129    language_settings::{
  130        self, LanguageSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  131        all_language_settings, language_settings,
  132    },
  133    point_from_lsp, point_to_lsp, text_diff_with_options,
  134};
  135use linked_editing_ranges::refresh_linked_ranges;
  136use lsp::{
  137    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  138    LanguageServerId,
  139};
  140use lsp_colors::LspColorData;
  141use markdown::Markdown;
  142use mouse_context_menu::MouseContextMenu;
  143use movement::TextLayoutDetails;
  144use multi_buffer::{
  145    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  146};
  147use parking_lot::Mutex;
  148use persistence::DB;
  149use project::{
  150    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  151    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, InlayId,
  152    InvalidationStrategy, Location, LocationLink, LspAction, PrepareRenameResponse, Project,
  153    ProjectItem, ProjectPath, ProjectTransaction, TaskSourceKind,
  154    debugger::{
  155        breakpoint_store::{
  156            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  157            BreakpointStore, BreakpointStoreEvent,
  158        },
  159        session::{Session, SessionEvent},
  160    },
  161    git_store::GitStoreEvent,
  162    lsp_store::{
  163        CacheInlayHints, CompletionDocumentation, FormatTrigger, LspFormatTarget,
  164        OpenLspBufferHandle,
  165    },
  166    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  167};
  168use rand::seq::SliceRandom;
  169use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  170use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager};
  171use selections_collection::{MutableSelectionsCollection, SelectionsCollection};
  172use serde::{Deserialize, Serialize};
  173use settings::{
  174    GitGutterSetting, RelativeLineNumbers, Settings, SettingsLocation, SettingsStore,
  175    update_settings_file,
  176};
  177use smallvec::{SmallVec, smallvec};
  178use snippet::Snippet;
  179use std::{
  180    any::{Any, TypeId},
  181    borrow::Cow,
  182    cell::{OnceCell, RefCell},
  183    cmp::{self, Ordering, Reverse},
  184    collections::hash_map,
  185    iter::{self, Peekable},
  186    mem,
  187    num::NonZeroU32,
  188    ops::{ControlFlow, Deref, DerefMut, Not, Range, RangeInclusive},
  189    path::{Path, PathBuf},
  190    rc::Rc,
  191    sync::Arc,
  192    time::{Duration, Instant},
  193};
  194use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
  195use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
  196use theme::{
  197    AccentColors, ActiveTheme, PlayerColor, StatusColors, SyntaxTheme, Theme, ThemeSettings,
  198    observe_buffer_font_size_adjustment,
  199};
  200use ui::{
  201    ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape, IconName,
  202    IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  203};
  204use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  205use vim_mode_setting::VimModeSetting;
  206use workspace::{
  207    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, OpenInTerminal, OpenTerminal,
  208    RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection, TabBarSettings, Toast,
  209    ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  210    item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  211    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  212    searchable::SearchEvent,
  213};
  214
  215use crate::{
  216    code_context_menus::CompletionsMenuSource,
  217    editor_settings::MultiCursorModifier,
  218    hover_links::{find_url, find_url_from_range},
  219    inlays::{
  220        InlineValueCache,
  221        inlay_hints::{LspInlayHintData, inlay_hint_settings},
  222    },
  223    scroll::{ScrollOffset, ScrollPixelOffset},
  224    selections_collection::resolve_selections_wrapping_blocks,
  225    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  226};
  227
  228pub const FILE_HEADER_HEIGHT: u32 = 2;
  229pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  230const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  231const MAX_LINE_LEN: usize = 1024;
  232const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  233const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  234pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  235#[doc(hidden)]
  236pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  237pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  238
  239pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  240pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  241pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  242pub const FETCH_COLORS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(150);
  243
  244pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  245pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  246pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  247
  248pub type RenderDiffHunkControlsFn = Arc<
  249    dyn Fn(
  250        u32,
  251        &DiffHunkStatus,
  252        Range<Anchor>,
  253        bool,
  254        Pixels,
  255        &Entity<Editor>,
  256        &mut Window,
  257        &mut App,
  258    ) -> AnyElement,
  259>;
  260
  261enum ReportEditorEvent {
  262    Saved { auto_saved: bool },
  263    EditorOpened,
  264    Closed,
  265}
  266
  267impl ReportEditorEvent {
  268    pub fn event_type(&self) -> &'static str {
  269        match self {
  270            Self::Saved { .. } => "Editor Saved",
  271            Self::EditorOpened => "Editor Opened",
  272            Self::Closed => "Editor Closed",
  273        }
  274    }
  275}
  276
  277pub enum ActiveDebugLine {}
  278pub enum DebugStackFrameLine {}
  279enum DocumentHighlightRead {}
  280enum DocumentHighlightWrite {}
  281enum InputComposition {}
  282pub enum PendingInput {}
  283enum SelectedTextHighlight {}
  284
  285pub enum ConflictsOuter {}
  286pub enum ConflictsOurs {}
  287pub enum ConflictsTheirs {}
  288pub enum ConflictsOursMarker {}
  289pub enum ConflictsTheirsMarker {}
  290
  291pub struct HunkAddedColor;
  292pub struct HunkRemovedColor;
  293
  294#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  295pub enum Navigated {
  296    Yes,
  297    No,
  298}
  299
  300impl Navigated {
  301    pub fn from_bool(yes: bool) -> Navigated {
  302        if yes { Navigated::Yes } else { Navigated::No }
  303    }
  304}
  305
  306#[derive(Debug, Clone, PartialEq, Eq)]
  307enum DisplayDiffHunk {
  308    Folded {
  309        display_row: DisplayRow,
  310    },
  311    Unfolded {
  312        is_created_file: bool,
  313        diff_base_byte_range: Range<usize>,
  314        display_row_range: Range<DisplayRow>,
  315        multi_buffer_range: Range<Anchor>,
  316        status: DiffHunkStatus,
  317        word_diffs: Vec<Range<MultiBufferOffset>>,
  318    },
  319}
  320
  321pub enum HideMouseCursorOrigin {
  322    TypingAction,
  323    MovementAction,
  324}
  325
  326pub fn init(cx: &mut App) {
  327    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  328
  329    workspace::register_project_item::<Editor>(cx);
  330    workspace::FollowableViewRegistry::register::<Editor>(cx);
  331    workspace::register_serializable_item::<Editor>(cx);
  332
  333    cx.observe_new(
  334        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  335            workspace.register_action(Editor::new_file);
  336            workspace.register_action(Editor::new_file_split);
  337            workspace.register_action(Editor::new_file_vertical);
  338            workspace.register_action(Editor::new_file_horizontal);
  339            workspace.register_action(Editor::cancel_language_server_work);
  340            workspace.register_action(Editor::toggle_focus);
  341        },
  342    )
  343    .detach();
  344
  345    cx.on_action(move |_: &workspace::NewFile, cx| {
  346        let app_state = workspace::AppState::global(cx);
  347        if let Some(app_state) = app_state.upgrade() {
  348            workspace::open_new(
  349                Default::default(),
  350                app_state,
  351                cx,
  352                |workspace, window, cx| {
  353                    Editor::new_file(workspace, &Default::default(), window, cx)
  354                },
  355            )
  356            .detach();
  357        }
  358    })
  359    .on_action(move |_: &workspace::NewWindow, cx| {
  360        let app_state = workspace::AppState::global(cx);
  361        if let Some(app_state) = app_state.upgrade() {
  362            workspace::open_new(
  363                Default::default(),
  364                app_state,
  365                cx,
  366                |workspace, window, cx| {
  367                    cx.activate(true);
  368                    Editor::new_file(workspace, &Default::default(), window, cx)
  369                },
  370            )
  371            .detach();
  372        }
  373    });
  374}
  375
  376pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  377    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  378}
  379
  380pub trait DiagnosticRenderer {
  381    fn render_group(
  382        &self,
  383        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  384        buffer_id: BufferId,
  385        snapshot: EditorSnapshot,
  386        editor: WeakEntity<Editor>,
  387        language_registry: Option<Arc<LanguageRegistry>>,
  388        cx: &mut App,
  389    ) -> Vec<BlockProperties<Anchor>>;
  390
  391    fn render_hover(
  392        &self,
  393        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  394        range: Range<Point>,
  395        buffer_id: BufferId,
  396        language_registry: Option<Arc<LanguageRegistry>>,
  397        cx: &mut App,
  398    ) -> Option<Entity<markdown::Markdown>>;
  399
  400    fn open_link(
  401        &self,
  402        editor: &mut Editor,
  403        link: SharedString,
  404        window: &mut Window,
  405        cx: &mut Context<Editor>,
  406    );
  407}
  408
  409pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  410
  411impl GlobalDiagnosticRenderer {
  412    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  413        cx.try_global::<Self>().map(|g| g.0.clone())
  414    }
  415}
  416
  417impl gpui::Global for GlobalDiagnosticRenderer {}
  418pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  419    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  420}
  421
  422pub struct SearchWithinRange;
  423
  424trait InvalidationRegion {
  425    fn ranges(&self) -> &[Range<Anchor>];
  426}
  427
  428#[derive(Clone, Debug, PartialEq)]
  429pub enum SelectPhase {
  430    Begin {
  431        position: DisplayPoint,
  432        add: bool,
  433        click_count: usize,
  434    },
  435    BeginColumnar {
  436        position: DisplayPoint,
  437        reset: bool,
  438        mode: ColumnarMode,
  439        goal_column: u32,
  440    },
  441    Extend {
  442        position: DisplayPoint,
  443        click_count: usize,
  444    },
  445    Update {
  446        position: DisplayPoint,
  447        goal_column: u32,
  448        scroll_delta: gpui::Point<f32>,
  449    },
  450    End,
  451}
  452
  453#[derive(Clone, Debug, PartialEq)]
  454pub enum ColumnarMode {
  455    FromMouse,
  456    FromSelection,
  457}
  458
  459#[derive(Clone, Debug)]
  460pub enum SelectMode {
  461    Character,
  462    Word(Range<Anchor>),
  463    Line(Range<Anchor>),
  464    All,
  465}
  466
  467#[derive(Copy, Clone, Default, PartialEq, Eq, Debug)]
  468pub enum SizingBehavior {
  469    /// The editor will layout itself using `size_full` and will include the vertical
  470    /// scroll margin as requested by user settings.
  471    #[default]
  472    Default,
  473    /// The editor will layout itself using `size_full`, but will not have any
  474    /// vertical overscroll.
  475    ExcludeOverscrollMargin,
  476    /// The editor will request a vertical size according to its content and will be
  477    /// layouted without a vertical scroll margin.
  478    SizeByContent,
  479}
  480
  481#[derive(Clone, PartialEq, Eq, Debug)]
  482pub enum EditorMode {
  483    SingleLine,
  484    AutoHeight {
  485        min_lines: usize,
  486        max_lines: Option<usize>,
  487    },
  488    Full {
  489        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  490        scale_ui_elements_with_buffer_font_size: bool,
  491        /// When set to `true`, the editor will render a background for the active line.
  492        show_active_line_background: bool,
  493        /// Determines the sizing behavior for this editor
  494        sizing_behavior: SizingBehavior,
  495    },
  496    Minimap {
  497        parent: WeakEntity<Editor>,
  498    },
  499}
  500
  501impl EditorMode {
  502    pub fn full() -> Self {
  503        Self::Full {
  504            scale_ui_elements_with_buffer_font_size: true,
  505            show_active_line_background: true,
  506            sizing_behavior: SizingBehavior::Default,
  507        }
  508    }
  509
  510    #[inline]
  511    pub fn is_full(&self) -> bool {
  512        matches!(self, Self::Full { .. })
  513    }
  514
  515    #[inline]
  516    pub fn is_single_line(&self) -> bool {
  517        matches!(self, Self::SingleLine { .. })
  518    }
  519
  520    #[inline]
  521    fn is_minimap(&self) -> bool {
  522        matches!(self, Self::Minimap { .. })
  523    }
  524}
  525
  526#[derive(Copy, Clone, Debug)]
  527pub enum SoftWrap {
  528    /// Prefer not to wrap at all.
  529    ///
  530    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  531    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  532    GitDiff,
  533    /// Prefer a single line generally, unless an overly long line is encountered.
  534    None,
  535    /// Soft wrap lines that exceed the editor width.
  536    EditorWidth,
  537    /// Soft wrap lines at the preferred line length.
  538    Column(u32),
  539    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  540    Bounded(u32),
  541}
  542
  543#[derive(Clone)]
  544pub struct EditorStyle {
  545    pub background: Hsla,
  546    pub border: Hsla,
  547    pub local_player: PlayerColor,
  548    pub text: TextStyle,
  549    pub scrollbar_width: Pixels,
  550    pub syntax: Arc<SyntaxTheme>,
  551    pub status: StatusColors,
  552    pub inlay_hints_style: HighlightStyle,
  553    pub edit_prediction_styles: EditPredictionStyles,
  554    pub unnecessary_code_fade: f32,
  555    pub show_underlines: bool,
  556}
  557
  558impl Default for EditorStyle {
  559    fn default() -> Self {
  560        Self {
  561            background: Hsla::default(),
  562            border: Hsla::default(),
  563            local_player: PlayerColor::default(),
  564            text: TextStyle::default(),
  565            scrollbar_width: Pixels::default(),
  566            syntax: Default::default(),
  567            // HACK: Status colors don't have a real default.
  568            // We should look into removing the status colors from the editor
  569            // style and retrieve them directly from the theme.
  570            status: StatusColors::dark(),
  571            inlay_hints_style: HighlightStyle::default(),
  572            edit_prediction_styles: EditPredictionStyles {
  573                insertion: HighlightStyle::default(),
  574                whitespace: HighlightStyle::default(),
  575            },
  576            unnecessary_code_fade: Default::default(),
  577            show_underlines: true,
  578        }
  579    }
  580}
  581
  582pub fn make_inlay_hints_style(cx: &App) -> HighlightStyle {
  583    let show_background = language_settings::language_settings(None, None, cx)
  584        .inlay_hints
  585        .show_background;
  586
  587    let mut style = cx.theme().syntax().get("hint");
  588
  589    if style.color.is_none() {
  590        style.color = Some(cx.theme().status().hint);
  591    }
  592
  593    if !show_background {
  594        style.background_color = None;
  595        return style;
  596    }
  597
  598    if style.background_color.is_none() {
  599        style.background_color = Some(cx.theme().status().hint_background);
  600    }
  601
  602    style
  603}
  604
  605pub fn make_suggestion_styles(cx: &App) -> EditPredictionStyles {
  606    EditPredictionStyles {
  607        insertion: HighlightStyle {
  608            color: Some(cx.theme().status().predictive),
  609            ..HighlightStyle::default()
  610        },
  611        whitespace: HighlightStyle {
  612            background_color: Some(cx.theme().status().created_background),
  613            ..HighlightStyle::default()
  614        },
  615    }
  616}
  617
  618type CompletionId = usize;
  619
  620pub(crate) enum EditDisplayMode {
  621    TabAccept,
  622    DiffPopover,
  623    Inline,
  624}
  625
  626enum EditPrediction {
  627    Edit {
  628        edits: Vec<(Range<Anchor>, Arc<str>)>,
  629        edit_preview: Option<EditPreview>,
  630        display_mode: EditDisplayMode,
  631        snapshot: BufferSnapshot,
  632    },
  633    /// Move to a specific location in the active editor
  634    MoveWithin {
  635        target: Anchor,
  636        snapshot: BufferSnapshot,
  637    },
  638    /// Move to a specific location in a different editor (not the active one)
  639    MoveOutside {
  640        target: language::Anchor,
  641        snapshot: BufferSnapshot,
  642    },
  643}
  644
  645struct EditPredictionState {
  646    inlay_ids: Vec<InlayId>,
  647    completion: EditPrediction,
  648    completion_id: Option<SharedString>,
  649    invalidation_range: Option<Range<Anchor>>,
  650}
  651
  652enum EditPredictionSettings {
  653    Disabled,
  654    Enabled {
  655        show_in_menu: bool,
  656        preview_requires_modifier: bool,
  657    },
  658}
  659
  660enum EditPredictionHighlight {}
  661
  662#[derive(Debug, Clone)]
  663struct InlineDiagnostic {
  664    message: SharedString,
  665    group_id: usize,
  666    is_primary: bool,
  667    start: Point,
  668    severity: lsp::DiagnosticSeverity,
  669}
  670
  671pub enum MenuEditPredictionsPolicy {
  672    Never,
  673    ByProvider,
  674}
  675
  676pub enum EditPredictionPreview {
  677    /// Modifier is not pressed
  678    Inactive { released_too_fast: bool },
  679    /// Modifier pressed
  680    Active {
  681        since: Instant,
  682        previous_scroll_position: Option<ScrollAnchor>,
  683    },
  684}
  685
  686impl EditPredictionPreview {
  687    pub fn released_too_fast(&self) -> bool {
  688        match self {
  689            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  690            EditPredictionPreview::Active { .. } => false,
  691        }
  692    }
  693
  694    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<ScrollAnchor>) {
  695        if let EditPredictionPreview::Active {
  696            previous_scroll_position,
  697            ..
  698        } = self
  699        {
  700            *previous_scroll_position = scroll_position;
  701        }
  702    }
  703}
  704
  705pub struct ContextMenuOptions {
  706    pub min_entries_visible: usize,
  707    pub max_entries_visible: usize,
  708    pub placement: Option<ContextMenuPlacement>,
  709}
  710
  711#[derive(Debug, Clone, PartialEq, Eq)]
  712pub enum ContextMenuPlacement {
  713    Above,
  714    Below,
  715}
  716
  717#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  718struct EditorActionId(usize);
  719
  720impl EditorActionId {
  721    pub fn post_inc(&mut self) -> Self {
  722        let answer = self.0;
  723
  724        *self = Self(answer + 1);
  725
  726        Self(answer)
  727    }
  728}
  729
  730// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  731// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  732
  733type BackgroundHighlight = (
  734    Arc<dyn Fn(&usize, &Theme) -> Hsla + Send + Sync>,
  735    Arc<[Range<Anchor>]>,
  736);
  737type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  738
  739#[derive(Default)]
  740struct ScrollbarMarkerState {
  741    scrollbar_size: Size<Pixels>,
  742    dirty: bool,
  743    markers: Arc<[PaintQuad]>,
  744    pending_refresh: Option<Task<Result<()>>>,
  745}
  746
  747impl ScrollbarMarkerState {
  748    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  749        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  750    }
  751}
  752
  753#[derive(Clone, Copy, PartialEq, Eq)]
  754pub enum MinimapVisibility {
  755    Disabled,
  756    Enabled {
  757        /// The configuration currently present in the users settings.
  758        setting_configuration: bool,
  759        /// Whether to override the currently set visibility from the users setting.
  760        toggle_override: bool,
  761    },
  762}
  763
  764impl MinimapVisibility {
  765    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  766        if mode.is_full() {
  767            Self::Enabled {
  768                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  769                toggle_override: false,
  770            }
  771        } else {
  772            Self::Disabled
  773        }
  774    }
  775
  776    fn hidden(&self) -> Self {
  777        match *self {
  778            Self::Enabled {
  779                setting_configuration,
  780                ..
  781            } => Self::Enabled {
  782                setting_configuration,
  783                toggle_override: setting_configuration,
  784            },
  785            Self::Disabled => Self::Disabled,
  786        }
  787    }
  788
  789    fn disabled(&self) -> bool {
  790        matches!(*self, Self::Disabled)
  791    }
  792
  793    fn settings_visibility(&self) -> bool {
  794        match *self {
  795            Self::Enabled {
  796                setting_configuration,
  797                ..
  798            } => setting_configuration,
  799            _ => false,
  800        }
  801    }
  802
  803    fn visible(&self) -> bool {
  804        match *self {
  805            Self::Enabled {
  806                setting_configuration,
  807                toggle_override,
  808            } => setting_configuration ^ toggle_override,
  809            _ => false,
  810        }
  811    }
  812
  813    fn toggle_visibility(&self) -> Self {
  814        match *self {
  815            Self::Enabled {
  816                toggle_override,
  817                setting_configuration,
  818            } => Self::Enabled {
  819                setting_configuration,
  820                toggle_override: !toggle_override,
  821            },
  822            Self::Disabled => Self::Disabled,
  823        }
  824    }
  825}
  826
  827#[derive(Debug, Clone, Copy, PartialEq, Eq)]
  828pub enum BufferSerialization {
  829    All,
  830    NonDirtyBuffers,
  831}
  832
  833impl BufferSerialization {
  834    fn new(restore_unsaved_buffers: bool) -> Self {
  835        if restore_unsaved_buffers {
  836            Self::All
  837        } else {
  838            Self::NonDirtyBuffers
  839        }
  840    }
  841}
  842
  843#[derive(Clone, Debug)]
  844struct RunnableTasks {
  845    templates: Vec<(TaskSourceKind, TaskTemplate)>,
  846    offset: multi_buffer::Anchor,
  847    // We need the column at which the task context evaluation should take place (when we're spawning it via gutter).
  848    column: u32,
  849    // Values of all named captures, including those starting with '_'
  850    extra_variables: HashMap<String, String>,
  851    // Full range of the tagged region. We use it to determine which `extra_variables` to grab for context resolution in e.g. a modal.
  852    context_range: Range<BufferOffset>,
  853}
  854
  855impl RunnableTasks {
  856    fn resolve<'a>(
  857        &'a self,
  858        cx: &'a task::TaskContext,
  859    ) -> impl Iterator<Item = (TaskSourceKind, ResolvedTask)> + 'a {
  860        self.templates.iter().filter_map(|(kind, template)| {
  861            template
  862                .resolve_task(&kind.to_id_base(), cx)
  863                .map(|task| (kind.clone(), task))
  864        })
  865    }
  866}
  867
  868#[derive(Clone)]
  869pub struct ResolvedTasks {
  870    templates: SmallVec<[(TaskSourceKind, ResolvedTask); 1]>,
  871    position: Anchor,
  872}
  873
  874/// Addons allow storing per-editor state in other crates (e.g. Vim)
  875pub trait Addon: 'static {
  876    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  877
  878    fn render_buffer_header_controls(
  879        &self,
  880        _: &ExcerptInfo,
  881        _: &Window,
  882        _: &App,
  883    ) -> Option<AnyElement> {
  884        None
  885    }
  886
  887    fn override_status_for_buffer_id(&self, _: BufferId, _: &App) -> Option<FileStatus> {
  888        None
  889    }
  890
  891    fn to_any(&self) -> &dyn std::any::Any;
  892
  893    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  894        None
  895    }
  896}
  897
  898struct ChangeLocation {
  899    current: Option<Vec<Anchor>>,
  900    original: Vec<Anchor>,
  901}
  902impl ChangeLocation {
  903    fn locations(&self) -> &[Anchor] {
  904        self.current.as_ref().unwrap_or(&self.original)
  905    }
  906}
  907
  908/// A set of caret positions, registered when the editor was edited.
  909pub struct ChangeList {
  910    changes: Vec<ChangeLocation>,
  911    /// Currently "selected" change.
  912    position: Option<usize>,
  913}
  914
  915impl ChangeList {
  916    pub fn new() -> Self {
  917        Self {
  918            changes: Vec::new(),
  919            position: None,
  920        }
  921    }
  922
  923    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  924    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  925    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  926        if self.changes.is_empty() {
  927            return None;
  928        }
  929
  930        let prev = self.position.unwrap_or(self.changes.len());
  931        let next = if direction == Direction::Prev {
  932            prev.saturating_sub(count)
  933        } else {
  934            (prev + count).min(self.changes.len() - 1)
  935        };
  936        self.position = Some(next);
  937        self.changes.get(next).map(|change| change.locations())
  938    }
  939
  940    /// Adds a new change to the list, resetting the change list position.
  941    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  942        self.position.take();
  943        if let Some(last) = self.changes.last_mut()
  944            && group
  945        {
  946            last.current = Some(new_positions)
  947        } else {
  948            self.changes.push(ChangeLocation {
  949                original: new_positions,
  950                current: None,
  951            });
  952        }
  953    }
  954
  955    pub fn last(&self) -> Option<&[Anchor]> {
  956        self.changes.last().map(|change| change.locations())
  957    }
  958
  959    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  960        self.changes.last().map(|change| change.original.as_slice())
  961    }
  962
  963    pub fn invert_last_group(&mut self) {
  964        if let Some(last) = self.changes.last_mut()
  965            && let Some(current) = last.current.as_mut()
  966        {
  967            mem::swap(&mut last.original, current);
  968        }
  969    }
  970}
  971
  972#[derive(Clone)]
  973struct InlineBlamePopoverState {
  974    scroll_handle: ScrollHandle,
  975    commit_message: Option<ParsedCommitMessage>,
  976    markdown: Entity<Markdown>,
  977}
  978
  979struct InlineBlamePopover {
  980    position: gpui::Point<Pixels>,
  981    hide_task: Option<Task<()>>,
  982    popover_bounds: Option<Bounds<Pixels>>,
  983    popover_state: InlineBlamePopoverState,
  984    keyboard_grace: bool,
  985}
  986
  987enum SelectionDragState {
  988    /// State when no drag related activity is detected.
  989    None,
  990    /// State when the mouse is down on a selection that is about to be dragged.
  991    ReadyToDrag {
  992        selection: Selection<Anchor>,
  993        click_position: gpui::Point<Pixels>,
  994        mouse_down_time: Instant,
  995    },
  996    /// State when the mouse is dragging the selection in the editor.
  997    Dragging {
  998        selection: Selection<Anchor>,
  999        drop_cursor: Selection<Anchor>,
 1000        hide_drop_cursor: bool,
 1001    },
 1002}
 1003
 1004enum ColumnarSelectionState {
 1005    FromMouse {
 1006        selection_tail: Anchor,
 1007        display_point: Option<DisplayPoint>,
 1008    },
 1009    FromSelection {
 1010        selection_tail: Anchor,
 1011    },
 1012}
 1013
 1014/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1015/// a breakpoint on them.
 1016#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1017struct PhantomBreakpointIndicator {
 1018    display_row: DisplayRow,
 1019    /// There's a small debounce between hovering over the line and showing the indicator.
 1020    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1021    is_active: bool,
 1022    collides_with_existing_breakpoint: bool,
 1023}
 1024
 1025/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1026///
 1027/// See the [module level documentation](self) for more information.
 1028pub struct Editor {
 1029    focus_handle: FocusHandle,
 1030    last_focused_descendant: Option<WeakFocusHandle>,
 1031    /// The text buffer being edited
 1032    buffer: Entity<MultiBuffer>,
 1033    /// Map of how text in the buffer should be displayed.
 1034    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1035    pub display_map: Entity<DisplayMap>,
 1036    placeholder_display_map: Option<Entity<DisplayMap>>,
 1037    pub selections: SelectionsCollection,
 1038    pub scroll_manager: ScrollManager,
 1039    /// When inline assist editors are linked, they all render cursors because
 1040    /// typing enters text into each of them, even the ones that aren't focused.
 1041    pub(crate) show_cursor_when_unfocused: bool,
 1042    columnar_selection_state: Option<ColumnarSelectionState>,
 1043    add_selections_state: Option<AddSelectionsState>,
 1044    select_next_state: Option<SelectNextState>,
 1045    select_prev_state: Option<SelectNextState>,
 1046    selection_history: SelectionHistory,
 1047    defer_selection_effects: bool,
 1048    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1049    autoclose_regions: Vec<AutocloseRegion>,
 1050    snippet_stack: InvalidationStack<SnippetState>,
 1051    select_syntax_node_history: SelectSyntaxNodeHistory,
 1052    ime_transaction: Option<TransactionId>,
 1053    pub diagnostics_max_severity: DiagnosticSeverity,
 1054    active_diagnostics: ActiveDiagnostic,
 1055    show_inline_diagnostics: bool,
 1056    inline_diagnostics_update: Task<()>,
 1057    inline_diagnostics_enabled: bool,
 1058    diagnostics_enabled: bool,
 1059    word_completions_enabled: bool,
 1060    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1061    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1062    hard_wrap: Option<usize>,
 1063    project: Option<Entity<Project>>,
 1064    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1065    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1066    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1067    blink_manager: Entity<BlinkManager>,
 1068    show_cursor_names: bool,
 1069    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1070    pub show_local_selections: bool,
 1071    mode: EditorMode,
 1072    show_breadcrumbs: bool,
 1073    show_gutter: bool,
 1074    show_scrollbars: ScrollbarAxes,
 1075    minimap_visibility: MinimapVisibility,
 1076    offset_content: bool,
 1077    disable_expand_excerpt_buttons: bool,
 1078    show_line_numbers: Option<bool>,
 1079    use_relative_line_numbers: Option<bool>,
 1080    show_git_diff_gutter: Option<bool>,
 1081    show_code_actions: Option<bool>,
 1082    show_runnables: Option<bool>,
 1083    show_breakpoints: Option<bool>,
 1084    show_wrap_guides: Option<bool>,
 1085    show_indent_guides: Option<bool>,
 1086    buffers_with_disabled_indent_guides: HashSet<BufferId>,
 1087    highlight_order: usize,
 1088    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1089    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1090    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1091    scrollbar_marker_state: ScrollbarMarkerState,
 1092    active_indent_guides_state: ActiveIndentGuidesState,
 1093    nav_history: Option<ItemNavHistory>,
 1094    context_menu: RefCell<Option<CodeContextMenu>>,
 1095    context_menu_options: Option<ContextMenuOptions>,
 1096    mouse_context_menu: Option<MouseContextMenu>,
 1097    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1098    inline_blame_popover: Option<InlineBlamePopover>,
 1099    inline_blame_popover_show_task: Option<Task<()>>,
 1100    signature_help_state: SignatureHelpState,
 1101    auto_signature_help: Option<bool>,
 1102    find_all_references_task_sources: Vec<Anchor>,
 1103    next_completion_id: CompletionId,
 1104    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1105    code_actions_task: Option<Task<Result<()>>>,
 1106    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1107    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1108    document_highlights_task: Option<Task<()>>,
 1109    linked_editing_range_task: Option<Task<Option<()>>>,
 1110    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1111    pending_rename: Option<RenameState>,
 1112    searchable: bool,
 1113    cursor_shape: CursorShape,
 1114    current_line_highlight: Option<CurrentLineHighlight>,
 1115    pub collapse_matches: bool,
 1116    autoindent_mode: Option<AutoindentMode>,
 1117    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1118    input_enabled: bool,
 1119    use_modal_editing: bool,
 1120    read_only: bool,
 1121    leader_id: Option<CollaboratorId>,
 1122    remote_id: Option<ViewId>,
 1123    pub hover_state: HoverState,
 1124    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1125    prev_pressure_stage: Option<PressureStage>,
 1126    gutter_hovered: bool,
 1127    hovered_link_state: Option<HoveredLinkState>,
 1128    edit_prediction_provider: Option<RegisteredEditPredictionDelegate>,
 1129    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1130    active_edit_prediction: Option<EditPredictionState>,
 1131    /// Used to prevent flickering as the user types while the menu is open
 1132    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1133    edit_prediction_settings: EditPredictionSettings,
 1134    edit_predictions_hidden_for_vim_mode: bool,
 1135    show_edit_predictions_override: Option<bool>,
 1136    show_completions_on_input_override: Option<bool>,
 1137    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1138    edit_prediction_preview: EditPredictionPreview,
 1139    edit_prediction_indent_conflict: bool,
 1140    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1141    next_inlay_id: usize,
 1142    next_color_inlay_id: usize,
 1143    _subscriptions: Vec<Subscription>,
 1144    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1145    gutter_dimensions: GutterDimensions,
 1146    style: Option<EditorStyle>,
 1147    text_style_refinement: Option<TextStyleRefinement>,
 1148    next_editor_action_id: EditorActionId,
 1149    editor_actions: Rc<
 1150        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1151    >,
 1152    use_autoclose: bool,
 1153    use_auto_surround: bool,
 1154    auto_replace_emoji_shortcode: bool,
 1155    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1156    show_git_blame_gutter: bool,
 1157    show_git_blame_inline: bool,
 1158    show_git_blame_inline_delay_task: Option<Task<()>>,
 1159    git_blame_inline_enabled: bool,
 1160    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1161    buffer_serialization: Option<BufferSerialization>,
 1162    show_selection_menu: Option<bool>,
 1163    blame: Option<Entity<GitBlame>>,
 1164    blame_subscription: Option<Subscription>,
 1165    custom_context_menu: Option<
 1166        Box<
 1167            dyn 'static
 1168                + Fn(
 1169                    &mut Self,
 1170                    DisplayPoint,
 1171                    &mut Window,
 1172                    &mut Context<Self>,
 1173                ) -> Option<Entity<ui::ContextMenu>>,
 1174        >,
 1175    >,
 1176    last_bounds: Option<Bounds<Pixels>>,
 1177    last_position_map: Option<Rc<PositionMap>>,
 1178    expect_bounds_change: Option<Bounds<Pixels>>,
 1179    tasks: BTreeMap<(BufferId, BufferRow), RunnableTasks>,
 1180    tasks_update_task: Option<Task<()>>,
 1181    breakpoint_store: Option<Entity<BreakpointStore>>,
 1182    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1183    hovered_diff_hunk_row: Option<DisplayRow>,
 1184    pull_diagnostics_task: Task<()>,
 1185    pull_diagnostics_background_task: Task<()>,
 1186    in_project_search: bool,
 1187    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1188    breadcrumb_header: Option<String>,
 1189    focused_block: Option<FocusedBlock>,
 1190    next_scroll_position: NextScrollCursorCenterTopBottom,
 1191    addons: HashMap<TypeId, Box<dyn Addon>>,
 1192    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1193    load_diff_task: Option<Shared<Task<()>>>,
 1194    /// Whether we are temporarily displaying a diff other than git's
 1195    temporary_diff_override: bool,
 1196    selection_mark_mode: bool,
 1197    toggle_fold_multiple_buffers: Task<()>,
 1198    _scroll_cursor_center_top_bottom_task: Task<()>,
 1199    serialize_selections: Task<()>,
 1200    serialize_folds: Task<()>,
 1201    mouse_cursor_hidden: bool,
 1202    minimap: Option<Entity<Self>>,
 1203    hide_mouse_mode: HideMouseMode,
 1204    pub change_list: ChangeList,
 1205    inline_value_cache: InlineValueCache,
 1206
 1207    selection_drag_state: SelectionDragState,
 1208    colors: Option<LspColorData>,
 1209    post_scroll_update: Task<()>,
 1210    refresh_colors_task: Task<()>,
 1211    inlay_hints: Option<LspInlayHintData>,
 1212    folding_newlines: Task<()>,
 1213    select_next_is_case_sensitive: Option<bool>,
 1214    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1215    applicable_language_settings: HashMap<Option<LanguageName>, LanguageSettings>,
 1216    accent_data: Option<AccentData>,
 1217    fetched_tree_sitter_chunks: HashMap<ExcerptId, HashSet<Range<BufferRow>>>,
 1218    use_base_text_line_numbers: bool,
 1219}
 1220
 1221#[derive(Debug, PartialEq)]
 1222struct AccentData {
 1223    colors: AccentColors,
 1224    overrides: Vec<SharedString>,
 1225}
 1226
 1227fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1228    if debounce_ms > 0 {
 1229        Some(Duration::from_millis(debounce_ms))
 1230    } else {
 1231        None
 1232    }
 1233}
 1234
 1235#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1236enum NextScrollCursorCenterTopBottom {
 1237    #[default]
 1238    Center,
 1239    Top,
 1240    Bottom,
 1241}
 1242
 1243impl NextScrollCursorCenterTopBottom {
 1244    fn next(&self) -> Self {
 1245        match self {
 1246            Self::Center => Self::Top,
 1247            Self::Top => Self::Bottom,
 1248            Self::Bottom => Self::Center,
 1249        }
 1250    }
 1251}
 1252
 1253#[derive(Clone)]
 1254pub struct EditorSnapshot {
 1255    pub mode: EditorMode,
 1256    show_gutter: bool,
 1257    offset_content: bool,
 1258    show_line_numbers: Option<bool>,
 1259    show_git_diff_gutter: Option<bool>,
 1260    show_code_actions: Option<bool>,
 1261    show_runnables: Option<bool>,
 1262    show_breakpoints: Option<bool>,
 1263    git_blame_gutter_max_author_length: Option<usize>,
 1264    pub display_snapshot: DisplaySnapshot,
 1265    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1266    is_focused: bool,
 1267    scroll_anchor: ScrollAnchor,
 1268    ongoing_scroll: OngoingScroll,
 1269    current_line_highlight: CurrentLineHighlight,
 1270    gutter_hovered: bool,
 1271}
 1272
 1273#[derive(Default, Debug, Clone, Copy)]
 1274pub struct GutterDimensions {
 1275    pub left_padding: Pixels,
 1276    pub right_padding: Pixels,
 1277    pub width: Pixels,
 1278    pub margin: Pixels,
 1279    pub git_blame_entries_width: Option<Pixels>,
 1280}
 1281
 1282impl GutterDimensions {
 1283    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1284        Self {
 1285            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1286            ..Default::default()
 1287        }
 1288    }
 1289
 1290    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1291        -cx.text_system().descent(font_id, font_size)
 1292    }
 1293    /// The full width of the space taken up by the gutter.
 1294    pub fn full_width(&self) -> Pixels {
 1295        self.margin + self.width
 1296    }
 1297
 1298    /// The width of the space reserved for the fold indicators,
 1299    /// use alongside 'justify_end' and `gutter_width` to
 1300    /// right align content with the line numbers
 1301    pub fn fold_area_width(&self) -> Pixels {
 1302        self.margin + self.right_padding
 1303    }
 1304}
 1305
 1306struct CharacterDimensions {
 1307    em_width: Pixels,
 1308    em_advance: Pixels,
 1309    line_height: Pixels,
 1310}
 1311
 1312#[derive(Debug)]
 1313pub struct RemoteSelection {
 1314    pub replica_id: ReplicaId,
 1315    pub selection: Selection<Anchor>,
 1316    pub cursor_shape: CursorShape,
 1317    pub collaborator_id: CollaboratorId,
 1318    pub line_mode: bool,
 1319    pub user_name: Option<SharedString>,
 1320    pub color: PlayerColor,
 1321}
 1322
 1323#[derive(Clone, Debug)]
 1324struct SelectionHistoryEntry {
 1325    selections: Arc<[Selection<Anchor>]>,
 1326    select_next_state: Option<SelectNextState>,
 1327    select_prev_state: Option<SelectNextState>,
 1328    add_selections_state: Option<AddSelectionsState>,
 1329}
 1330
 1331#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
 1332enum SelectionHistoryMode {
 1333    #[default]
 1334    Normal,
 1335    Undoing,
 1336    Redoing,
 1337    Skipping,
 1338}
 1339
 1340#[derive(Clone, PartialEq, Eq, Hash)]
 1341struct HoveredCursor {
 1342    replica_id: ReplicaId,
 1343    selection_id: usize,
 1344}
 1345
 1346#[derive(Debug)]
 1347/// SelectionEffects controls the side-effects of updating the selection.
 1348///
 1349/// The default behaviour does "what you mostly want":
 1350/// - it pushes to the nav history if the cursor moved by >10 lines
 1351/// - it re-triggers completion requests
 1352/// - it scrolls to fit
 1353///
 1354/// You might want to modify these behaviours. For example when doing a "jump"
 1355/// like go to definition, we always want to add to nav history; but when scrolling
 1356/// in vim mode we never do.
 1357///
 1358/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1359/// move.
 1360#[derive(Clone)]
 1361pub struct SelectionEffects {
 1362    nav_history: Option<bool>,
 1363    completions: bool,
 1364    scroll: Option<Autoscroll>,
 1365}
 1366
 1367impl Default for SelectionEffects {
 1368    fn default() -> Self {
 1369        Self {
 1370            nav_history: None,
 1371            completions: true,
 1372            scroll: Some(Autoscroll::fit()),
 1373        }
 1374    }
 1375}
 1376impl SelectionEffects {
 1377    pub fn scroll(scroll: Autoscroll) -> Self {
 1378        Self {
 1379            scroll: Some(scroll),
 1380            ..Default::default()
 1381        }
 1382    }
 1383
 1384    pub fn no_scroll() -> Self {
 1385        Self {
 1386            scroll: None,
 1387            ..Default::default()
 1388        }
 1389    }
 1390
 1391    pub fn completions(self, completions: bool) -> Self {
 1392        Self {
 1393            completions,
 1394            ..self
 1395        }
 1396    }
 1397
 1398    pub fn nav_history(self, nav_history: bool) -> Self {
 1399        Self {
 1400            nav_history: Some(nav_history),
 1401            ..self
 1402        }
 1403    }
 1404}
 1405
 1406struct DeferredSelectionEffectsState {
 1407    changed: bool,
 1408    effects: SelectionEffects,
 1409    old_cursor_position: Anchor,
 1410    history_entry: SelectionHistoryEntry,
 1411}
 1412
 1413#[derive(Default)]
 1414struct SelectionHistory {
 1415    #[allow(clippy::type_complexity)]
 1416    selections_by_transaction:
 1417        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1418    mode: SelectionHistoryMode,
 1419    undo_stack: VecDeque<SelectionHistoryEntry>,
 1420    redo_stack: VecDeque<SelectionHistoryEntry>,
 1421}
 1422
 1423impl SelectionHistory {
 1424    #[track_caller]
 1425    fn insert_transaction(
 1426        &mut self,
 1427        transaction_id: TransactionId,
 1428        selections: Arc<[Selection<Anchor>]>,
 1429    ) {
 1430        if selections.is_empty() {
 1431            log::error!(
 1432                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1433                std::panic::Location::caller()
 1434            );
 1435            return;
 1436        }
 1437        self.selections_by_transaction
 1438            .insert(transaction_id, (selections, None));
 1439    }
 1440
 1441    #[allow(clippy::type_complexity)]
 1442    fn transaction(
 1443        &self,
 1444        transaction_id: TransactionId,
 1445    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1446        self.selections_by_transaction.get(&transaction_id)
 1447    }
 1448
 1449    #[allow(clippy::type_complexity)]
 1450    fn transaction_mut(
 1451        &mut self,
 1452        transaction_id: TransactionId,
 1453    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1454        self.selections_by_transaction.get_mut(&transaction_id)
 1455    }
 1456
 1457    fn push(&mut self, entry: SelectionHistoryEntry) {
 1458        if !entry.selections.is_empty() {
 1459            match self.mode {
 1460                SelectionHistoryMode::Normal => {
 1461                    self.push_undo(entry);
 1462                    self.redo_stack.clear();
 1463                }
 1464                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1465                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1466                SelectionHistoryMode::Skipping => {}
 1467            }
 1468        }
 1469    }
 1470
 1471    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1472        if self
 1473            .undo_stack
 1474            .back()
 1475            .is_none_or(|e| e.selections != entry.selections)
 1476        {
 1477            self.undo_stack.push_back(entry);
 1478            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1479                self.undo_stack.pop_front();
 1480            }
 1481        }
 1482    }
 1483
 1484    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1485        if self
 1486            .redo_stack
 1487            .back()
 1488            .is_none_or(|e| e.selections != entry.selections)
 1489        {
 1490            self.redo_stack.push_back(entry);
 1491            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1492                self.redo_stack.pop_front();
 1493            }
 1494        }
 1495    }
 1496}
 1497
 1498#[derive(Clone, Copy)]
 1499pub struct RowHighlightOptions {
 1500    pub autoscroll: bool,
 1501    pub include_gutter: bool,
 1502}
 1503
 1504impl Default for RowHighlightOptions {
 1505    fn default() -> Self {
 1506        Self {
 1507            autoscroll: Default::default(),
 1508            include_gutter: true,
 1509        }
 1510    }
 1511}
 1512
 1513struct RowHighlight {
 1514    index: usize,
 1515    range: Range<Anchor>,
 1516    color: Hsla,
 1517    options: RowHighlightOptions,
 1518    type_id: TypeId,
 1519}
 1520
 1521#[derive(Clone, Debug)]
 1522struct AddSelectionsState {
 1523    groups: Vec<AddSelectionsGroup>,
 1524}
 1525
 1526#[derive(Clone, Debug)]
 1527struct AddSelectionsGroup {
 1528    above: bool,
 1529    stack: Vec<usize>,
 1530}
 1531
 1532#[derive(Clone)]
 1533struct SelectNextState {
 1534    query: AhoCorasick,
 1535    wordwise: bool,
 1536    done: bool,
 1537}
 1538
 1539impl std::fmt::Debug for SelectNextState {
 1540    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1541        f.debug_struct(std::any::type_name::<Self>())
 1542            .field("wordwise", &self.wordwise)
 1543            .field("done", &self.done)
 1544            .finish()
 1545    }
 1546}
 1547
 1548#[derive(Debug)]
 1549struct AutocloseRegion {
 1550    selection_id: usize,
 1551    range: Range<Anchor>,
 1552    pair: BracketPair,
 1553}
 1554
 1555#[derive(Debug)]
 1556struct SnippetState {
 1557    ranges: Vec<Vec<Range<Anchor>>>,
 1558    active_index: usize,
 1559    choices: Vec<Option<Vec<String>>>,
 1560}
 1561
 1562#[doc(hidden)]
 1563pub struct RenameState {
 1564    pub range: Range<Anchor>,
 1565    pub old_name: Arc<str>,
 1566    pub editor: Entity<Editor>,
 1567    block_id: CustomBlockId,
 1568}
 1569
 1570struct InvalidationStack<T>(Vec<T>);
 1571
 1572struct RegisteredEditPredictionDelegate {
 1573    provider: Arc<dyn EditPredictionDelegateHandle>,
 1574    _subscription: Subscription,
 1575}
 1576
 1577#[derive(Debug, PartialEq, Eq)]
 1578pub struct ActiveDiagnosticGroup {
 1579    pub active_range: Range<Anchor>,
 1580    pub active_message: String,
 1581    pub group_id: usize,
 1582    pub blocks: HashSet<CustomBlockId>,
 1583}
 1584
 1585#[derive(Debug, PartialEq, Eq)]
 1586
 1587pub(crate) enum ActiveDiagnostic {
 1588    None,
 1589    All,
 1590    Group(ActiveDiagnosticGroup),
 1591}
 1592
 1593#[derive(Serialize, Deserialize, Clone, Debug)]
 1594pub struct ClipboardSelection {
 1595    /// The number of bytes in this selection.
 1596    pub len: usize,
 1597    /// Whether this was a full-line selection.
 1598    pub is_entire_line: bool,
 1599    /// The indentation of the first line when this content was originally copied.
 1600    pub first_line_indent: u32,
 1601    #[serde(default)]
 1602    pub file_path: Option<PathBuf>,
 1603    #[serde(default)]
 1604    pub line_range: Option<RangeInclusive<u32>>,
 1605}
 1606
 1607impl ClipboardSelection {
 1608    pub fn for_buffer(
 1609        len: usize,
 1610        is_entire_line: bool,
 1611        range: Range<Point>,
 1612        buffer: &MultiBufferSnapshot,
 1613        project: Option<&Entity<Project>>,
 1614        cx: &App,
 1615    ) -> Self {
 1616        let first_line_indent = buffer
 1617            .indent_size_for_line(MultiBufferRow(range.start.row))
 1618            .len;
 1619
 1620        let file_path = util::maybe!({
 1621            let project = project?.read(cx);
 1622            let file = buffer.file_at(range.start)?;
 1623            let project_path = ProjectPath {
 1624                worktree_id: file.worktree_id(cx),
 1625                path: file.path().clone(),
 1626            };
 1627            project.absolute_path(&project_path, cx)
 1628        });
 1629
 1630        let line_range = file_path.as_ref().map(|_| range.start.row..=range.end.row);
 1631
 1632        Self {
 1633            len,
 1634            is_entire_line,
 1635            first_line_indent,
 1636            file_path,
 1637            line_range,
 1638        }
 1639    }
 1640}
 1641
 1642// selections, scroll behavior, was newest selection reversed
 1643type SelectSyntaxNodeHistoryState = (
 1644    Box<[Selection<MultiBufferOffset>]>,
 1645    SelectSyntaxNodeScrollBehavior,
 1646    bool,
 1647);
 1648
 1649#[derive(Default)]
 1650struct SelectSyntaxNodeHistory {
 1651    stack: Vec<SelectSyntaxNodeHistoryState>,
 1652    // disable temporarily to allow changing selections without losing the stack
 1653    pub disable_clearing: bool,
 1654}
 1655
 1656impl SelectSyntaxNodeHistory {
 1657    pub fn try_clear(&mut self) {
 1658        if !self.disable_clearing {
 1659            self.stack.clear();
 1660        }
 1661    }
 1662
 1663    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1664        self.stack.push(selection);
 1665    }
 1666
 1667    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1668        self.stack.pop()
 1669    }
 1670}
 1671
 1672enum SelectSyntaxNodeScrollBehavior {
 1673    CursorTop,
 1674    FitSelection,
 1675    CursorBottom,
 1676}
 1677
 1678#[derive(Debug)]
 1679pub(crate) struct NavigationData {
 1680    cursor_anchor: Anchor,
 1681    cursor_position: Point,
 1682    scroll_anchor: ScrollAnchor,
 1683    scroll_top_row: u32,
 1684}
 1685
 1686#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1687pub enum GotoDefinitionKind {
 1688    Symbol,
 1689    Declaration,
 1690    Type,
 1691    Implementation,
 1692}
 1693
 1694pub enum FormatTarget {
 1695    Buffers(HashSet<Entity<Buffer>>),
 1696    Ranges(Vec<Range<MultiBufferPoint>>),
 1697}
 1698
 1699pub(crate) struct FocusedBlock {
 1700    id: BlockId,
 1701    focus_handle: WeakFocusHandle,
 1702}
 1703
 1704#[derive(Clone, Debug)]
 1705enum JumpData {
 1706    MultiBufferRow {
 1707        row: MultiBufferRow,
 1708        line_offset_from_top: u32,
 1709    },
 1710    MultiBufferPoint {
 1711        excerpt_id: ExcerptId,
 1712        position: Point,
 1713        anchor: text::Anchor,
 1714        line_offset_from_top: u32,
 1715    },
 1716}
 1717
 1718pub enum MultibufferSelectionMode {
 1719    First,
 1720    All,
 1721}
 1722
 1723#[derive(Clone, Copy, Debug, Default)]
 1724pub struct RewrapOptions {
 1725    pub override_language_settings: bool,
 1726    pub preserve_existing_whitespace: bool,
 1727}
 1728
 1729impl Editor {
 1730    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1731        let buffer = cx.new(|cx| Buffer::local("", cx));
 1732        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1733        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1734    }
 1735
 1736    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1737        let buffer = cx.new(|cx| Buffer::local("", cx));
 1738        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1739        Self::new(EditorMode::full(), buffer, None, window, cx)
 1740    }
 1741
 1742    pub fn auto_height(
 1743        min_lines: usize,
 1744        max_lines: usize,
 1745        window: &mut Window,
 1746        cx: &mut Context<Self>,
 1747    ) -> Self {
 1748        let buffer = cx.new(|cx| Buffer::local("", cx));
 1749        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1750        Self::new(
 1751            EditorMode::AutoHeight {
 1752                min_lines,
 1753                max_lines: Some(max_lines),
 1754            },
 1755            buffer,
 1756            None,
 1757            window,
 1758            cx,
 1759        )
 1760    }
 1761
 1762    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1763    /// The editor grows as tall as needed to fit its content.
 1764    pub fn auto_height_unbounded(
 1765        min_lines: usize,
 1766        window: &mut Window,
 1767        cx: &mut Context<Self>,
 1768    ) -> Self {
 1769        let buffer = cx.new(|cx| Buffer::local("", cx));
 1770        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1771        Self::new(
 1772            EditorMode::AutoHeight {
 1773                min_lines,
 1774                max_lines: None,
 1775            },
 1776            buffer,
 1777            None,
 1778            window,
 1779            cx,
 1780        )
 1781    }
 1782
 1783    pub fn for_buffer(
 1784        buffer: Entity<Buffer>,
 1785        project: Option<Entity<Project>>,
 1786        window: &mut Window,
 1787        cx: &mut Context<Self>,
 1788    ) -> Self {
 1789        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1790        Self::new(EditorMode::full(), buffer, project, window, cx)
 1791    }
 1792
 1793    pub fn for_multibuffer(
 1794        buffer: Entity<MultiBuffer>,
 1795        project: Option<Entity<Project>>,
 1796        window: &mut Window,
 1797        cx: &mut Context<Self>,
 1798    ) -> Self {
 1799        Self::new(EditorMode::full(), buffer, project, window, cx)
 1800    }
 1801
 1802    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1803        let mut clone = Self::new(
 1804            self.mode.clone(),
 1805            self.buffer.clone(),
 1806            self.project.clone(),
 1807            window,
 1808            cx,
 1809        );
 1810        self.display_map.update(cx, |display_map, cx| {
 1811            let snapshot = display_map.snapshot(cx);
 1812            clone.display_map.update(cx, |display_map, cx| {
 1813                display_map.set_state(&snapshot, cx);
 1814            });
 1815        });
 1816        clone.folds_did_change(cx);
 1817        clone.selections.clone_state(&self.selections);
 1818        clone.scroll_manager.clone_state(&self.scroll_manager);
 1819        clone.searchable = self.searchable;
 1820        clone.read_only = self.read_only;
 1821        clone
 1822    }
 1823
 1824    pub fn new(
 1825        mode: EditorMode,
 1826        buffer: Entity<MultiBuffer>,
 1827        project: Option<Entity<Project>>,
 1828        window: &mut Window,
 1829        cx: &mut Context<Self>,
 1830    ) -> Self {
 1831        Editor::new_internal(mode, buffer, project, None, window, cx)
 1832    }
 1833
 1834    pub fn sticky_headers(
 1835        &self,
 1836        style: &EditorStyle,
 1837        cx: &App,
 1838    ) -> Option<Vec<OutlineItem<Anchor>>> {
 1839        let multi_buffer = self.buffer().read(cx);
 1840        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 1841        let multi_buffer_visible_start = self
 1842            .scroll_manager
 1843            .anchor()
 1844            .anchor
 1845            .to_point(&multi_buffer_snapshot);
 1846        let max_row = multi_buffer_snapshot.max_point().row;
 1847
 1848        let start_row = (multi_buffer_visible_start.row).min(max_row);
 1849        let end_row = (multi_buffer_visible_start.row + 10).min(max_row);
 1850
 1851        if let Some((excerpt_id, _, buffer)) = multi_buffer.read(cx).as_singleton() {
 1852            let outline_items = buffer
 1853                .outline_items_containing(
 1854                    Point::new(start_row, 0)..Point::new(end_row, 0),
 1855                    true,
 1856                    Some(style.syntax.as_ref()),
 1857                )
 1858                .into_iter()
 1859                .map(|outline_item| OutlineItem {
 1860                    depth: outline_item.depth,
 1861                    range: Anchor::range_in_buffer(*excerpt_id, outline_item.range),
 1862                    source_range_for_text: Anchor::range_in_buffer(
 1863                        *excerpt_id,
 1864                        outline_item.source_range_for_text,
 1865                    ),
 1866                    text: outline_item.text,
 1867                    highlight_ranges: outline_item.highlight_ranges,
 1868                    name_ranges: outline_item.name_ranges,
 1869                    body_range: outline_item
 1870                        .body_range
 1871                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1872                    annotation_range: outline_item
 1873                        .annotation_range
 1874                        .map(|range| Anchor::range_in_buffer(*excerpt_id, range)),
 1875                });
 1876            return Some(outline_items.collect());
 1877        }
 1878
 1879        None
 1880    }
 1881
 1882    fn new_internal(
 1883        mode: EditorMode,
 1884        multi_buffer: Entity<MultiBuffer>,
 1885        project: Option<Entity<Project>>,
 1886        display_map: Option<Entity<DisplayMap>>,
 1887        window: &mut Window,
 1888        cx: &mut Context<Self>,
 1889    ) -> Self {
 1890        debug_assert!(
 1891            display_map.is_none() || mode.is_minimap(),
 1892            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 1893        );
 1894
 1895        let full_mode = mode.is_full();
 1896        let is_minimap = mode.is_minimap();
 1897        let diagnostics_max_severity = if full_mode {
 1898            EditorSettings::get_global(cx)
 1899                .diagnostics_max_severity
 1900                .unwrap_or(DiagnosticSeverity::Hint)
 1901        } else {
 1902            DiagnosticSeverity::Off
 1903        };
 1904        let style = window.text_style();
 1905        let font_size = style.font_size.to_pixels(window.rem_size());
 1906        let editor = cx.entity().downgrade();
 1907        let fold_placeholder = FoldPlaceholder {
 1908            constrain_width: false,
 1909            render: Arc::new(move |fold_id, fold_range, cx| {
 1910                let editor = editor.clone();
 1911                div()
 1912                    .id(fold_id)
 1913                    .bg(cx.theme().colors().ghost_element_background)
 1914                    .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
 1915                    .active(|style| style.bg(cx.theme().colors().ghost_element_active))
 1916                    .rounded_xs()
 1917                    .size_full()
 1918                    .cursor_pointer()
 1919                    .child("")
 1920                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 1921                    .on_click(move |_, _window, cx| {
 1922                        editor
 1923                            .update(cx, |editor, cx| {
 1924                                editor.unfold_ranges(
 1925                                    &[fold_range.start..fold_range.end],
 1926                                    true,
 1927                                    false,
 1928                                    cx,
 1929                                );
 1930                                cx.stop_propagation();
 1931                            })
 1932                            .ok();
 1933                    })
 1934                    .into_any()
 1935            }),
 1936            merge_adjacent: true,
 1937            ..FoldPlaceholder::default()
 1938        };
 1939        let display_map = display_map.unwrap_or_else(|| {
 1940            cx.new(|cx| {
 1941                DisplayMap::new(
 1942                    multi_buffer.clone(),
 1943                    style.font(),
 1944                    font_size,
 1945                    None,
 1946                    FILE_HEADER_HEIGHT,
 1947                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 1948                    fold_placeholder,
 1949                    diagnostics_max_severity,
 1950                    cx,
 1951                )
 1952            })
 1953        });
 1954
 1955        let selections = SelectionsCollection::new();
 1956
 1957        let blink_manager = cx.new(|cx| {
 1958            let mut blink_manager = BlinkManager::new(
 1959                CURSOR_BLINK_INTERVAL,
 1960                |cx| EditorSettings::get_global(cx).cursor_blink,
 1961                cx,
 1962            );
 1963            if is_minimap {
 1964                blink_manager.disable(cx);
 1965            }
 1966            blink_manager
 1967        });
 1968
 1969        let soft_wrap_mode_override =
 1970            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 1971
 1972        let mut project_subscriptions = Vec::new();
 1973        if full_mode && let Some(project) = project.as_ref() {
 1974            project_subscriptions.push(cx.subscribe_in(
 1975                project,
 1976                window,
 1977                |editor, _, event, window, cx| match event {
 1978                    project::Event::RefreshCodeLens => {
 1979                        // we always query lens with actions, without storing them, always refreshing them
 1980                    }
 1981                    project::Event::RefreshInlayHints {
 1982                        server_id,
 1983                        request_id,
 1984                    } => {
 1985                        editor.refresh_inlay_hints(
 1986                            InlayHintRefreshReason::RefreshRequested {
 1987                                server_id: *server_id,
 1988                                request_id: *request_id,
 1989                            },
 1990                            cx,
 1991                        );
 1992                    }
 1993                    project::Event::LanguageServerRemoved(..) => {
 1994                        if editor.tasks_update_task.is_none() {
 1995                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 1996                        }
 1997                        editor.registered_buffers.clear();
 1998                        editor.register_visible_buffers(cx);
 1999                    }
 2000                    project::Event::LanguageServerAdded(..) => {
 2001                        if editor.tasks_update_task.is_none() {
 2002                            editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2003                        }
 2004                    }
 2005                    project::Event::SnippetEdit(id, snippet_edits) => {
 2006                        // todo(lw): Non singletons
 2007                        if let Some(buffer) = editor.buffer.read(cx).as_singleton() {
 2008                            let snapshot = buffer.read(cx).snapshot();
 2009                            let focus_handle = editor.focus_handle(cx);
 2010                            if snapshot.remote_id() == *id && focus_handle.is_focused(window) {
 2011                                for (range, snippet) in snippet_edits {
 2012                                    let buffer_range =
 2013                                        language::range_from_lsp(*range).to_offset(&snapshot);
 2014                                    editor
 2015                                        .insert_snippet(
 2016                                            &[MultiBufferOffset(buffer_range.start)
 2017                                                ..MultiBufferOffset(buffer_range.end)],
 2018                                            snippet.clone(),
 2019                                            window,
 2020                                            cx,
 2021                                        )
 2022                                        .ok();
 2023                                }
 2024                            }
 2025                        }
 2026                    }
 2027                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 2028                        let buffer_id = *buffer_id;
 2029                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 2030                            editor.register_buffer(buffer_id, cx);
 2031                            editor.update_lsp_data(Some(buffer_id), window, cx);
 2032                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 2033                            refresh_linked_ranges(editor, window, cx);
 2034                            editor.refresh_code_actions(window, cx);
 2035                            editor.refresh_document_highlights(cx);
 2036                        }
 2037                    }
 2038
 2039                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 2040                        let Some(workspace) = editor.workspace() else {
 2041                            return;
 2042                        };
 2043                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2044                        else {
 2045                            return;
 2046                        };
 2047
 2048                        if active_editor.entity_id() == cx.entity_id() {
 2049                            let entity_id = cx.entity_id();
 2050                            workspace.update(cx, |this, cx| {
 2051                                this.panes_mut()
 2052                                    .iter_mut()
 2053                                    .filter(|pane| pane.entity_id() != entity_id)
 2054                                    .for_each(|p| {
 2055                                        p.update(cx, |pane, _| {
 2056                                            pane.nav_history_mut().rename_item(
 2057                                                entity_id,
 2058                                                project_path.clone(),
 2059                                                abs_path.clone().into(),
 2060                                            );
 2061                                        })
 2062                                    });
 2063                            });
 2064                            let edited_buffers_already_open = {
 2065                                let other_editors: Vec<Entity<Editor>> = workspace
 2066                                    .read(cx)
 2067                                    .panes()
 2068                                    .iter()
 2069                                    .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 2070                                    .filter(|editor| editor.entity_id() != cx.entity_id())
 2071                                    .collect();
 2072
 2073                                transaction.0.keys().all(|buffer| {
 2074                                    other_editors.iter().any(|editor| {
 2075                                        let multi_buffer = editor.read(cx).buffer();
 2076                                        multi_buffer.read(cx).is_singleton()
 2077                                            && multi_buffer.read(cx).as_singleton().map_or(
 2078                                                false,
 2079                                                |singleton| {
 2080                                                    singleton.entity_id() == buffer.entity_id()
 2081                                                },
 2082                                            )
 2083                                    })
 2084                                })
 2085                            };
 2086                            if !edited_buffers_already_open {
 2087                                let workspace = workspace.downgrade();
 2088                                let transaction = transaction.clone();
 2089                                cx.defer_in(window, move |_, window, cx| {
 2090                                    cx.spawn_in(window, async move |editor, cx| {
 2091                                        Self::open_project_transaction(
 2092                                            &editor,
 2093                                            workspace,
 2094                                            transaction,
 2095                                            "Rename".to_string(),
 2096                                            cx,
 2097                                        )
 2098                                        .await
 2099                                        .ok()
 2100                                    })
 2101                                    .detach();
 2102                                });
 2103                            }
 2104                        }
 2105                    }
 2106
 2107                    _ => {}
 2108                },
 2109            ));
 2110            if let Some(task_inventory) = project
 2111                .read(cx)
 2112                .task_store()
 2113                .read(cx)
 2114                .task_inventory()
 2115                .cloned()
 2116            {
 2117                project_subscriptions.push(cx.observe_in(
 2118                    &task_inventory,
 2119                    window,
 2120                    |editor, _, window, cx| {
 2121                        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2122                    },
 2123                ));
 2124            };
 2125
 2126            project_subscriptions.push(cx.subscribe_in(
 2127                &project.read(cx).breakpoint_store(),
 2128                window,
 2129                |editor, _, event, window, cx| match event {
 2130                    BreakpointStoreEvent::ClearDebugLines => {
 2131                        editor.clear_row_highlights::<ActiveDebugLine>();
 2132                        editor.refresh_inline_values(cx);
 2133                    }
 2134                    BreakpointStoreEvent::SetDebugLine => {
 2135                        if editor.go_to_active_debug_line(window, cx) {
 2136                            cx.stop_propagation();
 2137                        }
 2138
 2139                        editor.refresh_inline_values(cx);
 2140                    }
 2141                    _ => {}
 2142                },
 2143            ));
 2144            let git_store = project.read(cx).git_store().clone();
 2145            let project = project.clone();
 2146            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2147                if let GitStoreEvent::RepositoryAdded = event {
 2148                    this.load_diff_task = Some(
 2149                        update_uncommitted_diff_for_buffer(
 2150                            cx.entity(),
 2151                            &project,
 2152                            this.buffer.read(cx).all_buffers(),
 2153                            this.buffer.clone(),
 2154                            cx,
 2155                        )
 2156                        .shared(),
 2157                    );
 2158                }
 2159            }));
 2160        }
 2161
 2162        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2163
 2164        let inlay_hint_settings =
 2165            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2166        let focus_handle = cx.focus_handle();
 2167        if !is_minimap {
 2168            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2169                .detach();
 2170            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2171                .detach();
 2172            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2173                .detach();
 2174            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2175                .detach();
 2176            cx.observe_pending_input(window, Self::observe_pending_input)
 2177                .detach();
 2178        }
 2179
 2180        let show_indent_guides =
 2181            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2182                Some(false)
 2183            } else {
 2184                None
 2185            };
 2186
 2187        let breakpoint_store = match (&mode, project.as_ref()) {
 2188            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2189            _ => None,
 2190        };
 2191
 2192        let mut code_action_providers = Vec::new();
 2193        let mut load_uncommitted_diff = None;
 2194        if let Some(project) = project.clone() {
 2195            load_uncommitted_diff = Some(
 2196                update_uncommitted_diff_for_buffer(
 2197                    cx.entity(),
 2198                    &project,
 2199                    multi_buffer.read(cx).all_buffers(),
 2200                    multi_buffer.clone(),
 2201                    cx,
 2202                )
 2203                .shared(),
 2204            );
 2205            code_action_providers.push(Rc::new(project) as Rc<_>);
 2206        }
 2207
 2208        let mut editor = Self {
 2209            focus_handle,
 2210            show_cursor_when_unfocused: false,
 2211            last_focused_descendant: None,
 2212            buffer: multi_buffer.clone(),
 2213            display_map: display_map.clone(),
 2214            placeholder_display_map: None,
 2215            selections,
 2216            scroll_manager: ScrollManager::new(cx),
 2217            columnar_selection_state: None,
 2218            add_selections_state: None,
 2219            select_next_state: None,
 2220            select_prev_state: None,
 2221            selection_history: SelectionHistory::default(),
 2222            defer_selection_effects: false,
 2223            deferred_selection_effects_state: None,
 2224            autoclose_regions: Vec::new(),
 2225            snippet_stack: InvalidationStack::default(),
 2226            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2227            ime_transaction: None,
 2228            active_diagnostics: ActiveDiagnostic::None,
 2229            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2230            inline_diagnostics_update: Task::ready(()),
 2231            inline_diagnostics: Vec::new(),
 2232            soft_wrap_mode_override,
 2233            diagnostics_max_severity,
 2234            hard_wrap: None,
 2235            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2236            semantics_provider: project.clone().map(|project| Rc::new(project) as _),
 2237            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2238            project,
 2239            blink_manager: blink_manager.clone(),
 2240            show_local_selections: true,
 2241            show_scrollbars: ScrollbarAxes {
 2242                horizontal: full_mode,
 2243                vertical: full_mode,
 2244            },
 2245            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2246            offset_content: !matches!(mode, EditorMode::SingleLine),
 2247            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2248            show_gutter: full_mode,
 2249            show_line_numbers: (!full_mode).then_some(false),
 2250            use_relative_line_numbers: None,
 2251            disable_expand_excerpt_buttons: !full_mode,
 2252            show_git_diff_gutter: None,
 2253            show_code_actions: None,
 2254            show_runnables: None,
 2255            show_breakpoints: None,
 2256            show_wrap_guides: None,
 2257            show_indent_guides,
 2258            buffers_with_disabled_indent_guides: HashSet::default(),
 2259            highlight_order: 0,
 2260            highlighted_rows: HashMap::default(),
 2261            background_highlights: HashMap::default(),
 2262            gutter_highlights: HashMap::default(),
 2263            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2264            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2265            nav_history: None,
 2266            context_menu: RefCell::new(None),
 2267            context_menu_options: None,
 2268            mouse_context_menu: None,
 2269            completion_tasks: Vec::new(),
 2270            inline_blame_popover: None,
 2271            inline_blame_popover_show_task: None,
 2272            signature_help_state: SignatureHelpState::default(),
 2273            auto_signature_help: None,
 2274            find_all_references_task_sources: Vec::new(),
 2275            next_completion_id: 0,
 2276            next_inlay_id: 0,
 2277            code_action_providers,
 2278            available_code_actions: None,
 2279            code_actions_task: None,
 2280            quick_selection_highlight_task: None,
 2281            debounced_selection_highlight_task: None,
 2282            document_highlights_task: None,
 2283            linked_editing_range_task: None,
 2284            pending_rename: None,
 2285            searchable: !is_minimap,
 2286            cursor_shape: EditorSettings::get_global(cx)
 2287                .cursor_shape
 2288                .unwrap_or_default(),
 2289            current_line_highlight: None,
 2290            autoindent_mode: Some(AutoindentMode::EachLine),
 2291            collapse_matches: false,
 2292            workspace: None,
 2293            input_enabled: !is_minimap,
 2294            use_modal_editing: full_mode,
 2295            read_only: is_minimap,
 2296            use_autoclose: true,
 2297            use_auto_surround: true,
 2298            auto_replace_emoji_shortcode: false,
 2299            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2300            leader_id: None,
 2301            remote_id: None,
 2302            hover_state: HoverState::default(),
 2303            pending_mouse_down: None,
 2304            prev_pressure_stage: None,
 2305            hovered_link_state: None,
 2306            edit_prediction_provider: None,
 2307            active_edit_prediction: None,
 2308            stale_edit_prediction_in_menu: None,
 2309            edit_prediction_preview: EditPredictionPreview::Inactive {
 2310                released_too_fast: false,
 2311            },
 2312            inline_diagnostics_enabled: full_mode,
 2313            diagnostics_enabled: full_mode,
 2314            word_completions_enabled: full_mode,
 2315            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2316            gutter_hovered: false,
 2317            pixel_position_of_newest_cursor: None,
 2318            last_bounds: None,
 2319            last_position_map: None,
 2320            expect_bounds_change: None,
 2321            gutter_dimensions: GutterDimensions::default(),
 2322            style: None,
 2323            show_cursor_names: false,
 2324            hovered_cursors: HashMap::default(),
 2325            next_editor_action_id: EditorActionId::default(),
 2326            editor_actions: Rc::default(),
 2327            edit_predictions_hidden_for_vim_mode: false,
 2328            show_edit_predictions_override: None,
 2329            show_completions_on_input_override: None,
 2330            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2331            edit_prediction_settings: EditPredictionSettings::Disabled,
 2332            edit_prediction_indent_conflict: false,
 2333            edit_prediction_requires_modifier_in_indent_conflict: true,
 2334            custom_context_menu: None,
 2335            show_git_blame_gutter: false,
 2336            show_git_blame_inline: false,
 2337            show_selection_menu: None,
 2338            show_git_blame_inline_delay_task: None,
 2339            git_blame_inline_enabled: full_mode
 2340                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2341            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2342            buffer_serialization: is_minimap.not().then(|| {
 2343                BufferSerialization::new(
 2344                    ProjectSettings::get_global(cx)
 2345                        .session
 2346                        .restore_unsaved_buffers,
 2347                )
 2348            }),
 2349            blame: None,
 2350            blame_subscription: None,
 2351            tasks: BTreeMap::default(),
 2352
 2353            breakpoint_store,
 2354            gutter_breakpoint_indicator: (None, None),
 2355            hovered_diff_hunk_row: None,
 2356            _subscriptions: (!is_minimap)
 2357                .then(|| {
 2358                    vec![
 2359                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2360                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2361                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2362                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2363                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2364                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2365                        cx.observe_window_activation(window, |editor, window, cx| {
 2366                            let active = window.is_window_active();
 2367                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2368                                if active {
 2369                                    blink_manager.enable(cx);
 2370                                } else {
 2371                                    blink_manager.disable(cx);
 2372                                }
 2373                            });
 2374                            if active {
 2375                                editor.show_mouse_cursor(cx);
 2376                            }
 2377                        }),
 2378                    ]
 2379                })
 2380                .unwrap_or_default(),
 2381            tasks_update_task: None,
 2382            pull_diagnostics_task: Task::ready(()),
 2383            pull_diagnostics_background_task: Task::ready(()),
 2384            colors: None,
 2385            refresh_colors_task: Task::ready(()),
 2386            inlay_hints: None,
 2387            next_color_inlay_id: 0,
 2388            post_scroll_update: Task::ready(()),
 2389            linked_edit_ranges: Default::default(),
 2390            in_project_search: false,
 2391            previous_search_ranges: None,
 2392            breadcrumb_header: None,
 2393            focused_block: None,
 2394            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2395            addons: HashMap::default(),
 2396            registered_buffers: HashMap::default(),
 2397            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2398            selection_mark_mode: false,
 2399            toggle_fold_multiple_buffers: Task::ready(()),
 2400            serialize_selections: Task::ready(()),
 2401            serialize_folds: Task::ready(()),
 2402            text_style_refinement: None,
 2403            load_diff_task: load_uncommitted_diff,
 2404            temporary_diff_override: false,
 2405            mouse_cursor_hidden: false,
 2406            minimap: None,
 2407            hide_mouse_mode: EditorSettings::get_global(cx)
 2408                .hide_mouse
 2409                .unwrap_or_default(),
 2410            change_list: ChangeList::new(),
 2411            mode,
 2412            selection_drag_state: SelectionDragState::None,
 2413            folding_newlines: Task::ready(()),
 2414            lookup_key: None,
 2415            select_next_is_case_sensitive: None,
 2416            applicable_language_settings: HashMap::default(),
 2417            accent_data: None,
 2418            fetched_tree_sitter_chunks: HashMap::default(),
 2419            use_base_text_line_numbers: false,
 2420        };
 2421
 2422        if is_minimap {
 2423            return editor;
 2424        }
 2425
 2426        editor.applicable_language_settings = editor.fetch_applicable_language_settings(cx);
 2427        editor.accent_data = editor.fetch_accent_data(cx);
 2428
 2429        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2430            editor
 2431                ._subscriptions
 2432                .push(cx.observe(breakpoints, |_, _, cx| {
 2433                    cx.notify();
 2434                }));
 2435        }
 2436        editor.tasks_update_task = Some(editor.refresh_runnables(window, cx));
 2437        editor._subscriptions.extend(project_subscriptions);
 2438
 2439        editor._subscriptions.push(cx.subscribe_in(
 2440            &cx.entity(),
 2441            window,
 2442            |editor, _, e: &EditorEvent, window, cx| match e {
 2443                EditorEvent::ScrollPositionChanged { local, .. } => {
 2444                    if *local {
 2445                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2446                        editor.inline_blame_popover.take();
 2447                        let new_anchor = editor.scroll_manager.anchor();
 2448                        let snapshot = editor.snapshot(window, cx);
 2449                        editor.update_restoration_data(cx, move |data| {
 2450                            data.scroll_position = (
 2451                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2452                                new_anchor.offset,
 2453                            );
 2454                        });
 2455
 2456                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2457                            cx.background_executor()
 2458                                .timer(Duration::from_millis(50))
 2459                                .await;
 2460                            editor
 2461                                .update_in(cx, |editor, window, cx| {
 2462                                    editor.register_visible_buffers(cx);
 2463                                    editor.refresh_colors_for_visible_range(None, window, cx);
 2464                                    editor.refresh_inlay_hints(
 2465                                        InlayHintRefreshReason::NewLinesShown,
 2466                                        cx,
 2467                                    );
 2468                                    editor.colorize_brackets(false, cx);
 2469                                })
 2470                                .ok();
 2471                        });
 2472                    }
 2473                }
 2474                EditorEvent::Edited { .. } => {
 2475                    if !editor.is_vim_mode_enabled(cx) {
 2476                        let display_map = editor.display_snapshot(cx);
 2477                        let selections = editor.selections.all_adjusted_display(&display_map);
 2478                        let pop_state = editor
 2479                            .change_list
 2480                            .last()
 2481                            .map(|previous| {
 2482                                previous.len() == selections.len()
 2483                                    && previous.iter().enumerate().all(|(ix, p)| {
 2484                                        p.to_display_point(&display_map).row()
 2485                                            == selections[ix].head().row()
 2486                                    })
 2487                            })
 2488                            .unwrap_or(false);
 2489                        let new_positions = selections
 2490                            .into_iter()
 2491                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2492                            .collect();
 2493                        editor
 2494                            .change_list
 2495                            .push_to_change_list(pop_state, new_positions);
 2496                    }
 2497                }
 2498                _ => (),
 2499            },
 2500        ));
 2501
 2502        if let Some(dap_store) = editor
 2503            .project
 2504            .as_ref()
 2505            .map(|project| project.read(cx).dap_store())
 2506        {
 2507            let weak_editor = cx.weak_entity();
 2508
 2509            editor
 2510                ._subscriptions
 2511                .push(
 2512                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2513                        let session_entity = cx.entity();
 2514                        weak_editor
 2515                            .update(cx, |editor, cx| {
 2516                                editor._subscriptions.push(
 2517                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2518                                );
 2519                            })
 2520                            .ok();
 2521                    }),
 2522                );
 2523
 2524            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2525                editor
 2526                    ._subscriptions
 2527                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2528            }
 2529        }
 2530
 2531        // skip adding the initial selection to selection history
 2532        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2533        editor.end_selection(window, cx);
 2534        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2535
 2536        editor.scroll_manager.show_scrollbars(window, cx);
 2537        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2538
 2539        if full_mode {
 2540            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2541            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2542
 2543            if editor.git_blame_inline_enabled {
 2544                editor.start_git_blame_inline(false, window, cx);
 2545            }
 2546
 2547            editor.go_to_active_debug_line(window, cx);
 2548
 2549            editor.minimap =
 2550                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2551            editor.colors = Some(LspColorData::new(cx));
 2552            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2553
 2554            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2555                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2556            }
 2557            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2558        }
 2559
 2560        editor
 2561    }
 2562
 2563    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2564        self.display_map.update(cx, |map, cx| map.snapshot(cx))
 2565    }
 2566
 2567    pub fn deploy_mouse_context_menu(
 2568        &mut self,
 2569        position: gpui::Point<Pixels>,
 2570        context_menu: Entity<ContextMenu>,
 2571        window: &mut Window,
 2572        cx: &mut Context<Self>,
 2573    ) {
 2574        self.mouse_context_menu = Some(MouseContextMenu::new(
 2575            self,
 2576            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2577            context_menu,
 2578            window,
 2579            cx,
 2580        ));
 2581    }
 2582
 2583    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2584        self.mouse_context_menu
 2585            .as_ref()
 2586            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2587    }
 2588
 2589    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2590        if self
 2591            .selections
 2592            .pending_anchor()
 2593            .is_some_and(|pending_selection| {
 2594                let snapshot = self.buffer().read(cx).snapshot(cx);
 2595                pending_selection.range().includes(range, &snapshot)
 2596            })
 2597        {
 2598            return true;
 2599        }
 2600
 2601        self.selections
 2602            .disjoint_in_range::<MultiBufferOffset>(range.clone(), &self.display_snapshot(cx))
 2603            .into_iter()
 2604            .any(|selection| {
 2605                // This is needed to cover a corner case, if we just check for an existing
 2606                // selection in the fold range, having a cursor at the start of the fold
 2607                // marks it as selected. Non-empty selections don't cause this.
 2608                let length = selection.end - selection.start;
 2609                length > 0
 2610            })
 2611    }
 2612
 2613    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2614        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2615    }
 2616
 2617    fn key_context_internal(
 2618        &self,
 2619        has_active_edit_prediction: bool,
 2620        window: &mut Window,
 2621        cx: &mut App,
 2622    ) -> KeyContext {
 2623        let mut key_context = KeyContext::new_with_defaults();
 2624        key_context.add("Editor");
 2625        let mode = match self.mode {
 2626            EditorMode::SingleLine => "single_line",
 2627            EditorMode::AutoHeight { .. } => "auto_height",
 2628            EditorMode::Minimap { .. } => "minimap",
 2629            EditorMode::Full { .. } => "full",
 2630        };
 2631
 2632        if EditorSettings::jupyter_enabled(cx) {
 2633            key_context.add("jupyter");
 2634        }
 2635
 2636        key_context.set("mode", mode);
 2637        if self.pending_rename.is_some() {
 2638            key_context.add("renaming");
 2639        }
 2640
 2641        if let Some(snippet_stack) = self.snippet_stack.last() {
 2642            key_context.add("in_snippet");
 2643
 2644            if snippet_stack.active_index > 0 {
 2645                key_context.add("has_previous_tabstop");
 2646            }
 2647
 2648            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2649                key_context.add("has_next_tabstop");
 2650            }
 2651        }
 2652
 2653        match self.context_menu.borrow().as_ref() {
 2654            Some(CodeContextMenu::Completions(menu)) => {
 2655                if menu.visible() {
 2656                    key_context.add("menu");
 2657                    key_context.add("showing_completions");
 2658                }
 2659            }
 2660            Some(CodeContextMenu::CodeActions(menu)) => {
 2661                if menu.visible() {
 2662                    key_context.add("menu");
 2663                    key_context.add("showing_code_actions")
 2664                }
 2665            }
 2666            None => {}
 2667        }
 2668
 2669        if self.signature_help_state.has_multiple_signatures() {
 2670            key_context.add("showing_signature_help");
 2671        }
 2672
 2673        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2674        if !self.focus_handle(cx).contains_focused(window, cx)
 2675            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2676        {
 2677            for addon in self.addons.values() {
 2678                addon.extend_key_context(&mut key_context, cx)
 2679            }
 2680        }
 2681
 2682        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2683            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2684                Some(
 2685                    file.full_path(cx)
 2686                        .extension()?
 2687                        .to_string_lossy()
 2688                        .into_owned(),
 2689                )
 2690            }) {
 2691                key_context.set("extension", extension);
 2692            }
 2693        } else {
 2694            key_context.add("multibuffer");
 2695        }
 2696
 2697        if has_active_edit_prediction {
 2698            if self.edit_prediction_in_conflict() {
 2699                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2700            } else {
 2701                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2702                key_context.add("copilot_suggestion");
 2703            }
 2704        }
 2705
 2706        if self.selection_mark_mode {
 2707            key_context.add("selection_mode");
 2708        }
 2709
 2710        let disjoint = self.selections.disjoint_anchors();
 2711        let snapshot = self.snapshot(window, cx);
 2712        let snapshot = snapshot.buffer_snapshot();
 2713        if self.mode == EditorMode::SingleLine
 2714            && let [selection] = disjoint
 2715            && selection.start == selection.end
 2716            && selection.end.to_offset(snapshot) == snapshot.len()
 2717        {
 2718            key_context.add("end_of_input");
 2719        }
 2720
 2721        if self.has_any_expanded_diff_hunks(cx) {
 2722            key_context.add("diffs_expanded");
 2723        }
 2724
 2725        key_context
 2726    }
 2727
 2728    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2729        self.last_bounds.as_ref()
 2730    }
 2731
 2732    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2733        if self.mouse_cursor_hidden {
 2734            self.mouse_cursor_hidden = false;
 2735            cx.notify();
 2736        }
 2737    }
 2738
 2739    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2740        let hide_mouse_cursor = match origin {
 2741            HideMouseCursorOrigin::TypingAction => {
 2742                matches!(
 2743                    self.hide_mouse_mode,
 2744                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2745                )
 2746            }
 2747            HideMouseCursorOrigin::MovementAction => {
 2748                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2749            }
 2750        };
 2751        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2752            self.mouse_cursor_hidden = hide_mouse_cursor;
 2753            cx.notify();
 2754        }
 2755    }
 2756
 2757    pub fn edit_prediction_in_conflict(&self) -> bool {
 2758        if !self.show_edit_predictions_in_menu() {
 2759            return false;
 2760        }
 2761
 2762        let showing_completions = self
 2763            .context_menu
 2764            .borrow()
 2765            .as_ref()
 2766            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2767
 2768        showing_completions
 2769            || self.edit_prediction_requires_modifier()
 2770            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2771            // bindings to insert tab characters.
 2772            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2773    }
 2774
 2775    pub fn accept_edit_prediction_keybind(
 2776        &self,
 2777        granularity: EditPredictionGranularity,
 2778        window: &mut Window,
 2779        cx: &mut App,
 2780    ) -> AcceptEditPredictionBinding {
 2781        let key_context = self.key_context_internal(true, window, cx);
 2782        let in_conflict = self.edit_prediction_in_conflict();
 2783
 2784        let bindings =
 2785            match granularity {
 2786                EditPredictionGranularity::Word => window
 2787                    .bindings_for_action_in_context(&AcceptNextWordEditPrediction, key_context),
 2788                EditPredictionGranularity::Line => window
 2789                    .bindings_for_action_in_context(&AcceptNextLineEditPrediction, key_context),
 2790                EditPredictionGranularity::Full => {
 2791                    window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2792                }
 2793            };
 2794
 2795        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2796            !in_conflict
 2797                || binding
 2798                    .keystrokes()
 2799                    .first()
 2800                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2801        }))
 2802    }
 2803
 2804    pub fn new_file(
 2805        workspace: &mut Workspace,
 2806        _: &workspace::NewFile,
 2807        window: &mut Window,
 2808        cx: &mut Context<Workspace>,
 2809    ) {
 2810        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2811            "Failed to create buffer",
 2812            window,
 2813            cx,
 2814            |e, _, _| match e.error_code() {
 2815                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2816                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2817                e.error_tag("required").unwrap_or("the latest version")
 2818            )),
 2819                _ => None,
 2820            },
 2821        );
 2822    }
 2823
 2824    pub fn new_in_workspace(
 2825        workspace: &mut Workspace,
 2826        window: &mut Window,
 2827        cx: &mut Context<Workspace>,
 2828    ) -> Task<Result<Entity<Editor>>> {
 2829        let project = workspace.project().clone();
 2830        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2831
 2832        cx.spawn_in(window, async move |workspace, cx| {
 2833            let buffer = create.await?;
 2834            workspace.update_in(cx, |workspace, window, cx| {
 2835                let editor =
 2836                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2837                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2838                editor
 2839            })
 2840        })
 2841    }
 2842
 2843    fn new_file_vertical(
 2844        workspace: &mut Workspace,
 2845        _: &workspace::NewFileSplitVertical,
 2846        window: &mut Window,
 2847        cx: &mut Context<Workspace>,
 2848    ) {
 2849        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 2850    }
 2851
 2852    fn new_file_horizontal(
 2853        workspace: &mut Workspace,
 2854        _: &workspace::NewFileSplitHorizontal,
 2855        window: &mut Window,
 2856        cx: &mut Context<Workspace>,
 2857    ) {
 2858        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 2859    }
 2860
 2861    fn new_file_split(
 2862        workspace: &mut Workspace,
 2863        action: &workspace::NewFileSplit,
 2864        window: &mut Window,
 2865        cx: &mut Context<Workspace>,
 2866    ) {
 2867        Self::new_file_in_direction(workspace, action.0, window, cx)
 2868    }
 2869
 2870    fn new_file_in_direction(
 2871        workspace: &mut Workspace,
 2872        direction: SplitDirection,
 2873        window: &mut Window,
 2874        cx: &mut Context<Workspace>,
 2875    ) {
 2876        let project = workspace.project().clone();
 2877        let create = project.update(cx, |project, cx| project.create_buffer(true, cx));
 2878
 2879        cx.spawn_in(window, async move |workspace, cx| {
 2880            let buffer = create.await?;
 2881            workspace.update_in(cx, move |workspace, window, cx| {
 2882                workspace.split_item(
 2883                    direction,
 2884                    Box::new(
 2885                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 2886                    ),
 2887                    window,
 2888                    cx,
 2889                )
 2890            })?;
 2891            anyhow::Ok(())
 2892        })
 2893        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 2894            match e.error_code() {
 2895                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2896                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2897                e.error_tag("required").unwrap_or("the latest version")
 2898            )),
 2899                _ => None,
 2900            }
 2901        });
 2902    }
 2903
 2904    pub fn leader_id(&self) -> Option<CollaboratorId> {
 2905        self.leader_id
 2906    }
 2907
 2908    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 2909        &self.buffer
 2910    }
 2911
 2912    pub fn project(&self) -> Option<&Entity<Project>> {
 2913        self.project.as_ref()
 2914    }
 2915
 2916    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 2917        self.workspace.as_ref()?.0.upgrade()
 2918    }
 2919
 2920    /// Returns the workspace serialization ID if this editor should be serialized.
 2921    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 2922        self.workspace
 2923            .as_ref()
 2924            .filter(|_| self.should_serialize_buffer())
 2925            .and_then(|workspace| workspace.1)
 2926    }
 2927
 2928    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 2929        self.buffer().read(cx).title(cx)
 2930    }
 2931
 2932    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 2933        let git_blame_gutter_max_author_length = self
 2934            .render_git_blame_gutter(cx)
 2935            .then(|| {
 2936                if let Some(blame) = self.blame.as_ref() {
 2937                    let max_author_length =
 2938                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 2939                    Some(max_author_length)
 2940                } else {
 2941                    None
 2942                }
 2943            })
 2944            .flatten();
 2945
 2946        EditorSnapshot {
 2947            mode: self.mode.clone(),
 2948            show_gutter: self.show_gutter,
 2949            offset_content: self.offset_content,
 2950            show_line_numbers: self.show_line_numbers,
 2951            show_git_diff_gutter: self.show_git_diff_gutter,
 2952            show_code_actions: self.show_code_actions,
 2953            show_runnables: self.show_runnables,
 2954            show_breakpoints: self.show_breakpoints,
 2955            git_blame_gutter_max_author_length,
 2956            display_snapshot: self.display_map.update(cx, |map, cx| map.snapshot(cx)),
 2957            placeholder_display_snapshot: self
 2958                .placeholder_display_map
 2959                .as_ref()
 2960                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 2961            scroll_anchor: self.scroll_manager.anchor(),
 2962            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 2963            is_focused: self.focus_handle.is_focused(window),
 2964            current_line_highlight: self
 2965                .current_line_highlight
 2966                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 2967            gutter_hovered: self.gutter_hovered,
 2968        }
 2969    }
 2970
 2971    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 2972        self.buffer.read(cx).language_at(point, cx)
 2973    }
 2974
 2975    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 2976        self.buffer.read(cx).read(cx).file_at(point).cloned()
 2977    }
 2978
 2979    pub fn active_excerpt(
 2980        &self,
 2981        cx: &App,
 2982    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 2983        self.buffer
 2984            .read(cx)
 2985            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 2986    }
 2987
 2988    pub fn mode(&self) -> &EditorMode {
 2989        &self.mode
 2990    }
 2991
 2992    pub fn set_mode(&mut self, mode: EditorMode) {
 2993        self.mode = mode;
 2994    }
 2995
 2996    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 2997        self.collaboration_hub.as_deref()
 2998    }
 2999
 3000    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 3001        self.collaboration_hub = Some(hub);
 3002    }
 3003
 3004    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 3005        self.in_project_search = in_project_search;
 3006    }
 3007
 3008    pub fn set_custom_context_menu(
 3009        &mut self,
 3010        f: impl 'static
 3011        + Fn(
 3012            &mut Self,
 3013            DisplayPoint,
 3014            &mut Window,
 3015            &mut Context<Self>,
 3016        ) -> Option<Entity<ui::ContextMenu>>,
 3017    ) {
 3018        self.custom_context_menu = Some(Box::new(f))
 3019    }
 3020
 3021    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 3022        self.completion_provider = provider;
 3023    }
 3024
 3025    #[cfg(any(test, feature = "test-support"))]
 3026    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 3027        self.completion_provider.clone()
 3028    }
 3029
 3030    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 3031        self.semantics_provider.clone()
 3032    }
 3033
 3034    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 3035        self.semantics_provider = provider;
 3036    }
 3037
 3038    pub fn set_edit_prediction_provider<T>(
 3039        &mut self,
 3040        provider: Option<Entity<T>>,
 3041        window: &mut Window,
 3042        cx: &mut Context<Self>,
 3043    ) where
 3044        T: EditPredictionDelegate,
 3045    {
 3046        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionDelegate {
 3047            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 3048                if this.focus_handle.is_focused(window) {
 3049                    this.update_visible_edit_prediction(window, cx);
 3050                }
 3051            }),
 3052            provider: Arc::new(provider),
 3053        });
 3054        self.update_edit_prediction_settings(cx);
 3055        self.refresh_edit_prediction(false, false, window, cx);
 3056    }
 3057
 3058    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 3059        self.placeholder_display_map
 3060            .as_ref()
 3061            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 3062    }
 3063
 3064    pub fn set_placeholder_text(
 3065        &mut self,
 3066        placeholder_text: &str,
 3067        window: &mut Window,
 3068        cx: &mut Context<Self>,
 3069    ) {
 3070        let multibuffer = cx
 3071            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 3072
 3073        let style = window.text_style();
 3074
 3075        self.placeholder_display_map = Some(cx.new(|cx| {
 3076            DisplayMap::new(
 3077                multibuffer,
 3078                style.font(),
 3079                style.font_size.to_pixels(window.rem_size()),
 3080                None,
 3081                FILE_HEADER_HEIGHT,
 3082                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 3083                Default::default(),
 3084                DiagnosticSeverity::Off,
 3085                cx,
 3086            )
 3087        }));
 3088        cx.notify();
 3089    }
 3090
 3091    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 3092        self.cursor_shape = cursor_shape;
 3093
 3094        // Disrupt blink for immediate user feedback that the cursor shape has changed
 3095        self.blink_manager.update(cx, BlinkManager::show_cursor);
 3096
 3097        cx.notify();
 3098    }
 3099
 3100    pub fn cursor_shape(&self) -> CursorShape {
 3101        self.cursor_shape
 3102    }
 3103
 3104    pub fn set_current_line_highlight(
 3105        &mut self,
 3106        current_line_highlight: Option<CurrentLineHighlight>,
 3107    ) {
 3108        self.current_line_highlight = current_line_highlight;
 3109    }
 3110
 3111    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 3112        self.collapse_matches = collapse_matches;
 3113    }
 3114
 3115    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 3116        if self.collapse_matches {
 3117            return range.start..range.start;
 3118        }
 3119        range.clone()
 3120    }
 3121
 3122    pub fn clip_at_line_ends(&mut self, cx: &mut Context<Self>) -> bool {
 3123        self.display_map.read(cx).clip_at_line_ends
 3124    }
 3125
 3126    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3127        if self.display_map.read(cx).clip_at_line_ends != clip {
 3128            self.display_map
 3129                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3130        }
 3131    }
 3132
 3133    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3134        self.input_enabled = input_enabled;
 3135    }
 3136
 3137    pub fn set_edit_predictions_hidden_for_vim_mode(
 3138        &mut self,
 3139        hidden: bool,
 3140        window: &mut Window,
 3141        cx: &mut Context<Self>,
 3142    ) {
 3143        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3144            self.edit_predictions_hidden_for_vim_mode = hidden;
 3145            if hidden {
 3146                self.update_visible_edit_prediction(window, cx);
 3147            } else {
 3148                self.refresh_edit_prediction(true, false, window, cx);
 3149            }
 3150        }
 3151    }
 3152
 3153    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3154        self.menu_edit_predictions_policy = value;
 3155    }
 3156
 3157    pub fn set_autoindent(&mut self, autoindent: bool) {
 3158        if autoindent {
 3159            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3160        } else {
 3161            self.autoindent_mode = None;
 3162        }
 3163    }
 3164
 3165    pub fn read_only(&self, cx: &App) -> bool {
 3166        self.read_only || self.buffer.read(cx).read_only()
 3167    }
 3168
 3169    pub fn set_read_only(&mut self, read_only: bool) {
 3170        self.read_only = read_only;
 3171    }
 3172
 3173    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3174        self.use_autoclose = autoclose;
 3175    }
 3176
 3177    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3178        self.use_auto_surround = auto_surround;
 3179    }
 3180
 3181    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3182        self.auto_replace_emoji_shortcode = auto_replace;
 3183    }
 3184
 3185    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3186        self.buffer_serialization = should_serialize.then(|| {
 3187            BufferSerialization::new(
 3188                ProjectSettings::get_global(cx)
 3189                    .session
 3190                    .restore_unsaved_buffers,
 3191            )
 3192        })
 3193    }
 3194
 3195    fn should_serialize_buffer(&self) -> bool {
 3196        self.buffer_serialization.is_some()
 3197    }
 3198
 3199    pub fn toggle_edit_predictions(
 3200        &mut self,
 3201        _: &ToggleEditPrediction,
 3202        window: &mut Window,
 3203        cx: &mut Context<Self>,
 3204    ) {
 3205        if self.show_edit_predictions_override.is_some() {
 3206            self.set_show_edit_predictions(None, window, cx);
 3207        } else {
 3208            let show_edit_predictions = !self.edit_predictions_enabled();
 3209            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3210        }
 3211    }
 3212
 3213    pub fn set_show_completions_on_input(&mut self, show_completions_on_input: Option<bool>) {
 3214        self.show_completions_on_input_override = show_completions_on_input;
 3215    }
 3216
 3217    pub fn set_show_edit_predictions(
 3218        &mut self,
 3219        show_edit_predictions: Option<bool>,
 3220        window: &mut Window,
 3221        cx: &mut Context<Self>,
 3222    ) {
 3223        self.show_edit_predictions_override = show_edit_predictions;
 3224        self.update_edit_prediction_settings(cx);
 3225
 3226        if let Some(false) = show_edit_predictions {
 3227            self.discard_edit_prediction(false, cx);
 3228        } else {
 3229            self.refresh_edit_prediction(false, true, window, cx);
 3230        }
 3231    }
 3232
 3233    fn edit_predictions_disabled_in_scope(
 3234        &self,
 3235        buffer: &Entity<Buffer>,
 3236        buffer_position: language::Anchor,
 3237        cx: &App,
 3238    ) -> bool {
 3239        let snapshot = buffer.read(cx).snapshot();
 3240        let settings = snapshot.settings_at(buffer_position, cx);
 3241
 3242        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3243            return false;
 3244        };
 3245
 3246        scope.override_name().is_some_and(|scope_name| {
 3247            settings
 3248                .edit_predictions_disabled_in
 3249                .iter()
 3250                .any(|s| s == scope_name)
 3251        })
 3252    }
 3253
 3254    pub fn set_use_modal_editing(&mut self, to: bool) {
 3255        self.use_modal_editing = to;
 3256    }
 3257
 3258    pub fn use_modal_editing(&self) -> bool {
 3259        self.use_modal_editing
 3260    }
 3261
 3262    fn selections_did_change(
 3263        &mut self,
 3264        local: bool,
 3265        old_cursor_position: &Anchor,
 3266        effects: SelectionEffects,
 3267        window: &mut Window,
 3268        cx: &mut Context<Self>,
 3269    ) {
 3270        window.invalidate_character_coordinates();
 3271
 3272        // Copy selections to primary selection buffer
 3273        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3274        if local {
 3275            let selections = self
 3276                .selections
 3277                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 3278            let buffer_handle = self.buffer.read(cx).read(cx);
 3279
 3280            let mut text = String::new();
 3281            for (index, selection) in selections.iter().enumerate() {
 3282                let text_for_selection = buffer_handle
 3283                    .text_for_range(selection.start..selection.end)
 3284                    .collect::<String>();
 3285
 3286                text.push_str(&text_for_selection);
 3287                if index != selections.len() - 1 {
 3288                    text.push('\n');
 3289                }
 3290            }
 3291
 3292            if !text.is_empty() {
 3293                cx.write_to_primary(ClipboardItem::new_string(text));
 3294            }
 3295        }
 3296
 3297        let selection_anchors = self.selections.disjoint_anchors_arc();
 3298
 3299        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3300            self.buffer.update(cx, |buffer, cx| {
 3301                buffer.set_active_selections(
 3302                    &selection_anchors,
 3303                    self.selections.line_mode(),
 3304                    self.cursor_shape,
 3305                    cx,
 3306                )
 3307            });
 3308        }
 3309        let display_map = self
 3310            .display_map
 3311            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3312        let buffer = display_map.buffer_snapshot();
 3313        if self.selections.count() == 1 {
 3314            self.add_selections_state = None;
 3315        }
 3316        self.select_next_state = None;
 3317        self.select_prev_state = None;
 3318        self.select_syntax_node_history.try_clear();
 3319        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3320        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3321        self.take_rename(false, window, cx);
 3322
 3323        let newest_selection = self.selections.newest_anchor();
 3324        let new_cursor_position = newest_selection.head();
 3325        let selection_start = newest_selection.start;
 3326
 3327        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3328            self.push_to_nav_history(
 3329                *old_cursor_position,
 3330                Some(new_cursor_position.to_point(buffer)),
 3331                false,
 3332                effects.nav_history == Some(true),
 3333                cx,
 3334            );
 3335        }
 3336
 3337        if local {
 3338            if let Some(buffer_id) = new_cursor_position.text_anchor.buffer_id {
 3339                self.register_buffer(buffer_id, cx);
 3340            }
 3341
 3342            let mut context_menu = self.context_menu.borrow_mut();
 3343            let completion_menu = match context_menu.as_ref() {
 3344                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3345                Some(CodeContextMenu::CodeActions(_)) => {
 3346                    *context_menu = None;
 3347                    None
 3348                }
 3349                None => None,
 3350            };
 3351            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3352            drop(context_menu);
 3353
 3354            if effects.completions
 3355                && let Some(completion_position) = completion_position
 3356            {
 3357                let start_offset = selection_start.to_offset(buffer);
 3358                let position_matches = start_offset == completion_position.to_offset(buffer);
 3359                let continue_showing = if position_matches {
 3360                    if self.snippet_stack.is_empty() {
 3361                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3362                            == Some(CharKind::Word)
 3363                    } else {
 3364                        // Snippet choices can be shown even when the cursor is in whitespace.
 3365                        // Dismissing the menu with actions like backspace is handled by
 3366                        // invalidation regions.
 3367                        true
 3368                    }
 3369                } else {
 3370                    false
 3371                };
 3372
 3373                if continue_showing {
 3374                    self.open_or_update_completions_menu(None, None, false, window, cx);
 3375                } else {
 3376                    self.hide_context_menu(window, cx);
 3377                }
 3378            }
 3379
 3380            hide_hover(self, cx);
 3381
 3382            if old_cursor_position.to_display_point(&display_map).row()
 3383                != new_cursor_position.to_display_point(&display_map).row()
 3384            {
 3385                self.available_code_actions.take();
 3386            }
 3387            self.refresh_code_actions(window, cx);
 3388            self.refresh_document_highlights(cx);
 3389            refresh_linked_ranges(self, window, cx);
 3390
 3391            self.refresh_selected_text_highlights(false, window, cx);
 3392            self.refresh_matching_bracket_highlights(window, cx);
 3393            self.update_visible_edit_prediction(window, cx);
 3394            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3395            self.inline_blame_popover.take();
 3396            if self.git_blame_inline_enabled {
 3397                self.start_inline_blame_timer(window, cx);
 3398            }
 3399        }
 3400
 3401        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3402        cx.emit(EditorEvent::SelectionsChanged { local });
 3403
 3404        let selections = &self.selections.disjoint_anchors_arc();
 3405        if selections.len() == 1 {
 3406            cx.emit(SearchEvent::ActiveMatchChanged)
 3407        }
 3408        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3409            let inmemory_selections = selections
 3410                .iter()
 3411                .map(|s| {
 3412                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3413                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3414                })
 3415                .collect();
 3416            self.update_restoration_data(cx, |data| {
 3417                data.selections = inmemory_selections;
 3418            });
 3419
 3420            if WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
 3421                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3422            {
 3423                let snapshot = self.buffer().read(cx).snapshot(cx);
 3424                let selections = selections.clone();
 3425                let background_executor = cx.background_executor().clone();
 3426                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3427                self.serialize_selections = cx.background_spawn(async move {
 3428                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3429                    let db_selections = selections
 3430                        .iter()
 3431                        .map(|selection| {
 3432                            (
 3433                                selection.start.to_offset(&snapshot).0,
 3434                                selection.end.to_offset(&snapshot).0,
 3435                            )
 3436                        })
 3437                        .collect();
 3438
 3439                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3440                        .await
 3441                        .with_context(|| {
 3442                            format!(
 3443                                "persisting editor selections for editor {editor_id}, \
 3444                                workspace {workspace_id:?}"
 3445                            )
 3446                        })
 3447                        .log_err();
 3448                });
 3449            }
 3450        }
 3451
 3452        cx.notify();
 3453    }
 3454
 3455    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3456        use text::ToOffset as _;
 3457        use text::ToPoint as _;
 3458
 3459        if self.mode.is_minimap()
 3460            || WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
 3461        {
 3462            return;
 3463        }
 3464
 3465        if !self.buffer().read(cx).is_singleton() {
 3466            return;
 3467        }
 3468
 3469        let display_snapshot = self
 3470            .display_map
 3471            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3472        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3473            return;
 3474        };
 3475        let inmemory_folds = display_snapshot
 3476            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3477            .map(|fold| {
 3478                fold.range.start.text_anchor.to_point(&snapshot)
 3479                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3480            })
 3481            .collect();
 3482        self.update_restoration_data(cx, |data| {
 3483            data.folds = inmemory_folds;
 3484        });
 3485
 3486        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3487            return;
 3488        };
 3489        let background_executor = cx.background_executor().clone();
 3490        let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3491        let db_folds = display_snapshot
 3492            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3493            .map(|fold| {
 3494                (
 3495                    fold.range.start.text_anchor.to_offset(&snapshot),
 3496                    fold.range.end.text_anchor.to_offset(&snapshot),
 3497                )
 3498            })
 3499            .collect();
 3500        self.serialize_folds = cx.background_spawn(async move {
 3501            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3502            DB.save_editor_folds(editor_id, workspace_id, db_folds)
 3503                .await
 3504                .with_context(|| {
 3505                    format!(
 3506                        "persisting editor folds for editor {editor_id}, workspace {workspace_id:?}"
 3507                    )
 3508                })
 3509                .log_err();
 3510        });
 3511    }
 3512
 3513    pub fn sync_selections(
 3514        &mut self,
 3515        other: Entity<Editor>,
 3516        cx: &mut Context<Self>,
 3517    ) -> gpui::Subscription {
 3518        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3519        if !other_selections.is_empty() {
 3520            self.selections
 3521                .change_with(&self.display_snapshot(cx), |selections| {
 3522                    selections.select_anchors(other_selections);
 3523                });
 3524        }
 3525
 3526        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3527            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3528                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3529                if other_selections.is_empty() {
 3530                    return;
 3531                }
 3532                let snapshot = this.display_snapshot(cx);
 3533                this.selections.change_with(&snapshot, |selections| {
 3534                    selections.select_anchors(other_selections);
 3535                });
 3536            }
 3537        });
 3538
 3539        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3540            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3541                let these_selections = this.selections.disjoint_anchors().to_vec();
 3542                if these_selections.is_empty() {
 3543                    return;
 3544                }
 3545                other.update(cx, |other_editor, cx| {
 3546                    let snapshot = other_editor.display_snapshot(cx);
 3547                    other_editor
 3548                        .selections
 3549                        .change_with(&snapshot, |selections| {
 3550                            selections.select_anchors(these_selections);
 3551                        })
 3552                });
 3553            }
 3554        });
 3555
 3556        Subscription::join(other_subscription, this_subscription)
 3557    }
 3558
 3559    fn unfold_buffers_with_selections(&mut self, cx: &mut Context<Self>) {
 3560        if self.buffer().read(cx).is_singleton() {
 3561            return;
 3562        }
 3563        let snapshot = self.buffer.read(cx).snapshot(cx);
 3564        let buffer_ids: HashSet<BufferId> = self
 3565            .selections
 3566            .disjoint_anchor_ranges()
 3567            .flat_map(|range| snapshot.buffer_ids_for_range(range))
 3568            .collect();
 3569        for buffer_id in buffer_ids {
 3570            self.unfold_buffer(buffer_id, cx);
 3571        }
 3572    }
 3573
 3574    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3575    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3576    /// effects of selection change occur at the end of the transaction.
 3577    pub fn change_selections<R>(
 3578        &mut self,
 3579        effects: SelectionEffects,
 3580        window: &mut Window,
 3581        cx: &mut Context<Self>,
 3582        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 3583    ) -> R {
 3584        let snapshot = self.display_snapshot(cx);
 3585        if let Some(state) = &mut self.deferred_selection_effects_state {
 3586            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3587            state.effects.completions = effects.completions;
 3588            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3589            let (changed, result) = self.selections.change_with(&snapshot, change);
 3590            state.changed |= changed;
 3591            return result;
 3592        }
 3593        let mut state = DeferredSelectionEffectsState {
 3594            changed: false,
 3595            effects,
 3596            old_cursor_position: self.selections.newest_anchor().head(),
 3597            history_entry: SelectionHistoryEntry {
 3598                selections: self.selections.disjoint_anchors_arc(),
 3599                select_next_state: self.select_next_state.clone(),
 3600                select_prev_state: self.select_prev_state.clone(),
 3601                add_selections_state: self.add_selections_state.clone(),
 3602            },
 3603        };
 3604        let (changed, result) = self.selections.change_with(&snapshot, change);
 3605        state.changed = state.changed || changed;
 3606        if self.defer_selection_effects {
 3607            self.deferred_selection_effects_state = Some(state);
 3608        } else {
 3609            self.apply_selection_effects(state, window, cx);
 3610        }
 3611        result
 3612    }
 3613
 3614    /// Defers the effects of selection change, so that the effects of multiple calls to
 3615    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3616    /// to selection history and the state of popovers based on selection position aren't
 3617    /// erroneously updated.
 3618    pub fn with_selection_effects_deferred<R>(
 3619        &mut self,
 3620        window: &mut Window,
 3621        cx: &mut Context<Self>,
 3622        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3623    ) -> R {
 3624        let already_deferred = self.defer_selection_effects;
 3625        self.defer_selection_effects = true;
 3626        let result = update(self, window, cx);
 3627        if !already_deferred {
 3628            self.defer_selection_effects = false;
 3629            if let Some(state) = self.deferred_selection_effects_state.take() {
 3630                self.apply_selection_effects(state, window, cx);
 3631            }
 3632        }
 3633        result
 3634    }
 3635
 3636    fn apply_selection_effects(
 3637        &mut self,
 3638        state: DeferredSelectionEffectsState,
 3639        window: &mut Window,
 3640        cx: &mut Context<Self>,
 3641    ) {
 3642        if state.changed {
 3643            self.selection_history.push(state.history_entry);
 3644
 3645            if let Some(autoscroll) = state.effects.scroll {
 3646                self.request_autoscroll(autoscroll, cx);
 3647            }
 3648
 3649            let old_cursor_position = &state.old_cursor_position;
 3650
 3651            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3652
 3653            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3654                self.show_signature_help(&ShowSignatureHelp, window, cx);
 3655            }
 3656        }
 3657    }
 3658
 3659    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3660    where
 3661        I: IntoIterator<Item = (Range<S>, T)>,
 3662        S: ToOffset,
 3663        T: Into<Arc<str>>,
 3664    {
 3665        if self.read_only(cx) {
 3666            return;
 3667        }
 3668
 3669        self.buffer
 3670            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3671    }
 3672
 3673    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3674    where
 3675        I: IntoIterator<Item = (Range<S>, T)>,
 3676        S: ToOffset,
 3677        T: Into<Arc<str>>,
 3678    {
 3679        if self.read_only(cx) {
 3680            return;
 3681        }
 3682
 3683        self.buffer.update(cx, |buffer, cx| {
 3684            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3685        });
 3686    }
 3687
 3688    pub fn edit_with_block_indent<I, S, T>(
 3689        &mut self,
 3690        edits: I,
 3691        original_indent_columns: Vec<Option<u32>>,
 3692        cx: &mut Context<Self>,
 3693    ) where
 3694        I: IntoIterator<Item = (Range<S>, T)>,
 3695        S: ToOffset,
 3696        T: Into<Arc<str>>,
 3697    {
 3698        if self.read_only(cx) {
 3699            return;
 3700        }
 3701
 3702        self.buffer.update(cx, |buffer, cx| {
 3703            buffer.edit(
 3704                edits,
 3705                Some(AutoindentMode::Block {
 3706                    original_indent_columns,
 3707                }),
 3708                cx,
 3709            )
 3710        });
 3711    }
 3712
 3713    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3714        self.hide_context_menu(window, cx);
 3715
 3716        match phase {
 3717            SelectPhase::Begin {
 3718                position,
 3719                add,
 3720                click_count,
 3721            } => self.begin_selection(position, add, click_count, window, cx),
 3722            SelectPhase::BeginColumnar {
 3723                position,
 3724                goal_column,
 3725                reset,
 3726                mode,
 3727            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3728            SelectPhase::Extend {
 3729                position,
 3730                click_count,
 3731            } => self.extend_selection(position, click_count, window, cx),
 3732            SelectPhase::Update {
 3733                position,
 3734                goal_column,
 3735                scroll_delta,
 3736            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3737            SelectPhase::End => self.end_selection(window, cx),
 3738        }
 3739    }
 3740
 3741    fn extend_selection(
 3742        &mut self,
 3743        position: DisplayPoint,
 3744        click_count: usize,
 3745        window: &mut Window,
 3746        cx: &mut Context<Self>,
 3747    ) {
 3748        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3749        let tail = self
 3750            .selections
 3751            .newest::<MultiBufferOffset>(&display_map)
 3752            .tail();
 3753        let click_count = click_count.max(match self.selections.select_mode() {
 3754            SelectMode::Character => 1,
 3755            SelectMode::Word(_) => 2,
 3756            SelectMode::Line(_) => 3,
 3757            SelectMode::All => 4,
 3758        });
 3759        self.begin_selection(position, false, click_count, window, cx);
 3760
 3761        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3762
 3763        let current_selection = match self.selections.select_mode() {
 3764            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 3765            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 3766        };
 3767
 3768        let mut pending_selection = self
 3769            .selections
 3770            .pending_anchor()
 3771            .cloned()
 3772            .expect("extend_selection not called with pending selection");
 3773
 3774        if pending_selection
 3775            .start
 3776            .cmp(&current_selection.start, display_map.buffer_snapshot())
 3777            == Ordering::Greater
 3778        {
 3779            pending_selection.start = current_selection.start;
 3780        }
 3781        if pending_selection
 3782            .end
 3783            .cmp(&current_selection.end, display_map.buffer_snapshot())
 3784            == Ordering::Less
 3785        {
 3786            pending_selection.end = current_selection.end;
 3787            pending_selection.reversed = true;
 3788        }
 3789
 3790        let mut pending_mode = self.selections.pending_mode().unwrap();
 3791        match &mut pending_mode {
 3792            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 3793            _ => {}
 3794        }
 3795
 3796        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 3797            SelectionEffects::scroll(Autoscroll::fit())
 3798        } else {
 3799            SelectionEffects::no_scroll()
 3800        };
 3801
 3802        self.change_selections(effects, window, cx, |s| {
 3803            s.set_pending(pending_selection.clone(), pending_mode);
 3804            s.set_is_extending(true);
 3805        });
 3806    }
 3807
 3808    fn begin_selection(
 3809        &mut self,
 3810        position: DisplayPoint,
 3811        add: bool,
 3812        click_count: usize,
 3813        window: &mut Window,
 3814        cx: &mut Context<Self>,
 3815    ) {
 3816        if !self.focus_handle.is_focused(window) {
 3817            self.last_focused_descendant = None;
 3818            window.focus(&self.focus_handle);
 3819        }
 3820
 3821        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3822        let buffer = display_map.buffer_snapshot();
 3823        let position = display_map.clip_point(position, Bias::Left);
 3824
 3825        let start;
 3826        let end;
 3827        let mode;
 3828        let mut auto_scroll;
 3829        match click_count {
 3830            1 => {
 3831                start = buffer.anchor_before(position.to_point(&display_map));
 3832                end = start;
 3833                mode = SelectMode::Character;
 3834                auto_scroll = true;
 3835            }
 3836            2 => {
 3837                let position = display_map
 3838                    .clip_point(position, Bias::Left)
 3839                    .to_offset(&display_map, Bias::Left);
 3840                let (range, _) = buffer.surrounding_word(position, None);
 3841                start = buffer.anchor_before(range.start);
 3842                end = buffer.anchor_before(range.end);
 3843                mode = SelectMode::Word(start..end);
 3844                auto_scroll = true;
 3845            }
 3846            3 => {
 3847                let position = display_map
 3848                    .clip_point(position, Bias::Left)
 3849                    .to_point(&display_map);
 3850                let line_start = display_map.prev_line_boundary(position).0;
 3851                let next_line_start = buffer.clip_point(
 3852                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 3853                    Bias::Left,
 3854                );
 3855                start = buffer.anchor_before(line_start);
 3856                end = buffer.anchor_before(next_line_start);
 3857                mode = SelectMode::Line(start..end);
 3858                auto_scroll = true;
 3859            }
 3860            _ => {
 3861                start = buffer.anchor_before(MultiBufferOffset(0));
 3862                end = buffer.anchor_before(buffer.len());
 3863                mode = SelectMode::All;
 3864                auto_scroll = false;
 3865            }
 3866        }
 3867        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 3868
 3869        let point_to_delete: Option<usize> = {
 3870            let selected_points: Vec<Selection<Point>> =
 3871                self.selections.disjoint_in_range(start..end, &display_map);
 3872
 3873            if !add || click_count > 1 {
 3874                None
 3875            } else if !selected_points.is_empty() {
 3876                Some(selected_points[0].id)
 3877            } else {
 3878                let clicked_point_already_selected =
 3879                    self.selections.disjoint_anchors().iter().find(|selection| {
 3880                        selection.start.to_point(buffer) == start.to_point(buffer)
 3881                            || selection.end.to_point(buffer) == end.to_point(buffer)
 3882                    });
 3883
 3884                clicked_point_already_selected.map(|selection| selection.id)
 3885            }
 3886        };
 3887
 3888        let selections_count = self.selections.count();
 3889        let effects = if auto_scroll {
 3890            SelectionEffects::default()
 3891        } else {
 3892            SelectionEffects::no_scroll()
 3893        };
 3894
 3895        self.change_selections(effects, window, cx, |s| {
 3896            if let Some(point_to_delete) = point_to_delete {
 3897                s.delete(point_to_delete);
 3898
 3899                if selections_count == 1 {
 3900                    s.set_pending_anchor_range(start..end, mode);
 3901                }
 3902            } else {
 3903                if !add {
 3904                    s.clear_disjoint();
 3905                }
 3906
 3907                s.set_pending_anchor_range(start..end, mode);
 3908            }
 3909        });
 3910    }
 3911
 3912    fn begin_columnar_selection(
 3913        &mut self,
 3914        position: DisplayPoint,
 3915        goal_column: u32,
 3916        reset: bool,
 3917        mode: ColumnarMode,
 3918        window: &mut Window,
 3919        cx: &mut Context<Self>,
 3920    ) {
 3921        if !self.focus_handle.is_focused(window) {
 3922            self.last_focused_descendant = None;
 3923            window.focus(&self.focus_handle);
 3924        }
 3925
 3926        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3927
 3928        if reset {
 3929            let pointer_position = display_map
 3930                .buffer_snapshot()
 3931                .anchor_before(position.to_point(&display_map));
 3932
 3933            self.change_selections(
 3934                SelectionEffects::scroll(Autoscroll::newest()),
 3935                window,
 3936                cx,
 3937                |s| {
 3938                    s.clear_disjoint();
 3939                    s.set_pending_anchor_range(
 3940                        pointer_position..pointer_position,
 3941                        SelectMode::Character,
 3942                    );
 3943                },
 3944            );
 3945        };
 3946
 3947        let tail = self.selections.newest::<Point>(&display_map).tail();
 3948        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 3949        self.columnar_selection_state = match mode {
 3950            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 3951                selection_tail: selection_anchor,
 3952                display_point: if reset {
 3953                    if position.column() != goal_column {
 3954                        Some(DisplayPoint::new(position.row(), goal_column))
 3955                    } else {
 3956                        None
 3957                    }
 3958                } else {
 3959                    None
 3960                },
 3961            }),
 3962            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 3963                selection_tail: selection_anchor,
 3964            }),
 3965        };
 3966
 3967        if !reset {
 3968            self.select_columns(position, goal_column, &display_map, window, cx);
 3969        }
 3970    }
 3971
 3972    fn update_selection(
 3973        &mut self,
 3974        position: DisplayPoint,
 3975        goal_column: u32,
 3976        scroll_delta: gpui::Point<f32>,
 3977        window: &mut Window,
 3978        cx: &mut Context<Self>,
 3979    ) {
 3980        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3981
 3982        if self.columnar_selection_state.is_some() {
 3983            self.select_columns(position, goal_column, &display_map, window, cx);
 3984        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 3985            let buffer = display_map.buffer_snapshot();
 3986            let head;
 3987            let tail;
 3988            let mode = self.selections.pending_mode().unwrap();
 3989            match &mode {
 3990                SelectMode::Character => {
 3991                    head = position.to_point(&display_map);
 3992                    tail = pending.tail().to_point(buffer);
 3993                }
 3994                SelectMode::Word(original_range) => {
 3995                    let offset = display_map
 3996                        .clip_point(position, Bias::Left)
 3997                        .to_offset(&display_map, Bias::Left);
 3998                    let original_range = original_range.to_offset(buffer);
 3999
 4000                    let head_offset = if buffer.is_inside_word(offset, None)
 4001                        || original_range.contains(&offset)
 4002                    {
 4003                        let (word_range, _) = buffer.surrounding_word(offset, None);
 4004                        if word_range.start < original_range.start {
 4005                            word_range.start
 4006                        } else {
 4007                            word_range.end
 4008                        }
 4009                    } else {
 4010                        offset
 4011                    };
 4012
 4013                    head = head_offset.to_point(buffer);
 4014                    if head_offset <= original_range.start {
 4015                        tail = original_range.end.to_point(buffer);
 4016                    } else {
 4017                        tail = original_range.start.to_point(buffer);
 4018                    }
 4019                }
 4020                SelectMode::Line(original_range) => {
 4021                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 4022
 4023                    let position = display_map
 4024                        .clip_point(position, Bias::Left)
 4025                        .to_point(&display_map);
 4026                    let line_start = display_map.prev_line_boundary(position).0;
 4027                    let next_line_start = buffer.clip_point(
 4028                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 4029                        Bias::Left,
 4030                    );
 4031
 4032                    if line_start < original_range.start {
 4033                        head = line_start
 4034                    } else {
 4035                        head = next_line_start
 4036                    }
 4037
 4038                    if head <= original_range.start {
 4039                        tail = original_range.end;
 4040                    } else {
 4041                        tail = original_range.start;
 4042                    }
 4043                }
 4044                SelectMode::All => {
 4045                    return;
 4046                }
 4047            };
 4048
 4049            if head < tail {
 4050                pending.start = buffer.anchor_before(head);
 4051                pending.end = buffer.anchor_before(tail);
 4052                pending.reversed = true;
 4053            } else {
 4054                pending.start = buffer.anchor_before(tail);
 4055                pending.end = buffer.anchor_before(head);
 4056                pending.reversed = false;
 4057            }
 4058
 4059            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4060                s.set_pending(pending.clone(), mode);
 4061            });
 4062        } else {
 4063            log::error!("update_selection dispatched with no pending selection");
 4064            return;
 4065        }
 4066
 4067        self.apply_scroll_delta(scroll_delta, window, cx);
 4068        cx.notify();
 4069    }
 4070
 4071    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4072        self.columnar_selection_state.take();
 4073        if let Some(pending_mode) = self.selections.pending_mode() {
 4074            let selections = self
 4075                .selections
 4076                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 4077            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4078                s.select(selections);
 4079                s.clear_pending();
 4080                if s.is_extending() {
 4081                    s.set_is_extending(false);
 4082                } else {
 4083                    s.set_select_mode(pending_mode);
 4084                }
 4085            });
 4086        }
 4087    }
 4088
 4089    fn select_columns(
 4090        &mut self,
 4091        head: DisplayPoint,
 4092        goal_column: u32,
 4093        display_map: &DisplaySnapshot,
 4094        window: &mut Window,
 4095        cx: &mut Context<Self>,
 4096    ) {
 4097        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 4098            return;
 4099        };
 4100
 4101        let tail = match columnar_state {
 4102            ColumnarSelectionState::FromMouse {
 4103                selection_tail,
 4104                display_point,
 4105            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 4106            ColumnarSelectionState::FromSelection { selection_tail } => {
 4107                selection_tail.to_display_point(display_map)
 4108            }
 4109        };
 4110
 4111        let start_row = cmp::min(tail.row(), head.row());
 4112        let end_row = cmp::max(tail.row(), head.row());
 4113        let start_column = cmp::min(tail.column(), goal_column);
 4114        let end_column = cmp::max(tail.column(), goal_column);
 4115        let reversed = start_column < tail.column();
 4116
 4117        let selection_ranges = (start_row.0..=end_row.0)
 4118            .map(DisplayRow)
 4119            .filter_map(|row| {
 4120                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 4121                    || start_column <= display_map.line_len(row))
 4122                    && !display_map.is_block_line(row)
 4123                {
 4124                    let start = display_map
 4125                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 4126                        .to_point(display_map);
 4127                    let end = display_map
 4128                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 4129                        .to_point(display_map);
 4130                    if reversed {
 4131                        Some(end..start)
 4132                    } else {
 4133                        Some(start..end)
 4134                    }
 4135                } else {
 4136                    None
 4137                }
 4138            })
 4139            .collect::<Vec<_>>();
 4140        if selection_ranges.is_empty() {
 4141            return;
 4142        }
 4143
 4144        let ranges = match columnar_state {
 4145            ColumnarSelectionState::FromMouse { .. } => {
 4146                let mut non_empty_ranges = selection_ranges
 4147                    .iter()
 4148                    .filter(|selection_range| selection_range.start != selection_range.end)
 4149                    .peekable();
 4150                if non_empty_ranges.peek().is_some() {
 4151                    non_empty_ranges.cloned().collect()
 4152                } else {
 4153                    selection_ranges
 4154                }
 4155            }
 4156            _ => selection_ranges,
 4157        };
 4158
 4159        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4160            s.select_ranges(ranges);
 4161        });
 4162        cx.notify();
 4163    }
 4164
 4165    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4166        self.selections
 4167            .all_adjusted(snapshot)
 4168            .iter()
 4169            .any(|selection| !selection.is_empty())
 4170    }
 4171
 4172    pub fn has_pending_nonempty_selection(&self) -> bool {
 4173        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4174            Some(Selection { start, end, .. }) => start != end,
 4175            None => false,
 4176        };
 4177
 4178        pending_nonempty_selection
 4179            || (self.columnar_selection_state.is_some()
 4180                && self.selections.disjoint_anchors().len() > 1)
 4181    }
 4182
 4183    pub fn has_pending_selection(&self) -> bool {
 4184        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4185    }
 4186
 4187    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4188        self.selection_mark_mode = false;
 4189        self.selection_drag_state = SelectionDragState::None;
 4190
 4191        if self.dismiss_menus_and_popups(true, window, cx) {
 4192            cx.notify();
 4193            return;
 4194        }
 4195        if self.clear_expanded_diff_hunks(cx) {
 4196            cx.notify();
 4197            return;
 4198        }
 4199        if self.show_git_blame_gutter {
 4200            self.show_git_blame_gutter = false;
 4201            cx.notify();
 4202            return;
 4203        }
 4204
 4205        if self.mode.is_full()
 4206            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4207        {
 4208            cx.notify();
 4209            return;
 4210        }
 4211
 4212        cx.propagate();
 4213    }
 4214
 4215    pub fn dismiss_menus_and_popups(
 4216        &mut self,
 4217        is_user_requested: bool,
 4218        window: &mut Window,
 4219        cx: &mut Context<Self>,
 4220    ) -> bool {
 4221        let mut dismissed = false;
 4222
 4223        dismissed |= self.take_rename(false, window, cx).is_some();
 4224        dismissed |= self.hide_blame_popover(true, cx);
 4225        dismissed |= hide_hover(self, cx);
 4226        dismissed |= self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 4227        dismissed |= self.hide_context_menu(window, cx).is_some();
 4228        dismissed |= self.mouse_context_menu.take().is_some();
 4229        dismissed |= is_user_requested && self.discard_edit_prediction(true, cx);
 4230        dismissed |= self.snippet_stack.pop().is_some();
 4231
 4232        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4233            self.dismiss_diagnostics(cx);
 4234            dismissed = true;
 4235        }
 4236
 4237        dismissed
 4238    }
 4239
 4240    fn linked_editing_ranges_for(
 4241        &self,
 4242        selection: Range<text::Anchor>,
 4243        cx: &App,
 4244    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4245        if self.linked_edit_ranges.is_empty() {
 4246            return None;
 4247        }
 4248        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4249            selection.end.buffer_id.and_then(|end_buffer_id| {
 4250                if selection.start.buffer_id != Some(end_buffer_id) {
 4251                    return None;
 4252                }
 4253                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4254                let snapshot = buffer.read(cx).snapshot();
 4255                self.linked_edit_ranges
 4256                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4257                    .map(|ranges| (ranges, snapshot, buffer))
 4258            })?;
 4259        use text::ToOffset as TO;
 4260        // find offset from the start of current range to current cursor position
 4261        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4262
 4263        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4264        let start_difference = start_offset - start_byte_offset;
 4265        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4266        let end_difference = end_offset - start_byte_offset;
 4267        // Current range has associated linked ranges.
 4268        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4269        for range in linked_ranges.iter() {
 4270            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4271            let end_offset = start_offset + end_difference;
 4272            let start_offset = start_offset + start_difference;
 4273            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4274                continue;
 4275            }
 4276            if self.selections.disjoint_anchor_ranges().any(|s| {
 4277                if s.start.text_anchor.buffer_id != selection.start.buffer_id
 4278                    || s.end.text_anchor.buffer_id != selection.end.buffer_id
 4279                {
 4280                    return false;
 4281                }
 4282                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4283                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4284            }) {
 4285                continue;
 4286            }
 4287            let start = buffer_snapshot.anchor_after(start_offset);
 4288            let end = buffer_snapshot.anchor_after(end_offset);
 4289            linked_edits
 4290                .entry(buffer.clone())
 4291                .or_default()
 4292                .push(start..end);
 4293        }
 4294        Some(linked_edits)
 4295    }
 4296
 4297    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4298        let text: Arc<str> = text.into();
 4299
 4300        if self.read_only(cx) {
 4301            return;
 4302        }
 4303
 4304        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4305
 4306        self.unfold_buffers_with_selections(cx);
 4307
 4308        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4309        let mut bracket_inserted = false;
 4310        let mut edits = Vec::new();
 4311        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4312        let mut new_selections = Vec::with_capacity(selections.len());
 4313        let mut new_autoclose_regions = Vec::new();
 4314        let snapshot = self.buffer.read(cx).read(cx);
 4315        let mut clear_linked_edit_ranges = false;
 4316
 4317        for (selection, autoclose_region) in
 4318            self.selections_with_autoclose_regions(selections, &snapshot)
 4319        {
 4320            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4321                // Determine if the inserted text matches the opening or closing
 4322                // bracket of any of this language's bracket pairs.
 4323                let mut bracket_pair = None;
 4324                let mut is_bracket_pair_start = false;
 4325                let mut is_bracket_pair_end = false;
 4326                if !text.is_empty() {
 4327                    let mut bracket_pair_matching_end = None;
 4328                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4329                    //  and they are removing the character that triggered IME popup.
 4330                    for (pair, enabled) in scope.brackets() {
 4331                        if !pair.close && !pair.surround {
 4332                            continue;
 4333                        }
 4334
 4335                        if enabled && pair.start.ends_with(text.as_ref()) {
 4336                            let prefix_len = pair.start.len() - text.len();
 4337                            let preceding_text_matches_prefix = prefix_len == 0
 4338                                || (selection.start.column >= (prefix_len as u32)
 4339                                    && snapshot.contains_str_at(
 4340                                        Point::new(
 4341                                            selection.start.row,
 4342                                            selection.start.column - (prefix_len as u32),
 4343                                        ),
 4344                                        &pair.start[..prefix_len],
 4345                                    ));
 4346                            if preceding_text_matches_prefix {
 4347                                bracket_pair = Some(pair.clone());
 4348                                is_bracket_pair_start = true;
 4349                                break;
 4350                            }
 4351                        }
 4352                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4353                        {
 4354                            // take first bracket pair matching end, but don't break in case a later bracket
 4355                            // pair matches start
 4356                            bracket_pair_matching_end = Some(pair.clone());
 4357                        }
 4358                    }
 4359                    if let Some(end) = bracket_pair_matching_end
 4360                        && bracket_pair.is_none()
 4361                    {
 4362                        bracket_pair = Some(end);
 4363                        is_bracket_pair_end = true;
 4364                    }
 4365                }
 4366
 4367                if let Some(bracket_pair) = bracket_pair {
 4368                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4369                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4370                    let auto_surround =
 4371                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4372                    if selection.is_empty() {
 4373                        if is_bracket_pair_start {
 4374                            // If the inserted text is a suffix of an opening bracket and the
 4375                            // selection is preceded by the rest of the opening bracket, then
 4376                            // insert the closing bracket.
 4377                            let following_text_allows_autoclose = snapshot
 4378                                .chars_at(selection.start)
 4379                                .next()
 4380                                .is_none_or(|c| scope.should_autoclose_before(c));
 4381
 4382                            let preceding_text_allows_autoclose = selection.start.column == 0
 4383                                || snapshot
 4384                                    .reversed_chars_at(selection.start)
 4385                                    .next()
 4386                                    .is_none_or(|c| {
 4387                                        bracket_pair.start != bracket_pair.end
 4388                                            || !snapshot
 4389                                                .char_classifier_at(selection.start)
 4390                                                .is_word(c)
 4391                                    });
 4392
 4393                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4394                                && bracket_pair.start.len() == 1
 4395                            {
 4396                                let target = bracket_pair.start.chars().next().unwrap();
 4397                                let current_line_count = snapshot
 4398                                    .reversed_chars_at(selection.start)
 4399                                    .take_while(|&c| c != '\n')
 4400                                    .filter(|&c| c == target)
 4401                                    .count();
 4402                                current_line_count % 2 == 1
 4403                            } else {
 4404                                false
 4405                            };
 4406
 4407                            if autoclose
 4408                                && bracket_pair.close
 4409                                && following_text_allows_autoclose
 4410                                && preceding_text_allows_autoclose
 4411                                && !is_closing_quote
 4412                            {
 4413                                let anchor = snapshot.anchor_before(selection.end);
 4414                                new_selections.push((selection.map(|_| anchor), text.len()));
 4415                                new_autoclose_regions.push((
 4416                                    anchor,
 4417                                    text.len(),
 4418                                    selection.id,
 4419                                    bracket_pair.clone(),
 4420                                ));
 4421                                edits.push((
 4422                                    selection.range(),
 4423                                    format!("{}{}", text, bracket_pair.end).into(),
 4424                                ));
 4425                                bracket_inserted = true;
 4426                                continue;
 4427                            }
 4428                        }
 4429
 4430                        if let Some(region) = autoclose_region {
 4431                            // If the selection is followed by an auto-inserted closing bracket,
 4432                            // then don't insert that closing bracket again; just move the selection
 4433                            // past the closing bracket.
 4434                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4435                                && text.as_ref() == region.pair.end.as_str()
 4436                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4437                            if should_skip {
 4438                                let anchor = snapshot.anchor_after(selection.end);
 4439                                new_selections
 4440                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4441                                continue;
 4442                            }
 4443                        }
 4444
 4445                        let always_treat_brackets_as_autoclosed = snapshot
 4446                            .language_settings_at(selection.start, cx)
 4447                            .always_treat_brackets_as_autoclosed;
 4448                        if always_treat_brackets_as_autoclosed
 4449                            && is_bracket_pair_end
 4450                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4451                        {
 4452                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4453                            // and the inserted text is a closing bracket and the selection is followed
 4454                            // by the closing bracket then move the selection past the closing bracket.
 4455                            let anchor = snapshot.anchor_after(selection.end);
 4456                            new_selections.push((selection.map(|_| anchor), text.len()));
 4457                            continue;
 4458                        }
 4459                    }
 4460                    // If an opening bracket is 1 character long and is typed while
 4461                    // text is selected, then surround that text with the bracket pair.
 4462                    else if auto_surround
 4463                        && bracket_pair.surround
 4464                        && is_bracket_pair_start
 4465                        && bracket_pair.start.chars().count() == 1
 4466                    {
 4467                        edits.push((selection.start..selection.start, text.clone()));
 4468                        edits.push((
 4469                            selection.end..selection.end,
 4470                            bracket_pair.end.as_str().into(),
 4471                        ));
 4472                        bracket_inserted = true;
 4473                        new_selections.push((
 4474                            Selection {
 4475                                id: selection.id,
 4476                                start: snapshot.anchor_after(selection.start),
 4477                                end: snapshot.anchor_before(selection.end),
 4478                                reversed: selection.reversed,
 4479                                goal: selection.goal,
 4480                            },
 4481                            0,
 4482                        ));
 4483                        continue;
 4484                    }
 4485                }
 4486            }
 4487
 4488            if self.auto_replace_emoji_shortcode
 4489                && selection.is_empty()
 4490                && text.as_ref().ends_with(':')
 4491                && let Some(possible_emoji_short_code) =
 4492                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4493                && !possible_emoji_short_code.is_empty()
 4494                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4495            {
 4496                let emoji_shortcode_start = Point::new(
 4497                    selection.start.row,
 4498                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4499                );
 4500
 4501                // Remove shortcode from buffer
 4502                edits.push((
 4503                    emoji_shortcode_start..selection.start,
 4504                    "".to_string().into(),
 4505                ));
 4506                new_selections.push((
 4507                    Selection {
 4508                        id: selection.id,
 4509                        start: snapshot.anchor_after(emoji_shortcode_start),
 4510                        end: snapshot.anchor_before(selection.start),
 4511                        reversed: selection.reversed,
 4512                        goal: selection.goal,
 4513                    },
 4514                    0,
 4515                ));
 4516
 4517                // Insert emoji
 4518                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4519                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4520                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4521
 4522                continue;
 4523            }
 4524
 4525            // If not handling any auto-close operation, then just replace the selected
 4526            // text with the given input and move the selection to the end of the
 4527            // newly inserted text.
 4528            let anchor = snapshot.anchor_after(selection.end);
 4529            if !self.linked_edit_ranges.is_empty() {
 4530                let start_anchor = snapshot.anchor_before(selection.start);
 4531
 4532                let is_word_char = text.chars().next().is_none_or(|char| {
 4533                    let classifier = snapshot
 4534                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4535                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4536                    classifier.is_word(char)
 4537                });
 4538
 4539                if is_word_char {
 4540                    if let Some(ranges) = self
 4541                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4542                    {
 4543                        for (buffer, edits) in ranges {
 4544                            linked_edits
 4545                                .entry(buffer.clone())
 4546                                .or_default()
 4547                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4548                        }
 4549                    }
 4550                } else {
 4551                    clear_linked_edit_ranges = true;
 4552                }
 4553            }
 4554
 4555            new_selections.push((selection.map(|_| anchor), 0));
 4556            edits.push((selection.start..selection.end, text.clone()));
 4557        }
 4558
 4559        drop(snapshot);
 4560
 4561        self.transact(window, cx, |this, window, cx| {
 4562            if clear_linked_edit_ranges {
 4563                this.linked_edit_ranges.clear();
 4564            }
 4565            let initial_buffer_versions =
 4566                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4567
 4568            this.buffer.update(cx, |buffer, cx| {
 4569                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4570            });
 4571            for (buffer, edits) in linked_edits {
 4572                buffer.update(cx, |buffer, cx| {
 4573                    let snapshot = buffer.snapshot();
 4574                    let edits = edits
 4575                        .into_iter()
 4576                        .map(|(range, text)| {
 4577                            use text::ToPoint as TP;
 4578                            let end_point = TP::to_point(&range.end, &snapshot);
 4579                            let start_point = TP::to_point(&range.start, &snapshot);
 4580                            (start_point..end_point, text)
 4581                        })
 4582                        .sorted_by_key(|(range, _)| range.start);
 4583                    buffer.edit(edits, None, cx);
 4584                })
 4585            }
 4586            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4587            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4588            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4589            let new_selections = resolve_selections_wrapping_blocks::<MultiBufferOffset, _>(
 4590                new_anchor_selections,
 4591                &map,
 4592            )
 4593            .zip(new_selection_deltas)
 4594            .map(|(selection, delta)| Selection {
 4595                id: selection.id,
 4596                start: selection.start + delta,
 4597                end: selection.end + delta,
 4598                reversed: selection.reversed,
 4599                goal: SelectionGoal::None,
 4600            })
 4601            .collect::<Vec<_>>();
 4602
 4603            let mut i = 0;
 4604            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4605                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4606                let start = map.buffer_snapshot().anchor_before(position);
 4607                let end = map.buffer_snapshot().anchor_after(position);
 4608                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4609                    match existing_state
 4610                        .range
 4611                        .start
 4612                        .cmp(&start, map.buffer_snapshot())
 4613                    {
 4614                        Ordering::Less => i += 1,
 4615                        Ordering::Greater => break,
 4616                        Ordering::Equal => {
 4617                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4618                                Ordering::Less => i += 1,
 4619                                Ordering::Equal => break,
 4620                                Ordering::Greater => break,
 4621                            }
 4622                        }
 4623                    }
 4624                }
 4625                this.autoclose_regions.insert(
 4626                    i,
 4627                    AutocloseRegion {
 4628                        selection_id,
 4629                        range: start..end,
 4630                        pair,
 4631                    },
 4632                );
 4633            }
 4634
 4635            let had_active_edit_prediction = this.has_active_edit_prediction();
 4636            this.change_selections(
 4637                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4638                window,
 4639                cx,
 4640                |s| s.select(new_selections),
 4641            );
 4642
 4643            if !bracket_inserted
 4644                && let Some(on_type_format_task) =
 4645                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4646            {
 4647                on_type_format_task.detach_and_log_err(cx);
 4648            }
 4649
 4650            let editor_settings = EditorSettings::get_global(cx);
 4651            if bracket_inserted
 4652                && (editor_settings.auto_signature_help
 4653                    || editor_settings.show_signature_help_after_edits)
 4654            {
 4655                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4656            }
 4657
 4658            let trigger_in_words =
 4659                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4660            if this.hard_wrap.is_some() {
 4661                let latest: Range<Point> = this.selections.newest(&map).range();
 4662                if latest.is_empty()
 4663                    && this
 4664                        .buffer()
 4665                        .read(cx)
 4666                        .snapshot(cx)
 4667                        .line_len(MultiBufferRow(latest.start.row))
 4668                        == latest.start.column
 4669                {
 4670                    this.rewrap_impl(
 4671                        RewrapOptions {
 4672                            override_language_settings: true,
 4673                            preserve_existing_whitespace: true,
 4674                        },
 4675                        cx,
 4676                    )
 4677                }
 4678            }
 4679            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4680            refresh_linked_ranges(this, window, cx);
 4681            this.refresh_edit_prediction(true, false, window, cx);
 4682            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4683        });
 4684    }
 4685
 4686    fn find_possible_emoji_shortcode_at_position(
 4687        snapshot: &MultiBufferSnapshot,
 4688        position: Point,
 4689    ) -> Option<String> {
 4690        let mut chars = Vec::new();
 4691        let mut found_colon = false;
 4692        for char in snapshot.reversed_chars_at(position).take(100) {
 4693            // Found a possible emoji shortcode in the middle of the buffer
 4694            if found_colon {
 4695                if char.is_whitespace() {
 4696                    chars.reverse();
 4697                    return Some(chars.iter().collect());
 4698                }
 4699                // If the previous character is not a whitespace, we are in the middle of a word
 4700                // and we only want to complete the shortcode if the word is made up of other emojis
 4701                let mut containing_word = String::new();
 4702                for ch in snapshot
 4703                    .reversed_chars_at(position)
 4704                    .skip(chars.len() + 1)
 4705                    .take(100)
 4706                {
 4707                    if ch.is_whitespace() {
 4708                        break;
 4709                    }
 4710                    containing_word.push(ch);
 4711                }
 4712                let containing_word = containing_word.chars().rev().collect::<String>();
 4713                if util::word_consists_of_emojis(containing_word.as_str()) {
 4714                    chars.reverse();
 4715                    return Some(chars.iter().collect());
 4716                }
 4717            }
 4718
 4719            if char.is_whitespace() || !char.is_ascii() {
 4720                return None;
 4721            }
 4722            if char == ':' {
 4723                found_colon = true;
 4724            } else {
 4725                chars.push(char);
 4726            }
 4727        }
 4728        // Found a possible emoji shortcode at the beginning of the buffer
 4729        chars.reverse();
 4730        Some(chars.iter().collect())
 4731    }
 4732
 4733    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4734        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4735        self.transact(window, cx, |this, window, cx| {
 4736            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4737                let selections = this
 4738                    .selections
 4739                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
 4740                let multi_buffer = this.buffer.read(cx);
 4741                let buffer = multi_buffer.snapshot(cx);
 4742                selections
 4743                    .iter()
 4744                    .map(|selection| {
 4745                        let start_point = selection.start.to_point(&buffer);
 4746                        let mut existing_indent =
 4747                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4748                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4749                        let start = selection.start;
 4750                        let end = selection.end;
 4751                        let selection_is_empty = start == end;
 4752                        let language_scope = buffer.language_scope_at(start);
 4753                        let (
 4754                            comment_delimiter,
 4755                            doc_delimiter,
 4756                            insert_extra_newline,
 4757                            indent_on_newline,
 4758                            indent_on_extra_newline,
 4759                        ) = if let Some(language) = &language_scope {
 4760                            let mut insert_extra_newline =
 4761                                insert_extra_newline_brackets(&buffer, start..end, language)
 4762                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4763
 4764                            // Comment extension on newline is allowed only for cursor selections
 4765                            let comment_delimiter = maybe!({
 4766                                if !selection_is_empty {
 4767                                    return None;
 4768                                }
 4769
 4770                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4771                                    return None;
 4772                                }
 4773
 4774                                let delimiters = language.line_comment_prefixes();
 4775                                let max_len_of_delimiter =
 4776                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4777                                let (snapshot, range) =
 4778                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4779
 4780                                let num_of_whitespaces = snapshot
 4781                                    .chars_for_range(range.clone())
 4782                                    .take_while(|c| c.is_whitespace())
 4783                                    .count();
 4784                                let comment_candidate = snapshot
 4785                                    .chars_for_range(range.clone())
 4786                                    .skip(num_of_whitespaces)
 4787                                    .take(max_len_of_delimiter)
 4788                                    .collect::<String>();
 4789                                let (delimiter, trimmed_len) = delimiters
 4790                                    .iter()
 4791                                    .filter_map(|delimiter| {
 4792                                        let prefix = delimiter.trim_end();
 4793                                        if comment_candidate.starts_with(prefix) {
 4794                                            Some((delimiter, prefix.len()))
 4795                                        } else {
 4796                                            None
 4797                                        }
 4798                                    })
 4799                                    .max_by_key(|(_, len)| *len)?;
 4800
 4801                                if let Some(BlockCommentConfig {
 4802                                    start: block_start, ..
 4803                                }) = language.block_comment()
 4804                                {
 4805                                    let block_start_trimmed = block_start.trim_end();
 4806                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4807                                        let line_content = snapshot
 4808                                            .chars_for_range(range)
 4809                                            .skip(num_of_whitespaces)
 4810                                            .take(block_start_trimmed.len())
 4811                                            .collect::<String>();
 4812
 4813                                        if line_content.starts_with(block_start_trimmed) {
 4814                                            return None;
 4815                                        }
 4816                                    }
 4817                                }
 4818
 4819                                let cursor_is_placed_after_comment_marker =
 4820                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4821                                if cursor_is_placed_after_comment_marker {
 4822                                    Some(delimiter.clone())
 4823                                } else {
 4824                                    None
 4825                                }
 4826                            });
 4827
 4828                            let mut indent_on_newline = IndentSize::spaces(0);
 4829                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4830
 4831                            let doc_delimiter = maybe!({
 4832                                if !selection_is_empty {
 4833                                    return None;
 4834                                }
 4835
 4836                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4837                                    return None;
 4838                                }
 4839
 4840                                let BlockCommentConfig {
 4841                                    start: start_tag,
 4842                                    end: end_tag,
 4843                                    prefix: delimiter,
 4844                                    tab_size: len,
 4845                                } = language.documentation_comment()?;
 4846                                let is_within_block_comment = buffer
 4847                                    .language_scope_at(start_point)
 4848                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4849                                if !is_within_block_comment {
 4850                                    return None;
 4851                                }
 4852
 4853                                let (snapshot, range) =
 4854                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4855
 4856                                let num_of_whitespaces = snapshot
 4857                                    .chars_for_range(range.clone())
 4858                                    .take_while(|c| c.is_whitespace())
 4859                                    .count();
 4860
 4861                                // 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.
 4862                                let column = start_point.column;
 4863                                let cursor_is_after_start_tag = {
 4864                                    let start_tag_len = start_tag.len();
 4865                                    let start_tag_line = snapshot
 4866                                        .chars_for_range(range.clone())
 4867                                        .skip(num_of_whitespaces)
 4868                                        .take(start_tag_len)
 4869                                        .collect::<String>();
 4870                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4871                                        num_of_whitespaces + start_tag_len <= column as usize
 4872                                    } else {
 4873                                        false
 4874                                    }
 4875                                };
 4876
 4877                                let cursor_is_after_delimiter = {
 4878                                    let delimiter_trim = delimiter.trim_end();
 4879                                    let delimiter_line = snapshot
 4880                                        .chars_for_range(range.clone())
 4881                                        .skip(num_of_whitespaces)
 4882                                        .take(delimiter_trim.len())
 4883                                        .collect::<String>();
 4884                                    if delimiter_line.starts_with(delimiter_trim) {
 4885                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4886                                    } else {
 4887                                        false
 4888                                    }
 4889                                };
 4890
 4891                                let cursor_is_before_end_tag_if_exists = {
 4892                                    let mut char_position = 0u32;
 4893                                    let mut end_tag_offset = None;
 4894
 4895                                    'outer: for chunk in snapshot.text_for_range(range) {
 4896                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4897                                            let chars_before_match =
 4898                                                chunk[..byte_pos].chars().count() as u32;
 4899                                            end_tag_offset =
 4900                                                Some(char_position + chars_before_match);
 4901                                            break 'outer;
 4902                                        }
 4903                                        char_position += chunk.chars().count() as u32;
 4904                                    }
 4905
 4906                                    if let Some(end_tag_offset) = end_tag_offset {
 4907                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4908                                        if cursor_is_after_start_tag {
 4909                                            if cursor_is_before_end_tag {
 4910                                                insert_extra_newline = true;
 4911                                            }
 4912                                            let cursor_is_at_start_of_end_tag =
 4913                                                column == end_tag_offset;
 4914                                            if cursor_is_at_start_of_end_tag {
 4915                                                indent_on_extra_newline.len = *len;
 4916                                            }
 4917                                        }
 4918                                        cursor_is_before_end_tag
 4919                                    } else {
 4920                                        true
 4921                                    }
 4922                                };
 4923
 4924                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4925                                    && cursor_is_before_end_tag_if_exists
 4926                                {
 4927                                    if cursor_is_after_start_tag {
 4928                                        indent_on_newline.len = *len;
 4929                                    }
 4930                                    Some(delimiter.clone())
 4931                                } else {
 4932                                    None
 4933                                }
 4934                            });
 4935
 4936                            (
 4937                                comment_delimiter,
 4938                                doc_delimiter,
 4939                                insert_extra_newline,
 4940                                indent_on_newline,
 4941                                indent_on_extra_newline,
 4942                            )
 4943                        } else {
 4944                            (
 4945                                None,
 4946                                None,
 4947                                false,
 4948                                IndentSize::default(),
 4949                                IndentSize::default(),
 4950                            )
 4951                        };
 4952
 4953                        let prevent_auto_indent = doc_delimiter.is_some();
 4954                        let delimiter = comment_delimiter.or(doc_delimiter);
 4955
 4956                        let capacity_for_delimiter =
 4957                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4958                        let mut new_text = String::with_capacity(
 4959                            1 + capacity_for_delimiter
 4960                                + existing_indent.len as usize
 4961                                + indent_on_newline.len as usize
 4962                                + indent_on_extra_newline.len as usize,
 4963                        );
 4964                        new_text.push('\n');
 4965                        new_text.extend(existing_indent.chars());
 4966                        new_text.extend(indent_on_newline.chars());
 4967
 4968                        if let Some(delimiter) = &delimiter {
 4969                            new_text.push_str(delimiter);
 4970                        }
 4971
 4972                        if insert_extra_newline {
 4973                            new_text.push('\n');
 4974                            new_text.extend(existing_indent.chars());
 4975                            new_text.extend(indent_on_extra_newline.chars());
 4976                        }
 4977
 4978                        let anchor = buffer.anchor_after(end);
 4979                        let new_selection = selection.map(|_| anchor);
 4980                        (
 4981                            ((start..end, new_text), prevent_auto_indent),
 4982                            (insert_extra_newline, new_selection),
 4983                        )
 4984                    })
 4985                    .unzip()
 4986            };
 4987
 4988            let mut auto_indent_edits = Vec::new();
 4989            let mut edits = Vec::new();
 4990            for (edit, prevent_auto_indent) in edits_with_flags {
 4991                if prevent_auto_indent {
 4992                    edits.push(edit);
 4993                } else {
 4994                    auto_indent_edits.push(edit);
 4995                }
 4996            }
 4997            if !edits.is_empty() {
 4998                this.edit(edits, cx);
 4999            }
 5000            if !auto_indent_edits.is_empty() {
 5001                this.edit_with_autoindent(auto_indent_edits, cx);
 5002            }
 5003
 5004            let buffer = this.buffer.read(cx).snapshot(cx);
 5005            let new_selections = selection_info
 5006                .into_iter()
 5007                .map(|(extra_newline_inserted, new_selection)| {
 5008                    let mut cursor = new_selection.end.to_point(&buffer);
 5009                    if extra_newline_inserted {
 5010                        cursor.row -= 1;
 5011                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 5012                    }
 5013                    new_selection.map(|_| cursor)
 5014                })
 5015                .collect();
 5016
 5017            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 5018            this.refresh_edit_prediction(true, false, window, cx);
 5019            if let Some(task) = this.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5020                task.detach_and_log_err(cx);
 5021            }
 5022        });
 5023    }
 5024
 5025    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 5026        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5027
 5028        let buffer = self.buffer.read(cx);
 5029        let snapshot = buffer.snapshot(cx);
 5030
 5031        let mut edits = Vec::new();
 5032        let mut rows = Vec::new();
 5033
 5034        for (rows_inserted, selection) in self
 5035            .selections
 5036            .all_adjusted(&self.display_snapshot(cx))
 5037            .into_iter()
 5038            .enumerate()
 5039        {
 5040            let cursor = selection.head();
 5041            let row = cursor.row;
 5042
 5043            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 5044
 5045            let newline = "\n".to_string();
 5046            edits.push((start_of_line..start_of_line, newline));
 5047
 5048            rows.push(row + rows_inserted as u32);
 5049        }
 5050
 5051        self.transact(window, cx, |editor, window, cx| {
 5052            editor.edit(edits, cx);
 5053
 5054            editor.change_selections(Default::default(), window, cx, |s| {
 5055                let mut index = 0;
 5056                s.move_cursors_with(|map, _, _| {
 5057                    let row = rows[index];
 5058                    index += 1;
 5059
 5060                    let point = Point::new(row, 0);
 5061                    let boundary = map.next_line_boundary(point).1;
 5062                    let clipped = map.clip_point(boundary, Bias::Left);
 5063
 5064                    (clipped, SelectionGoal::None)
 5065                });
 5066            });
 5067
 5068            let mut indent_edits = Vec::new();
 5069            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5070            for row in rows {
 5071                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5072                for (row, indent) in indents {
 5073                    if indent.len == 0 {
 5074                        continue;
 5075                    }
 5076
 5077                    let text = match indent.kind {
 5078                        IndentKind::Space => " ".repeat(indent.len as usize),
 5079                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5080                    };
 5081                    let point = Point::new(row.0, 0);
 5082                    indent_edits.push((point..point, text));
 5083                }
 5084            }
 5085            editor.edit(indent_edits, cx);
 5086            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5087                format.detach_and_log_err(cx);
 5088            }
 5089        });
 5090    }
 5091
 5092    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 5093        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5094
 5095        let buffer = self.buffer.read(cx);
 5096        let snapshot = buffer.snapshot(cx);
 5097
 5098        let mut edits = Vec::new();
 5099        let mut rows = Vec::new();
 5100        let mut rows_inserted = 0;
 5101
 5102        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 5103            let cursor = selection.head();
 5104            let row = cursor.row;
 5105
 5106            let point = Point::new(row + 1, 0);
 5107            let start_of_line = snapshot.clip_point(point, Bias::Left);
 5108
 5109            let newline = "\n".to_string();
 5110            edits.push((start_of_line..start_of_line, newline));
 5111
 5112            rows_inserted += 1;
 5113            rows.push(row + rows_inserted);
 5114        }
 5115
 5116        self.transact(window, cx, |editor, window, cx| {
 5117            editor.edit(edits, cx);
 5118
 5119            editor.change_selections(Default::default(), window, cx, |s| {
 5120                let mut index = 0;
 5121                s.move_cursors_with(|map, _, _| {
 5122                    let row = rows[index];
 5123                    index += 1;
 5124
 5125                    let point = Point::new(row, 0);
 5126                    let boundary = map.next_line_boundary(point).1;
 5127                    let clipped = map.clip_point(boundary, Bias::Left);
 5128
 5129                    (clipped, SelectionGoal::None)
 5130                });
 5131            });
 5132
 5133            let mut indent_edits = Vec::new();
 5134            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5135            for row in rows {
 5136                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5137                for (row, indent) in indents {
 5138                    if indent.len == 0 {
 5139                        continue;
 5140                    }
 5141
 5142                    let text = match indent.kind {
 5143                        IndentKind::Space => " ".repeat(indent.len as usize),
 5144                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5145                    };
 5146                    let point = Point::new(row.0, 0);
 5147                    indent_edits.push((point..point, text));
 5148                }
 5149            }
 5150            editor.edit(indent_edits, cx);
 5151            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5152                format.detach_and_log_err(cx);
 5153            }
 5154        });
 5155    }
 5156
 5157    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5158        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5159            original_indent_columns: Vec::new(),
 5160        });
 5161        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 5162    }
 5163
 5164    fn insert_with_autoindent_mode(
 5165        &mut self,
 5166        text: &str,
 5167        autoindent_mode: Option<AutoindentMode>,
 5168        window: &mut Window,
 5169        cx: &mut Context<Self>,
 5170    ) {
 5171        if self.read_only(cx) {
 5172            return;
 5173        }
 5174
 5175        let text: Arc<str> = text.into();
 5176        self.transact(window, cx, |this, window, cx| {
 5177            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5178            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5179                let anchors = {
 5180                    let snapshot = buffer.read(cx);
 5181                    old_selections
 5182                        .iter()
 5183                        .map(|s| {
 5184                            let anchor = snapshot.anchor_after(s.head());
 5185                            s.map(|_| anchor)
 5186                        })
 5187                        .collect::<Vec<_>>()
 5188                };
 5189                buffer.edit(
 5190                    old_selections
 5191                        .iter()
 5192                        .map(|s| (s.start..s.end, text.clone())),
 5193                    autoindent_mode,
 5194                    cx,
 5195                );
 5196                anchors
 5197            });
 5198
 5199            this.change_selections(Default::default(), window, cx, |s| {
 5200                s.select_anchors(selection_anchors);
 5201            });
 5202
 5203            cx.notify();
 5204        });
 5205    }
 5206
 5207    fn trigger_completion_on_input(
 5208        &mut self,
 5209        text: &str,
 5210        trigger_in_words: bool,
 5211        window: &mut Window,
 5212        cx: &mut Context<Self>,
 5213    ) {
 5214        let completions_source = self
 5215            .context_menu
 5216            .borrow()
 5217            .as_ref()
 5218            .and_then(|menu| match menu {
 5219                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5220                CodeContextMenu::CodeActions(_) => None,
 5221            });
 5222
 5223        match completions_source {
 5224            Some(CompletionsMenuSource::Words { .. }) => {
 5225                self.open_or_update_completions_menu(
 5226                    Some(CompletionsMenuSource::Words {
 5227                        ignore_threshold: false,
 5228                    }),
 5229                    None,
 5230                    trigger_in_words,
 5231                    window,
 5232                    cx,
 5233                );
 5234            }
 5235            _ => self.open_or_update_completions_menu(
 5236                None,
 5237                Some(text.to_owned()).filter(|x| !x.is_empty()),
 5238                true,
 5239                window,
 5240                cx,
 5241            ),
 5242        }
 5243    }
 5244
 5245    /// If any empty selections is touching the start of its innermost containing autoclose
 5246    /// region, expand it to select the brackets.
 5247    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5248        let selections = self
 5249            .selections
 5250            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 5251        let buffer = self.buffer.read(cx).read(cx);
 5252        let new_selections = self
 5253            .selections_with_autoclose_regions(selections, &buffer)
 5254            .map(|(mut selection, region)| {
 5255                if !selection.is_empty() {
 5256                    return selection;
 5257                }
 5258
 5259                if let Some(region) = region {
 5260                    let mut range = region.range.to_offset(&buffer);
 5261                    if selection.start == range.start && range.start.0 >= region.pair.start.len() {
 5262                        range.start -= region.pair.start.len();
 5263                        if buffer.contains_str_at(range.start, &region.pair.start)
 5264                            && buffer.contains_str_at(range.end, &region.pair.end)
 5265                        {
 5266                            range.end += region.pair.end.len();
 5267                            selection.start = range.start;
 5268                            selection.end = range.end;
 5269
 5270                            return selection;
 5271                        }
 5272                    }
 5273                }
 5274
 5275                let always_treat_brackets_as_autoclosed = buffer
 5276                    .language_settings_at(selection.start, cx)
 5277                    .always_treat_brackets_as_autoclosed;
 5278
 5279                if !always_treat_brackets_as_autoclosed {
 5280                    return selection;
 5281                }
 5282
 5283                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5284                    for (pair, enabled) in scope.brackets() {
 5285                        if !enabled || !pair.close {
 5286                            continue;
 5287                        }
 5288
 5289                        if buffer.contains_str_at(selection.start, &pair.end) {
 5290                            let pair_start_len = pair.start.len();
 5291                            if buffer.contains_str_at(
 5292                                selection.start.saturating_sub_usize(pair_start_len),
 5293                                &pair.start,
 5294                            ) {
 5295                                selection.start -= pair_start_len;
 5296                                selection.end += pair.end.len();
 5297
 5298                                return selection;
 5299                            }
 5300                        }
 5301                    }
 5302                }
 5303
 5304                selection
 5305            })
 5306            .collect();
 5307
 5308        drop(buffer);
 5309        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5310            selections.select(new_selections)
 5311        });
 5312    }
 5313
 5314    /// Iterate the given selections, and for each one, find the smallest surrounding
 5315    /// autoclose region. This uses the ordering of the selections and the autoclose
 5316    /// regions to avoid repeated comparisons.
 5317    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5318        &'a self,
 5319        selections: impl IntoIterator<Item = Selection<D>>,
 5320        buffer: &'a MultiBufferSnapshot,
 5321    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5322        let mut i = 0;
 5323        let mut regions = self.autoclose_regions.as_slice();
 5324        selections.into_iter().map(move |selection| {
 5325            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5326
 5327            let mut enclosing = None;
 5328            while let Some(pair_state) = regions.get(i) {
 5329                if pair_state.range.end.to_offset(buffer) < range.start {
 5330                    regions = &regions[i + 1..];
 5331                    i = 0;
 5332                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5333                    break;
 5334                } else {
 5335                    if pair_state.selection_id == selection.id {
 5336                        enclosing = Some(pair_state);
 5337                    }
 5338                    i += 1;
 5339                }
 5340            }
 5341
 5342            (selection, enclosing)
 5343        })
 5344    }
 5345
 5346    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5347    fn invalidate_autoclose_regions(
 5348        &mut self,
 5349        mut selections: &[Selection<Anchor>],
 5350        buffer: &MultiBufferSnapshot,
 5351    ) {
 5352        self.autoclose_regions.retain(|state| {
 5353            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5354                return false;
 5355            }
 5356
 5357            let mut i = 0;
 5358            while let Some(selection) = selections.get(i) {
 5359                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5360                    selections = &selections[1..];
 5361                    continue;
 5362                }
 5363                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5364                    break;
 5365                }
 5366                if selection.id == state.selection_id {
 5367                    return true;
 5368                } else {
 5369                    i += 1;
 5370                }
 5371            }
 5372            false
 5373        });
 5374    }
 5375
 5376    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5377        let offset = position.to_offset(buffer);
 5378        let (word_range, kind) =
 5379            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5380        if offset > word_range.start && kind == Some(CharKind::Word) {
 5381            Some(
 5382                buffer
 5383                    .text_for_range(word_range.start..offset)
 5384                    .collect::<String>(),
 5385            )
 5386        } else {
 5387            None
 5388        }
 5389    }
 5390
 5391    pub fn visible_excerpts(
 5392        &self,
 5393        lsp_related_only: bool,
 5394        cx: &mut Context<Editor>,
 5395    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5396        let project = self.project().cloned();
 5397        let multi_buffer = self.buffer().read(cx);
 5398        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5399        let multi_buffer_visible_start = self
 5400            .scroll_manager
 5401            .anchor()
 5402            .anchor
 5403            .to_point(&multi_buffer_snapshot);
 5404        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5405            multi_buffer_visible_start
 5406                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5407            Bias::Left,
 5408        );
 5409        multi_buffer_snapshot
 5410            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5411            .into_iter()
 5412            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5413            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5414                if !lsp_related_only {
 5415                    return Some((
 5416                        excerpt_id,
 5417                        (
 5418                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5419                            buffer.version().clone(),
 5420                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5421                        ),
 5422                    ));
 5423                }
 5424
 5425                let project = project.as_ref()?.read(cx);
 5426                let buffer_file = project::File::from_dyn(buffer.file())?;
 5427                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5428                let worktree_entry = buffer_worktree
 5429                    .read(cx)
 5430                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5431                if worktree_entry.is_ignored {
 5432                    None
 5433                } else {
 5434                    Some((
 5435                        excerpt_id,
 5436                        (
 5437                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5438                            buffer.version().clone(),
 5439                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5440                        ),
 5441                    ))
 5442                }
 5443            })
 5444            .collect()
 5445    }
 5446
 5447    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5448        TextLayoutDetails {
 5449            text_system: window.text_system().clone(),
 5450            editor_style: self.style.clone().unwrap(),
 5451            rem_size: window.rem_size(),
 5452            scroll_anchor: self.scroll_manager.anchor(),
 5453            visible_rows: self.visible_line_count(),
 5454            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5455        }
 5456    }
 5457
 5458    fn trigger_on_type_formatting(
 5459        &self,
 5460        input: String,
 5461        window: &mut Window,
 5462        cx: &mut Context<Self>,
 5463    ) -> Option<Task<Result<()>>> {
 5464        if input.chars().count() != 1 {
 5465            return None;
 5466        }
 5467
 5468        let project = self.project()?;
 5469        let position = self.selections.newest_anchor().head();
 5470        let (buffer, buffer_position) = self
 5471            .buffer
 5472            .read(cx)
 5473            .text_anchor_for_position(position, cx)?;
 5474
 5475        let settings = language_settings::language_settings(
 5476            buffer
 5477                .read(cx)
 5478                .language_at(buffer_position)
 5479                .map(|l| l.name()),
 5480            buffer.read(cx).file(),
 5481            cx,
 5482        );
 5483        if !settings.use_on_type_format {
 5484            return None;
 5485        }
 5486
 5487        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5488        // hence we do LSP request & edit on host side only — add formats to host's history.
 5489        let push_to_lsp_host_history = true;
 5490        // If this is not the host, append its history with new edits.
 5491        let push_to_client_history = project.read(cx).is_via_collab();
 5492
 5493        let on_type_formatting = project.update(cx, |project, cx| {
 5494            project.on_type_format(
 5495                buffer.clone(),
 5496                buffer_position,
 5497                input,
 5498                push_to_lsp_host_history,
 5499                cx,
 5500            )
 5501        });
 5502        Some(cx.spawn_in(window, async move |editor, cx| {
 5503            if let Some(transaction) = on_type_formatting.await? {
 5504                if push_to_client_history {
 5505                    buffer
 5506                        .update(cx, |buffer, _| {
 5507                            buffer.push_transaction(transaction, Instant::now());
 5508                            buffer.finalize_last_transaction();
 5509                        })
 5510                        .ok();
 5511                }
 5512                editor.update(cx, |editor, cx| {
 5513                    editor.refresh_document_highlights(cx);
 5514                })?;
 5515            }
 5516            Ok(())
 5517        }))
 5518    }
 5519
 5520    pub fn show_word_completions(
 5521        &mut self,
 5522        _: &ShowWordCompletions,
 5523        window: &mut Window,
 5524        cx: &mut Context<Self>,
 5525    ) {
 5526        self.open_or_update_completions_menu(
 5527            Some(CompletionsMenuSource::Words {
 5528                ignore_threshold: true,
 5529            }),
 5530            None,
 5531            false,
 5532            window,
 5533            cx,
 5534        );
 5535    }
 5536
 5537    pub fn show_completions(
 5538        &mut self,
 5539        _: &ShowCompletions,
 5540        window: &mut Window,
 5541        cx: &mut Context<Self>,
 5542    ) {
 5543        self.open_or_update_completions_menu(None, None, false, window, cx);
 5544    }
 5545
 5546    fn open_or_update_completions_menu(
 5547        &mut self,
 5548        requested_source: Option<CompletionsMenuSource>,
 5549        trigger: Option<String>,
 5550        trigger_in_words: bool,
 5551        window: &mut Window,
 5552        cx: &mut Context<Self>,
 5553    ) {
 5554        if self.pending_rename.is_some() {
 5555            return;
 5556        }
 5557
 5558        let completions_source = self
 5559            .context_menu
 5560            .borrow()
 5561            .as_ref()
 5562            .and_then(|menu| match menu {
 5563                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5564                CodeContextMenu::CodeActions(_) => None,
 5565            });
 5566
 5567        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5568
 5569        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5570        // inserted and selected. To handle that case, the start of the selection is used so that
 5571        // the menu starts with all choices.
 5572        let position = self
 5573            .selections
 5574            .newest_anchor()
 5575            .start
 5576            .bias_right(&multibuffer_snapshot);
 5577        if position.diff_base_anchor.is_some() {
 5578            return;
 5579        }
 5580        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5581        let Some(buffer) = buffer_position
 5582            .text_anchor
 5583            .buffer_id
 5584            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5585        else {
 5586            return;
 5587        };
 5588        let buffer_snapshot = buffer.read(cx).snapshot();
 5589
 5590        let menu_is_open = matches!(
 5591            self.context_menu.borrow().as_ref(),
 5592            Some(CodeContextMenu::Completions(_))
 5593        );
 5594
 5595        let language = buffer_snapshot
 5596            .language_at(buffer_position.text_anchor)
 5597            .map(|language| language.name());
 5598
 5599        let language_settings = language_settings(language.clone(), buffer_snapshot.file(), cx);
 5600        let completion_settings = language_settings.completions.clone();
 5601
 5602        let show_completions_on_input = self
 5603            .show_completions_on_input_override
 5604            .unwrap_or(language_settings.show_completions_on_input);
 5605        if !menu_is_open && trigger.is_some() && !show_completions_on_input {
 5606            return;
 5607        }
 5608
 5609        let query: Option<Arc<String>> =
 5610            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5611                .map(|query| query.into());
 5612
 5613        drop(multibuffer_snapshot);
 5614
 5615        // Hide the current completions menu when query is empty. Without this, cached
 5616        // completions from before the trigger char may be reused (#32774).
 5617        if query.is_none() && menu_is_open {
 5618            self.hide_context_menu(window, cx);
 5619        }
 5620
 5621        let mut ignore_word_threshold = false;
 5622        let provider = match requested_source {
 5623            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5624            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5625                ignore_word_threshold = ignore_threshold;
 5626                None
 5627            }
 5628            Some(CompletionsMenuSource::SnippetChoices)
 5629            | Some(CompletionsMenuSource::SnippetsOnly) => {
 5630                log::error!("bug: SnippetChoices requested_source is not handled");
 5631                None
 5632            }
 5633        };
 5634
 5635        let sort_completions = provider
 5636            .as_ref()
 5637            .is_some_and(|provider| provider.sort_completions());
 5638
 5639        let filter_completions = provider
 5640            .as_ref()
 5641            .is_none_or(|provider| provider.filter_completions());
 5642
 5643        let was_snippets_only = matches!(
 5644            completions_source,
 5645            Some(CompletionsMenuSource::SnippetsOnly)
 5646        );
 5647
 5648        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5649            if filter_completions {
 5650                menu.filter(
 5651                    query.clone().unwrap_or_default(),
 5652                    buffer_position.text_anchor,
 5653                    &buffer,
 5654                    provider.clone(),
 5655                    window,
 5656                    cx,
 5657                );
 5658            }
 5659            // When `is_incomplete` is false, no need to re-query completions when the current query
 5660            // is a suffix of the initial query.
 5661            let was_complete = !menu.is_incomplete;
 5662            if was_complete && !was_snippets_only {
 5663                // If the new query is a suffix of the old query (typing more characters) and
 5664                // the previous result was complete, the existing completions can be filtered.
 5665                //
 5666                // Note that snippet completions are always complete.
 5667                let query_matches = match (&menu.initial_query, &query) {
 5668                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5669                    (None, _) => true,
 5670                    _ => false,
 5671                };
 5672                if query_matches {
 5673                    let position_matches = if menu.initial_position == position {
 5674                        true
 5675                    } else {
 5676                        let snapshot = self.buffer.read(cx).read(cx);
 5677                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5678                    };
 5679                    if position_matches {
 5680                        return;
 5681                    }
 5682                }
 5683            }
 5684        };
 5685
 5686        let Anchor {
 5687            excerpt_id: buffer_excerpt_id,
 5688            text_anchor: buffer_position,
 5689            ..
 5690        } = buffer_position;
 5691
 5692        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5693            buffer_snapshot.surrounding_word(buffer_position, None)
 5694        {
 5695            let word_to_exclude = buffer_snapshot
 5696                .text_for_range(word_range.clone())
 5697                .collect::<String>();
 5698            (
 5699                buffer_snapshot.anchor_before(word_range.start)
 5700                    ..buffer_snapshot.anchor_after(buffer_position),
 5701                Some(word_to_exclude),
 5702            )
 5703        } else {
 5704            (buffer_position..buffer_position, None)
 5705        };
 5706
 5707        let show_completion_documentation = buffer_snapshot
 5708            .settings_at(buffer_position, cx)
 5709            .show_completion_documentation;
 5710
 5711        // The document can be large, so stay in reasonable bounds when searching for words,
 5712        // otherwise completion pop-up might be slow to appear.
 5713        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5714        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5715        let min_word_search = buffer_snapshot.clip_point(
 5716            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5717            Bias::Left,
 5718        );
 5719        let max_word_search = buffer_snapshot.clip_point(
 5720            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5721            Bias::Right,
 5722        );
 5723        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5724            ..buffer_snapshot.point_to_offset(max_word_search);
 5725
 5726        let skip_digits = query
 5727            .as_ref()
 5728            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5729
 5730        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 5731            trigger.as_ref().is_none_or(|trigger| {
 5732                provider.is_completion_trigger(
 5733                    &buffer,
 5734                    position.text_anchor,
 5735                    trigger,
 5736                    trigger_in_words,
 5737                    cx,
 5738                )
 5739            })
 5740        });
 5741
 5742        let provider_responses = if let Some(provider) = &provider
 5743            && load_provider_completions
 5744        {
 5745            let trigger_character =
 5746                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 5747            let completion_context = CompletionContext {
 5748                trigger_kind: match &trigger_character {
 5749                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 5750                    None => CompletionTriggerKind::INVOKED,
 5751                },
 5752                trigger_character,
 5753            };
 5754
 5755            provider.completions(
 5756                buffer_excerpt_id,
 5757                &buffer,
 5758                buffer_position,
 5759                completion_context,
 5760                window,
 5761                cx,
 5762            )
 5763        } else {
 5764            Task::ready(Ok(Vec::new()))
 5765        };
 5766
 5767        let load_word_completions = if !self.word_completions_enabled {
 5768            false
 5769        } else if requested_source
 5770            == Some(CompletionsMenuSource::Words {
 5771                ignore_threshold: true,
 5772            })
 5773        {
 5774            true
 5775        } else {
 5776            load_provider_completions
 5777                && completion_settings.words != WordsCompletionMode::Disabled
 5778                && (ignore_word_threshold || {
 5779                    let words_min_length = completion_settings.words_min_length;
 5780                    // check whether word has at least `words_min_length` characters
 5781                    let query_chars = query.iter().flat_map(|q| q.chars());
 5782                    query_chars.take(words_min_length).count() == words_min_length
 5783                })
 5784        };
 5785
 5786        let mut words = if load_word_completions {
 5787            cx.background_spawn({
 5788                let buffer_snapshot = buffer_snapshot.clone();
 5789                async move {
 5790                    buffer_snapshot.words_in_range(WordsQuery {
 5791                        fuzzy_contents: None,
 5792                        range: word_search_range,
 5793                        skip_digits,
 5794                    })
 5795                }
 5796            })
 5797        } else {
 5798            Task::ready(BTreeMap::default())
 5799        };
 5800
 5801        let snippets = if let Some(provider) = &provider
 5802            && provider.show_snippets()
 5803            && let Some(project) = self.project()
 5804        {
 5805            let char_classifier = buffer_snapshot
 5806                .char_classifier_at(buffer_position)
 5807                .scope_context(Some(CharScopeContext::Completion));
 5808            project.update(cx, |project, cx| {
 5809                snippet_completions(project, &buffer, buffer_position, char_classifier, cx)
 5810            })
 5811        } else {
 5812            Task::ready(Ok(CompletionResponse {
 5813                completions: Vec::new(),
 5814                display_options: Default::default(),
 5815                is_incomplete: false,
 5816            }))
 5817        };
 5818
 5819        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5820
 5821        let id = post_inc(&mut self.next_completion_id);
 5822        let task = cx.spawn_in(window, async move |editor, cx| {
 5823            let Ok(()) = editor.update(cx, |this, _| {
 5824                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5825            }) else {
 5826                return;
 5827            };
 5828
 5829            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5830            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5831            let mut completions = Vec::new();
 5832            let mut is_incomplete = false;
 5833            let mut display_options: Option<CompletionDisplayOptions> = None;
 5834            if let Some(provider_responses) = provider_responses.await.log_err()
 5835                && !provider_responses.is_empty()
 5836            {
 5837                for response in provider_responses {
 5838                    completions.extend(response.completions);
 5839                    is_incomplete = is_incomplete || response.is_incomplete;
 5840                    match display_options.as_mut() {
 5841                        None => {
 5842                            display_options = Some(response.display_options);
 5843                        }
 5844                        Some(options) => options.merge(&response.display_options),
 5845                    }
 5846                }
 5847                if completion_settings.words == WordsCompletionMode::Fallback {
 5848                    words = Task::ready(BTreeMap::default());
 5849                }
 5850            }
 5851            let display_options = display_options.unwrap_or_default();
 5852
 5853            let mut words = words.await;
 5854            if let Some(word_to_exclude) = &word_to_exclude {
 5855                words.remove(word_to_exclude);
 5856            }
 5857            for lsp_completion in &completions {
 5858                words.remove(&lsp_completion.new_text);
 5859            }
 5860            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5861                replace_range: word_replace_range.clone(),
 5862                new_text: word.clone(),
 5863                label: CodeLabel::plain(word, None),
 5864                match_start: None,
 5865                snippet_deduplication_key: None,
 5866                icon_path: None,
 5867                documentation: None,
 5868                source: CompletionSource::BufferWord {
 5869                    word_range,
 5870                    resolved: false,
 5871                },
 5872                insert_text_mode: Some(InsertTextMode::AS_IS),
 5873                confirm: None,
 5874            }));
 5875
 5876            completions.extend(
 5877                snippets
 5878                    .await
 5879                    .into_iter()
 5880                    .flat_map(|response| response.completions),
 5881            );
 5882
 5883            let menu = if completions.is_empty() {
 5884                None
 5885            } else {
 5886                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5887                    let languages = editor
 5888                        .workspace
 5889                        .as_ref()
 5890                        .and_then(|(workspace, _)| workspace.upgrade())
 5891                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5892                    let menu = CompletionsMenu::new(
 5893                        id,
 5894                        requested_source.unwrap_or(if load_provider_completions {
 5895                            CompletionsMenuSource::Normal
 5896                        } else {
 5897                            CompletionsMenuSource::SnippetsOnly
 5898                        }),
 5899                        sort_completions,
 5900                        show_completion_documentation,
 5901                        position,
 5902                        query.clone(),
 5903                        is_incomplete,
 5904                        buffer.clone(),
 5905                        completions.into(),
 5906                        editor
 5907                            .context_menu()
 5908                            .borrow_mut()
 5909                            .as_ref()
 5910                            .map(|menu| menu.primary_scroll_handle()),
 5911                        display_options,
 5912                        snippet_sort_order,
 5913                        languages,
 5914                        language,
 5915                        cx,
 5916                    );
 5917
 5918                    let query = if filter_completions { query } else { None };
 5919                    let matches_task = menu.do_async_filtering(
 5920                        query.unwrap_or_default(),
 5921                        buffer_position,
 5922                        &buffer,
 5923                        cx,
 5924                    );
 5925                    (menu, matches_task)
 5926                }) else {
 5927                    return;
 5928                };
 5929
 5930                let matches = matches_task.await;
 5931
 5932                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5933                    // Newer menu already set, so exit.
 5934                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5935                        editor.context_menu.borrow().as_ref()
 5936                        && prev_menu.id > id
 5937                    {
 5938                        return;
 5939                    };
 5940
 5941                    // Only valid to take prev_menu because either the new menu is immediately set
 5942                    // below, or the menu is hidden.
 5943                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5944                        editor.context_menu.borrow_mut().take()
 5945                    {
 5946                        let position_matches =
 5947                            if prev_menu.initial_position == menu.initial_position {
 5948                                true
 5949                            } else {
 5950                                let snapshot = editor.buffer.read(cx).read(cx);
 5951                                prev_menu.initial_position.to_offset(&snapshot)
 5952                                    == menu.initial_position.to_offset(&snapshot)
 5953                            };
 5954                        if position_matches {
 5955                            // Preserve markdown cache before `set_filter_results` because it will
 5956                            // try to populate the documentation cache.
 5957                            menu.preserve_markdown_cache(prev_menu);
 5958                        }
 5959                    };
 5960
 5961                    menu.set_filter_results(matches, provider, window, cx);
 5962                }) else {
 5963                    return;
 5964                };
 5965
 5966                menu.visible().then_some(menu)
 5967            };
 5968
 5969            editor
 5970                .update_in(cx, |editor, window, cx| {
 5971                    if editor.focus_handle.is_focused(window)
 5972                        && let Some(menu) = menu
 5973                    {
 5974                        *editor.context_menu.borrow_mut() =
 5975                            Some(CodeContextMenu::Completions(menu));
 5976
 5977                        crate::hover_popover::hide_hover(editor, cx);
 5978                        if editor.show_edit_predictions_in_menu() {
 5979                            editor.update_visible_edit_prediction(window, cx);
 5980                        } else {
 5981                            editor.discard_edit_prediction(false, cx);
 5982                        }
 5983
 5984                        cx.notify();
 5985                        return;
 5986                    }
 5987
 5988                    if editor.completion_tasks.len() <= 1 {
 5989                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 5990                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 5991                        // If it was already hidden and we don't show edit predictions in the menu,
 5992                        // we should also show the edit prediction when available.
 5993                        if was_hidden && editor.show_edit_predictions_in_menu() {
 5994                            editor.update_visible_edit_prediction(window, cx);
 5995                        }
 5996                    }
 5997                })
 5998                .ok();
 5999        });
 6000
 6001        self.completion_tasks.push((id, task));
 6002    }
 6003
 6004    #[cfg(feature = "test-support")]
 6005    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 6006        let menu = self.context_menu.borrow();
 6007        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 6008            let completions = menu.completions.borrow();
 6009            Some(completions.to_vec())
 6010        } else {
 6011            None
 6012        }
 6013    }
 6014
 6015    pub fn with_completions_menu_matching_id<R>(
 6016        &self,
 6017        id: CompletionId,
 6018        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 6019    ) -> R {
 6020        let mut context_menu = self.context_menu.borrow_mut();
 6021        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 6022            return f(None);
 6023        };
 6024        if completions_menu.id != id {
 6025            return f(None);
 6026        }
 6027        f(Some(completions_menu))
 6028    }
 6029
 6030    pub fn confirm_completion(
 6031        &mut self,
 6032        action: &ConfirmCompletion,
 6033        window: &mut Window,
 6034        cx: &mut Context<Self>,
 6035    ) -> Option<Task<Result<()>>> {
 6036        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6037        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 6038    }
 6039
 6040    pub fn confirm_completion_insert(
 6041        &mut self,
 6042        _: &ConfirmCompletionInsert,
 6043        window: &mut Window,
 6044        cx: &mut Context<Self>,
 6045    ) -> Option<Task<Result<()>>> {
 6046        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6047        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 6048    }
 6049
 6050    pub fn confirm_completion_replace(
 6051        &mut self,
 6052        _: &ConfirmCompletionReplace,
 6053        window: &mut Window,
 6054        cx: &mut Context<Self>,
 6055    ) -> Option<Task<Result<()>>> {
 6056        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6057        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 6058    }
 6059
 6060    pub fn compose_completion(
 6061        &mut self,
 6062        action: &ComposeCompletion,
 6063        window: &mut Window,
 6064        cx: &mut Context<Self>,
 6065    ) -> Option<Task<Result<()>>> {
 6066        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6067        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 6068    }
 6069
 6070    fn do_completion(
 6071        &mut self,
 6072        item_ix: Option<usize>,
 6073        intent: CompletionIntent,
 6074        window: &mut Window,
 6075        cx: &mut Context<Editor>,
 6076    ) -> Option<Task<Result<()>>> {
 6077        use language::ToOffset as _;
 6078
 6079        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 6080        else {
 6081            return None;
 6082        };
 6083
 6084        let candidate_id = {
 6085            let entries = completions_menu.entries.borrow();
 6086            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 6087            if self.show_edit_predictions_in_menu() {
 6088                self.discard_edit_prediction(true, cx);
 6089            }
 6090            mat.candidate_id
 6091        };
 6092
 6093        let completion = completions_menu
 6094            .completions
 6095            .borrow()
 6096            .get(candidate_id)?
 6097            .clone();
 6098        cx.stop_propagation();
 6099
 6100        let buffer_handle = completions_menu.buffer.clone();
 6101
 6102        let CompletionEdit {
 6103            new_text,
 6104            snippet,
 6105            replace_range,
 6106        } = process_completion_for_edit(
 6107            &completion,
 6108            intent,
 6109            &buffer_handle,
 6110            &completions_menu.initial_position.text_anchor,
 6111            cx,
 6112        );
 6113
 6114        let buffer = buffer_handle.read(cx);
 6115        let snapshot = self.buffer.read(cx).snapshot(cx);
 6116        let newest_anchor = self.selections.newest_anchor();
 6117        let replace_range_multibuffer = {
 6118            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 6119            excerpt.map_range_from_buffer(replace_range.clone())
 6120        };
 6121        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6122            return None;
 6123        }
 6124
 6125        let old_text = buffer
 6126            .text_for_range(replace_range.clone())
 6127            .collect::<String>();
 6128        let lookbehind = newest_anchor
 6129            .start
 6130            .text_anchor
 6131            .to_offset(buffer)
 6132            .saturating_sub(replace_range.start.0);
 6133        let lookahead = replace_range
 6134            .end
 6135            .0
 6136            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6137        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6138        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6139
 6140        let selections = self
 6141            .selections
 6142            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 6143        let mut ranges = Vec::new();
 6144        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6145
 6146        for selection in &selections {
 6147            let range = if selection.id == newest_anchor.id {
 6148                replace_range_multibuffer.clone()
 6149            } else {
 6150                let mut range = selection.range();
 6151
 6152                // if prefix is present, don't duplicate it
 6153                if snapshot.contains_str_at(range.start.saturating_sub_usize(lookbehind), prefix) {
 6154                    range.start = range.start.saturating_sub_usize(lookbehind);
 6155
 6156                    // if suffix is also present, mimic the newest cursor and replace it
 6157                    if selection.id != newest_anchor.id
 6158                        && snapshot.contains_str_at(range.end, suffix)
 6159                    {
 6160                        range.end += lookahead;
 6161                    }
 6162                }
 6163                range
 6164            };
 6165
 6166            ranges.push(range.clone());
 6167
 6168            if !self.linked_edit_ranges.is_empty() {
 6169                let start_anchor = snapshot.anchor_before(range.start);
 6170                let end_anchor = snapshot.anchor_after(range.end);
 6171                if let Some(ranges) = self
 6172                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6173                {
 6174                    for (buffer, edits) in ranges {
 6175                        linked_edits
 6176                            .entry(buffer.clone())
 6177                            .or_default()
 6178                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6179                    }
 6180                }
 6181            }
 6182        }
 6183
 6184        let common_prefix_len = old_text
 6185            .chars()
 6186            .zip(new_text.chars())
 6187            .take_while(|(a, b)| a == b)
 6188            .map(|(a, _)| a.len_utf8())
 6189            .sum::<usize>();
 6190
 6191        cx.emit(EditorEvent::InputHandled {
 6192            utf16_range_to_replace: None,
 6193            text: new_text[common_prefix_len..].into(),
 6194        });
 6195
 6196        self.transact(window, cx, |editor, window, cx| {
 6197            if let Some(mut snippet) = snippet {
 6198                snippet.text = new_text.to_string();
 6199                editor
 6200                    .insert_snippet(&ranges, snippet, window, cx)
 6201                    .log_err();
 6202            } else {
 6203                editor.buffer.update(cx, |multi_buffer, cx| {
 6204                    let auto_indent = match completion.insert_text_mode {
 6205                        Some(InsertTextMode::AS_IS) => None,
 6206                        _ => editor.autoindent_mode.clone(),
 6207                    };
 6208                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6209                    multi_buffer.edit(edits, auto_indent, cx);
 6210                });
 6211            }
 6212            for (buffer, edits) in linked_edits {
 6213                buffer.update(cx, |buffer, cx| {
 6214                    let snapshot = buffer.snapshot();
 6215                    let edits = edits
 6216                        .into_iter()
 6217                        .map(|(range, text)| {
 6218                            use text::ToPoint as TP;
 6219                            let end_point = TP::to_point(&range.end, &snapshot);
 6220                            let start_point = TP::to_point(&range.start, &snapshot);
 6221                            (start_point..end_point, text)
 6222                        })
 6223                        .sorted_by_key(|(range, _)| range.start);
 6224                    buffer.edit(edits, None, cx);
 6225                })
 6226            }
 6227
 6228            editor.refresh_edit_prediction(true, false, window, cx);
 6229        });
 6230        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6231
 6232        let show_new_completions_on_confirm = completion
 6233            .confirm
 6234            .as_ref()
 6235            .is_some_and(|confirm| confirm(intent, window, cx));
 6236        if show_new_completions_on_confirm {
 6237            self.open_or_update_completions_menu(None, None, false, window, cx);
 6238        }
 6239
 6240        let provider = self.completion_provider.as_ref()?;
 6241
 6242        let lsp_store = self.project().map(|project| project.read(cx).lsp_store());
 6243        let command = lsp_store.as_ref().and_then(|lsp_store| {
 6244            let CompletionSource::Lsp {
 6245                lsp_completion,
 6246                server_id,
 6247                ..
 6248            } = &completion.source
 6249            else {
 6250                return None;
 6251            };
 6252            let lsp_command = lsp_completion.command.as_ref()?;
 6253            let available_commands = lsp_store
 6254                .read(cx)
 6255                .lsp_server_capabilities
 6256                .get(server_id)
 6257                .and_then(|server_capabilities| {
 6258                    server_capabilities
 6259                        .execute_command_provider
 6260                        .as_ref()
 6261                        .map(|options| options.commands.as_slice())
 6262                })?;
 6263            if available_commands.contains(&lsp_command.command) {
 6264                Some(CodeAction {
 6265                    server_id: *server_id,
 6266                    range: language::Anchor::MIN..language::Anchor::MIN,
 6267                    lsp_action: LspAction::Command(lsp_command.clone()),
 6268                    resolved: false,
 6269                })
 6270            } else {
 6271                None
 6272            }
 6273        });
 6274
 6275        drop(completion);
 6276        let apply_edits = provider.apply_additional_edits_for_completion(
 6277            buffer_handle.clone(),
 6278            completions_menu.completions.clone(),
 6279            candidate_id,
 6280            true,
 6281            cx,
 6282        );
 6283
 6284        let editor_settings = EditorSettings::get_global(cx);
 6285        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6286            // After the code completion is finished, users often want to know what signatures are needed.
 6287            // so we should automatically call signature_help
 6288            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6289        }
 6290
 6291        Some(cx.spawn_in(window, async move |editor, cx| {
 6292            apply_edits.await?;
 6293
 6294            if let Some((lsp_store, command)) = lsp_store.zip(command) {
 6295                let title = command.lsp_action.title().to_owned();
 6296                let project_transaction = lsp_store
 6297                    .update(cx, |lsp_store, cx| {
 6298                        lsp_store.apply_code_action(buffer_handle, command, false, cx)
 6299                    })?
 6300                    .await
 6301                    .context("applying post-completion command")?;
 6302                if let Some(workspace) = editor.read_with(cx, |editor, _| editor.workspace())? {
 6303                    Self::open_project_transaction(
 6304                        &editor,
 6305                        workspace.downgrade(),
 6306                        project_transaction,
 6307                        title,
 6308                        cx,
 6309                    )
 6310                    .await?;
 6311                }
 6312            }
 6313
 6314            Ok(())
 6315        }))
 6316    }
 6317
 6318    pub fn toggle_code_actions(
 6319        &mut self,
 6320        action: &ToggleCodeActions,
 6321        window: &mut Window,
 6322        cx: &mut Context<Self>,
 6323    ) {
 6324        let quick_launch = action.quick_launch;
 6325        let mut context_menu = self.context_menu.borrow_mut();
 6326        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6327            if code_actions.deployed_from == action.deployed_from {
 6328                // Toggle if we're selecting the same one
 6329                *context_menu = None;
 6330                cx.notify();
 6331                return;
 6332            } else {
 6333                // Otherwise, clear it and start a new one
 6334                *context_menu = None;
 6335                cx.notify();
 6336            }
 6337        }
 6338        drop(context_menu);
 6339        let snapshot = self.snapshot(window, cx);
 6340        let deployed_from = action.deployed_from.clone();
 6341        let action = action.clone();
 6342        self.completion_tasks.clear();
 6343        self.discard_edit_prediction(false, cx);
 6344
 6345        let multibuffer_point = match &action.deployed_from {
 6346            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6347                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6348            }
 6349            _ => self
 6350                .selections
 6351                .newest::<Point>(&snapshot.display_snapshot)
 6352                .head(),
 6353        };
 6354        let Some((buffer, buffer_row)) = snapshot
 6355            .buffer_snapshot()
 6356            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6357            .and_then(|(buffer_snapshot, range)| {
 6358                self.buffer()
 6359                    .read(cx)
 6360                    .buffer(buffer_snapshot.remote_id())
 6361                    .map(|buffer| (buffer, range.start.row))
 6362            })
 6363        else {
 6364            return;
 6365        };
 6366        let buffer_id = buffer.read(cx).remote_id();
 6367        let tasks = self
 6368            .tasks
 6369            .get(&(buffer_id, buffer_row))
 6370            .map(|t| Arc::new(t.to_owned()));
 6371
 6372        if !self.focus_handle.is_focused(window) {
 6373            return;
 6374        }
 6375        let project = self.project.clone();
 6376
 6377        let code_actions_task = match deployed_from {
 6378            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6379            _ => self.code_actions(buffer_row, window, cx),
 6380        };
 6381
 6382        let runnable_task = match deployed_from {
 6383            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6384            _ => {
 6385                let mut task_context_task = Task::ready(None);
 6386                if let Some(tasks) = &tasks
 6387                    && let Some(project) = project
 6388                {
 6389                    task_context_task =
 6390                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6391                }
 6392
 6393                cx.spawn_in(window, {
 6394                    let buffer = buffer.clone();
 6395                    async move |editor, cx| {
 6396                        let task_context = task_context_task.await;
 6397
 6398                        let resolved_tasks =
 6399                            tasks
 6400                                .zip(task_context.clone())
 6401                                .map(|(tasks, task_context)| ResolvedTasks {
 6402                                    templates: tasks.resolve(&task_context).collect(),
 6403                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6404                                        multibuffer_point.row,
 6405                                        tasks.column,
 6406                                    )),
 6407                                });
 6408                        let debug_scenarios = editor
 6409                            .update(cx, |editor, cx| {
 6410                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6411                            })?
 6412                            .await;
 6413                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6414                    }
 6415                })
 6416            }
 6417        };
 6418
 6419        cx.spawn_in(window, async move |editor, cx| {
 6420            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6421            let code_actions = code_actions_task.await;
 6422            let spawn_straight_away = quick_launch
 6423                && resolved_tasks
 6424                    .as_ref()
 6425                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6426                && code_actions
 6427                    .as_ref()
 6428                    .is_none_or(|actions| actions.is_empty())
 6429                && debug_scenarios.is_empty();
 6430
 6431            editor.update_in(cx, |editor, window, cx| {
 6432                crate::hover_popover::hide_hover(editor, cx);
 6433                let actions = CodeActionContents::new(
 6434                    resolved_tasks,
 6435                    code_actions,
 6436                    debug_scenarios,
 6437                    task_context.unwrap_or_default(),
 6438                );
 6439
 6440                // Don't show the menu if there are no actions available
 6441                if actions.is_empty() {
 6442                    cx.notify();
 6443                    return Task::ready(Ok(()));
 6444                }
 6445
 6446                *editor.context_menu.borrow_mut() =
 6447                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6448                        buffer,
 6449                        actions,
 6450                        selected_item: Default::default(),
 6451                        scroll_handle: UniformListScrollHandle::default(),
 6452                        deployed_from,
 6453                    }));
 6454                cx.notify();
 6455                if spawn_straight_away
 6456                    && let Some(task) = editor.confirm_code_action(
 6457                        &ConfirmCodeAction { item_ix: Some(0) },
 6458                        window,
 6459                        cx,
 6460                    )
 6461                {
 6462                    return task;
 6463                }
 6464
 6465                Task::ready(Ok(()))
 6466            })
 6467        })
 6468        .detach_and_log_err(cx);
 6469    }
 6470
 6471    fn debug_scenarios(
 6472        &mut self,
 6473        resolved_tasks: &Option<ResolvedTasks>,
 6474        buffer: &Entity<Buffer>,
 6475        cx: &mut App,
 6476    ) -> Task<Vec<task::DebugScenario>> {
 6477        maybe!({
 6478            let project = self.project()?;
 6479            let dap_store = project.read(cx).dap_store();
 6480            let mut scenarios = vec![];
 6481            let resolved_tasks = resolved_tasks.as_ref()?;
 6482            let buffer = buffer.read(cx);
 6483            let language = buffer.language()?;
 6484            let file = buffer.file();
 6485            let debug_adapter = language_settings(language.name().into(), file, cx)
 6486                .debuggers
 6487                .first()
 6488                .map(SharedString::from)
 6489                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6490
 6491            dap_store.update(cx, |dap_store, cx| {
 6492                for (_, task) in &resolved_tasks.templates {
 6493                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6494                        task.original_task().clone(),
 6495                        debug_adapter.clone().into(),
 6496                        task.display_label().to_owned().into(),
 6497                        cx,
 6498                    );
 6499                    scenarios.push(maybe_scenario);
 6500                }
 6501            });
 6502            Some(cx.background_spawn(async move {
 6503                futures::future::join_all(scenarios)
 6504                    .await
 6505                    .into_iter()
 6506                    .flatten()
 6507                    .collect::<Vec<_>>()
 6508            }))
 6509        })
 6510        .unwrap_or_else(|| Task::ready(vec![]))
 6511    }
 6512
 6513    fn code_actions(
 6514        &mut self,
 6515        buffer_row: u32,
 6516        window: &mut Window,
 6517        cx: &mut Context<Self>,
 6518    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6519        let mut task = self.code_actions_task.take();
 6520        cx.spawn_in(window, async move |editor, cx| {
 6521            while let Some(prev_task) = task {
 6522                prev_task.await.log_err();
 6523                task = editor
 6524                    .update(cx, |this, _| this.code_actions_task.take())
 6525                    .ok()?;
 6526            }
 6527
 6528            editor
 6529                .update(cx, |editor, cx| {
 6530                    editor
 6531                        .available_code_actions
 6532                        .clone()
 6533                        .and_then(|(location, code_actions)| {
 6534                            let snapshot = location.buffer.read(cx).snapshot();
 6535                            let point_range = location.range.to_point(&snapshot);
 6536                            let point_range = point_range.start.row..=point_range.end.row;
 6537                            if point_range.contains(&buffer_row) {
 6538                                Some(code_actions)
 6539                            } else {
 6540                                None
 6541                            }
 6542                        })
 6543                })
 6544                .ok()
 6545                .flatten()
 6546        })
 6547    }
 6548
 6549    pub fn confirm_code_action(
 6550        &mut self,
 6551        action: &ConfirmCodeAction,
 6552        window: &mut Window,
 6553        cx: &mut Context<Self>,
 6554    ) -> Option<Task<Result<()>>> {
 6555        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6556
 6557        let actions_menu =
 6558            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6559                menu
 6560            } else {
 6561                return None;
 6562            };
 6563
 6564        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6565        let action = actions_menu.actions.get(action_ix)?;
 6566        let title = action.label();
 6567        let buffer = actions_menu.buffer;
 6568        let workspace = self.workspace()?;
 6569
 6570        match action {
 6571            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6572                workspace.update(cx, |workspace, cx| {
 6573                    workspace.schedule_resolved_task(
 6574                        task_source_kind,
 6575                        resolved_task,
 6576                        false,
 6577                        window,
 6578                        cx,
 6579                    );
 6580
 6581                    Some(Task::ready(Ok(())))
 6582                })
 6583            }
 6584            CodeActionsItem::CodeAction {
 6585                excerpt_id,
 6586                action,
 6587                provider,
 6588            } => {
 6589                let apply_code_action =
 6590                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6591                let workspace = workspace.downgrade();
 6592                Some(cx.spawn_in(window, async move |editor, cx| {
 6593                    let project_transaction = apply_code_action.await?;
 6594                    Self::open_project_transaction(
 6595                        &editor,
 6596                        workspace,
 6597                        project_transaction,
 6598                        title,
 6599                        cx,
 6600                    )
 6601                    .await
 6602                }))
 6603            }
 6604            CodeActionsItem::DebugScenario(scenario) => {
 6605                let context = actions_menu.actions.context;
 6606
 6607                workspace.update(cx, |workspace, cx| {
 6608                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6609                    workspace.start_debug_session(
 6610                        scenario,
 6611                        context,
 6612                        Some(buffer),
 6613                        None,
 6614                        window,
 6615                        cx,
 6616                    );
 6617                });
 6618                Some(Task::ready(Ok(())))
 6619            }
 6620        }
 6621    }
 6622
 6623    pub async fn open_project_transaction(
 6624        editor: &WeakEntity<Editor>,
 6625        workspace: WeakEntity<Workspace>,
 6626        transaction: ProjectTransaction,
 6627        title: String,
 6628        cx: &mut AsyncWindowContext,
 6629    ) -> Result<()> {
 6630        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6631        cx.update(|_, cx| {
 6632            entries.sort_unstable_by_key(|(buffer, _)| {
 6633                buffer.read(cx).file().map(|f| f.path().clone())
 6634            });
 6635        })?;
 6636        if entries.is_empty() {
 6637            return Ok(());
 6638        }
 6639
 6640        // If the project transaction's edits are all contained within this editor, then
 6641        // avoid opening a new editor to display them.
 6642
 6643        if let [(buffer, transaction)] = &*entries {
 6644            let excerpt = editor.update(cx, |editor, cx| {
 6645                editor
 6646                    .buffer()
 6647                    .read(cx)
 6648                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6649            })?;
 6650            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6651                && excerpted_buffer == *buffer
 6652            {
 6653                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6654                    let excerpt_range = excerpt_range.to_offset(buffer);
 6655                    buffer
 6656                        .edited_ranges_for_transaction::<usize>(transaction)
 6657                        .all(|range| {
 6658                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6659                        })
 6660                })?;
 6661
 6662                if all_edits_within_excerpt {
 6663                    return Ok(());
 6664                }
 6665            }
 6666        }
 6667
 6668        let mut ranges_to_highlight = Vec::new();
 6669        let excerpt_buffer = cx.new(|cx| {
 6670            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6671            for (buffer_handle, transaction) in &entries {
 6672                let edited_ranges = buffer_handle
 6673                    .read(cx)
 6674                    .edited_ranges_for_transaction::<Point>(transaction)
 6675                    .collect::<Vec<_>>();
 6676                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6677                    PathKey::for_buffer(buffer_handle, cx),
 6678                    buffer_handle.clone(),
 6679                    edited_ranges,
 6680                    multibuffer_context_lines(cx),
 6681                    cx,
 6682                );
 6683
 6684                ranges_to_highlight.extend(ranges);
 6685            }
 6686            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6687            multibuffer
 6688        })?;
 6689
 6690        workspace.update_in(cx, |workspace, window, cx| {
 6691            let project = workspace.project().clone();
 6692            let editor =
 6693                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6694            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6695            editor.update(cx, |editor, cx| {
 6696                editor.highlight_background::<Self>(
 6697                    &ranges_to_highlight,
 6698                    |_, theme| theme.colors().editor_highlighted_line_background,
 6699                    cx,
 6700                );
 6701            });
 6702        })?;
 6703
 6704        Ok(())
 6705    }
 6706
 6707    pub fn clear_code_action_providers(&mut self) {
 6708        self.code_action_providers.clear();
 6709        self.available_code_actions.take();
 6710    }
 6711
 6712    pub fn add_code_action_provider(
 6713        &mut self,
 6714        provider: Rc<dyn CodeActionProvider>,
 6715        window: &mut Window,
 6716        cx: &mut Context<Self>,
 6717    ) {
 6718        if self
 6719            .code_action_providers
 6720            .iter()
 6721            .any(|existing_provider| existing_provider.id() == provider.id())
 6722        {
 6723            return;
 6724        }
 6725
 6726        self.code_action_providers.push(provider);
 6727        self.refresh_code_actions(window, cx);
 6728    }
 6729
 6730    pub fn remove_code_action_provider(
 6731        &mut self,
 6732        id: Arc<str>,
 6733        window: &mut Window,
 6734        cx: &mut Context<Self>,
 6735    ) {
 6736        self.code_action_providers
 6737            .retain(|provider| provider.id() != id);
 6738        self.refresh_code_actions(window, cx);
 6739    }
 6740
 6741    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6742        !self.code_action_providers.is_empty()
 6743            && EditorSettings::get_global(cx).toolbar.code_actions
 6744    }
 6745
 6746    pub fn has_available_code_actions(&self) -> bool {
 6747        self.available_code_actions
 6748            .as_ref()
 6749            .is_some_and(|(_, actions)| !actions.is_empty())
 6750    }
 6751
 6752    fn render_inline_code_actions(
 6753        &self,
 6754        icon_size: ui::IconSize,
 6755        display_row: DisplayRow,
 6756        is_active: bool,
 6757        cx: &mut Context<Self>,
 6758    ) -> AnyElement {
 6759        let show_tooltip = !self.context_menu_visible();
 6760        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6761            .icon_size(icon_size)
 6762            .shape(ui::IconButtonShape::Square)
 6763            .icon_color(ui::Color::Hidden)
 6764            .toggle_state(is_active)
 6765            .when(show_tooltip, |this| {
 6766                this.tooltip({
 6767                    let focus_handle = self.focus_handle.clone();
 6768                    move |_window, cx| {
 6769                        Tooltip::for_action_in(
 6770                            "Toggle Code Actions",
 6771                            &ToggleCodeActions {
 6772                                deployed_from: None,
 6773                                quick_launch: false,
 6774                            },
 6775                            &focus_handle,
 6776                            cx,
 6777                        )
 6778                    }
 6779                })
 6780            })
 6781            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6782                window.focus(&editor.focus_handle(cx));
 6783                editor.toggle_code_actions(
 6784                    &crate::actions::ToggleCodeActions {
 6785                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6786                            display_row,
 6787                        )),
 6788                        quick_launch: false,
 6789                    },
 6790                    window,
 6791                    cx,
 6792                );
 6793            }))
 6794            .into_any_element()
 6795    }
 6796
 6797    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6798        &self.context_menu
 6799    }
 6800
 6801    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6802        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6803            cx.background_executor()
 6804                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6805                .await;
 6806
 6807            let (start_buffer, start, _, end, newest_selection) = this
 6808                .update(cx, |this, cx| {
 6809                    let newest_selection = this.selections.newest_anchor().clone();
 6810                    if newest_selection.head().diff_base_anchor.is_some() {
 6811                        return None;
 6812                    }
 6813                    let display_snapshot = this.display_snapshot(cx);
 6814                    let newest_selection_adjusted =
 6815                        this.selections.newest_adjusted(&display_snapshot);
 6816                    let buffer = this.buffer.read(cx);
 6817
 6818                    let (start_buffer, start) =
 6819                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6820                    let (end_buffer, end) =
 6821                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6822
 6823                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6824                })?
 6825                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6826                .context(
 6827                    "Expected selection to lie in a single buffer when refreshing code actions",
 6828                )?;
 6829            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6830                let providers = this.code_action_providers.clone();
 6831                let tasks = this
 6832                    .code_action_providers
 6833                    .iter()
 6834                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6835                    .collect::<Vec<_>>();
 6836                (providers, tasks)
 6837            })?;
 6838
 6839            let mut actions = Vec::new();
 6840            for (provider, provider_actions) in
 6841                providers.into_iter().zip(future::join_all(tasks).await)
 6842            {
 6843                if let Some(provider_actions) = provider_actions.log_err() {
 6844                    actions.extend(provider_actions.into_iter().map(|action| {
 6845                        AvailableCodeAction {
 6846                            excerpt_id: newest_selection.start.excerpt_id,
 6847                            action,
 6848                            provider: provider.clone(),
 6849                        }
 6850                    }));
 6851                }
 6852            }
 6853
 6854            this.update(cx, |this, cx| {
 6855                this.available_code_actions = if actions.is_empty() {
 6856                    None
 6857                } else {
 6858                    Some((
 6859                        Location {
 6860                            buffer: start_buffer,
 6861                            range: start..end,
 6862                        },
 6863                        actions.into(),
 6864                    ))
 6865                };
 6866                cx.notify();
 6867            })
 6868        }));
 6869    }
 6870
 6871    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6872        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6873            self.show_git_blame_inline = false;
 6874
 6875            self.show_git_blame_inline_delay_task =
 6876                Some(cx.spawn_in(window, async move |this, cx| {
 6877                    cx.background_executor().timer(delay).await;
 6878
 6879                    this.update(cx, |this, cx| {
 6880                        this.show_git_blame_inline = true;
 6881                        cx.notify();
 6882                    })
 6883                    .log_err();
 6884                }));
 6885        }
 6886    }
 6887
 6888    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6889        let snapshot = self.snapshot(window, cx);
 6890        let cursor = self
 6891            .selections
 6892            .newest::<Point>(&snapshot.display_snapshot)
 6893            .head();
 6894        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6895        else {
 6896            return;
 6897        };
 6898
 6899        if self.blame.is_none() {
 6900            self.start_git_blame(true, window, cx);
 6901        }
 6902        let Some(blame) = self.blame.as_ref() else {
 6903            return;
 6904        };
 6905
 6906        let row_info = RowInfo {
 6907            buffer_id: Some(buffer.remote_id()),
 6908            buffer_row: Some(point.row),
 6909            ..Default::default()
 6910        };
 6911        let Some((buffer, blame_entry)) = blame
 6912            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6913            .flatten()
 6914        else {
 6915            return;
 6916        };
 6917
 6918        let anchor = self.selections.newest_anchor().head();
 6919        let position = self.to_pixel_point(anchor, &snapshot, window, cx);
 6920        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6921            self.show_blame_popover(
 6922                buffer,
 6923                &blame_entry,
 6924                position + last_bounds.origin,
 6925                true,
 6926                cx,
 6927            );
 6928        };
 6929    }
 6930
 6931    fn show_blame_popover(
 6932        &mut self,
 6933        buffer: BufferId,
 6934        blame_entry: &BlameEntry,
 6935        position: gpui::Point<Pixels>,
 6936        ignore_timeout: bool,
 6937        cx: &mut Context<Self>,
 6938    ) {
 6939        if let Some(state) = &mut self.inline_blame_popover {
 6940            state.hide_task.take();
 6941        } else {
 6942            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6943            let blame_entry = blame_entry.clone();
 6944            let show_task = cx.spawn(async move |editor, cx| {
 6945                if !ignore_timeout {
 6946                    cx.background_executor()
 6947                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6948                        .await;
 6949                }
 6950                editor
 6951                    .update(cx, |editor, cx| {
 6952                        editor.inline_blame_popover_show_task.take();
 6953                        let Some(blame) = editor.blame.as_ref() else {
 6954                            return;
 6955                        };
 6956                        let blame = blame.read(cx);
 6957                        let details = blame.details_for_entry(buffer, &blame_entry);
 6958                        let markdown = cx.new(|cx| {
 6959                            Markdown::new(
 6960                                details
 6961                                    .as_ref()
 6962                                    .map(|message| message.message.clone())
 6963                                    .unwrap_or_default(),
 6964                                None,
 6965                                None,
 6966                                cx,
 6967                            )
 6968                        });
 6969                        editor.inline_blame_popover = Some(InlineBlamePopover {
 6970                            position,
 6971                            hide_task: None,
 6972                            popover_bounds: None,
 6973                            popover_state: InlineBlamePopoverState {
 6974                                scroll_handle: ScrollHandle::new(),
 6975                                commit_message: details,
 6976                                markdown,
 6977                            },
 6978                            keyboard_grace: ignore_timeout,
 6979                        });
 6980                        cx.notify();
 6981                    })
 6982                    .ok();
 6983            });
 6984            self.inline_blame_popover_show_task = Some(show_task);
 6985        }
 6986    }
 6987
 6988    pub fn has_mouse_context_menu(&self) -> bool {
 6989        self.mouse_context_menu.is_some()
 6990    }
 6991
 6992    pub fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 6993        self.inline_blame_popover_show_task.take();
 6994        if let Some(state) = &mut self.inline_blame_popover {
 6995            let hide_task = cx.spawn(async move |editor, cx| {
 6996                if !ignore_timeout {
 6997                    cx.background_executor()
 6998                        .timer(std::time::Duration::from_millis(100))
 6999                        .await;
 7000                }
 7001                editor
 7002                    .update(cx, |editor, cx| {
 7003                        editor.inline_blame_popover.take();
 7004                        cx.notify();
 7005                    })
 7006                    .ok();
 7007            });
 7008            state.hide_task = Some(hide_task);
 7009            true
 7010        } else {
 7011            false
 7012        }
 7013    }
 7014
 7015    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 7016        if self.pending_rename.is_some() {
 7017            return None;
 7018        }
 7019
 7020        let provider = self.semantics_provider.clone()?;
 7021        let buffer = self.buffer.read(cx);
 7022        let newest_selection = self.selections.newest_anchor().clone();
 7023        let cursor_position = newest_selection.head();
 7024        let (cursor_buffer, cursor_buffer_position) =
 7025            buffer.text_anchor_for_position(cursor_position, cx)?;
 7026        let (tail_buffer, tail_buffer_position) =
 7027            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 7028        if cursor_buffer != tail_buffer {
 7029            return None;
 7030        }
 7031
 7032        let snapshot = cursor_buffer.read(cx).snapshot();
 7033        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 7034        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 7035        if start_word_range != end_word_range {
 7036            self.document_highlights_task.take();
 7037            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 7038            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 7039            return None;
 7040        }
 7041
 7042        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 7043        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 7044            cx.background_executor()
 7045                .timer(Duration::from_millis(debounce))
 7046                .await;
 7047
 7048            let highlights = if let Some(highlights) = cx
 7049                .update(|cx| {
 7050                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 7051                })
 7052                .ok()
 7053                .flatten()
 7054            {
 7055                highlights.await.log_err()
 7056            } else {
 7057                None
 7058            };
 7059
 7060            if let Some(highlights) = highlights {
 7061                this.update(cx, |this, cx| {
 7062                    if this.pending_rename.is_some() {
 7063                        return;
 7064                    }
 7065
 7066                    let buffer = this.buffer.read(cx);
 7067                    if buffer
 7068                        .text_anchor_for_position(cursor_position, cx)
 7069                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 7070                    {
 7071                        return;
 7072                    }
 7073
 7074                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 7075                    let mut write_ranges = Vec::new();
 7076                    let mut read_ranges = Vec::new();
 7077                    for highlight in highlights {
 7078                        let buffer_id = cursor_buffer.read(cx).remote_id();
 7079                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 7080                        {
 7081                            let start = highlight
 7082                                .range
 7083                                .start
 7084                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 7085                            let end = highlight
 7086                                .range
 7087                                .end
 7088                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 7089                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 7090                                continue;
 7091                            }
 7092
 7093                            let range = Anchor::range_in_buffer(excerpt_id, *start..*end);
 7094                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 7095                                write_ranges.push(range);
 7096                            } else {
 7097                                read_ranges.push(range);
 7098                            }
 7099                        }
 7100                    }
 7101
 7102                    this.highlight_background::<DocumentHighlightRead>(
 7103                        &read_ranges,
 7104                        |_, theme| theme.colors().editor_document_highlight_read_background,
 7105                        cx,
 7106                    );
 7107                    this.highlight_background::<DocumentHighlightWrite>(
 7108                        &write_ranges,
 7109                        |_, theme| theme.colors().editor_document_highlight_write_background,
 7110                        cx,
 7111                    );
 7112                    cx.notify();
 7113                })
 7114                .log_err();
 7115            }
 7116        }));
 7117        None
 7118    }
 7119
 7120    fn prepare_highlight_query_from_selection(
 7121        &mut self,
 7122        window: &Window,
 7123        cx: &mut Context<Editor>,
 7124    ) -> Option<(String, Range<Anchor>)> {
 7125        if matches!(self.mode, EditorMode::SingleLine) {
 7126            return None;
 7127        }
 7128        if !EditorSettings::get_global(cx).selection_highlight {
 7129            return None;
 7130        }
 7131        if self.selections.count() != 1 || self.selections.line_mode() {
 7132            return None;
 7133        }
 7134        let snapshot = self.snapshot(window, cx);
 7135        let selection = self.selections.newest::<Point>(&snapshot);
 7136        // If the selection spans multiple rows OR it is empty
 7137        if selection.start.row != selection.end.row
 7138            || selection.start.column == selection.end.column
 7139        {
 7140            return None;
 7141        }
 7142        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 7143        let query = snapshot
 7144            .buffer_snapshot()
 7145            .text_for_range(selection_anchor_range.clone())
 7146            .collect::<String>();
 7147        if query.trim().is_empty() {
 7148            return None;
 7149        }
 7150        Some((query, selection_anchor_range))
 7151    }
 7152
 7153    #[ztracing::instrument(skip_all)]
 7154    fn update_selection_occurrence_highlights(
 7155        &mut self,
 7156        query_text: String,
 7157        query_range: Range<Anchor>,
 7158        multi_buffer_range_to_query: Range<Point>,
 7159        use_debounce: bool,
 7160        window: &mut Window,
 7161        cx: &mut Context<Editor>,
 7162    ) -> Task<()> {
 7163        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7164        cx.spawn_in(window, async move |editor, cx| {
 7165            if use_debounce {
 7166                cx.background_executor()
 7167                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 7168                    .await;
 7169            }
 7170            let match_task = cx.background_spawn(async move {
 7171                let buffer_ranges = multi_buffer_snapshot
 7172                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 7173                    .into_iter()
 7174                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 7175                let mut match_ranges = Vec::new();
 7176                let Ok(regex) = project::search::SearchQuery::text(
 7177                    query_text.clone(),
 7178                    false,
 7179                    false,
 7180                    false,
 7181                    Default::default(),
 7182                    Default::default(),
 7183                    false,
 7184                    None,
 7185                ) else {
 7186                    return Vec::default();
 7187                };
 7188                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7189                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7190                    match_ranges.extend(
 7191                        regex
 7192                            .search(
 7193                                buffer_snapshot,
 7194                                Some(search_range.start.0..search_range.end.0),
 7195                            )
 7196                            .await
 7197                            .into_iter()
 7198                            .filter_map(|match_range| {
 7199                                let match_start = buffer_snapshot
 7200                                    .anchor_after(search_range.start + match_range.start);
 7201                                let match_end = buffer_snapshot
 7202                                    .anchor_before(search_range.start + match_range.end);
 7203                                let match_anchor_range =
 7204                                    Anchor::range_in_buffer(excerpt_id, match_start..match_end);
 7205                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7206                            }),
 7207                    );
 7208                }
 7209                match_ranges
 7210            });
 7211            let match_ranges = match_task.await;
 7212            editor
 7213                .update_in(cx, |editor, _, cx| {
 7214                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7215                    if !match_ranges.is_empty() {
 7216                        editor.highlight_background::<SelectedTextHighlight>(
 7217                            &match_ranges,
 7218                            |_, theme| theme.colors().editor_document_highlight_bracket_background,
 7219                            cx,
 7220                        )
 7221                    }
 7222                })
 7223                .log_err();
 7224        })
 7225    }
 7226
 7227    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7228        struct NewlineFold;
 7229        let type_id = std::any::TypeId::of::<NewlineFold>();
 7230        if !self.mode.is_single_line() {
 7231            return;
 7232        }
 7233        let snapshot = self.snapshot(window, cx);
 7234        if snapshot.buffer_snapshot().max_point().row == 0 {
 7235            return;
 7236        }
 7237        let task = cx.background_spawn(async move {
 7238            let new_newlines = snapshot
 7239                .buffer_chars_at(MultiBufferOffset(0))
 7240                .filter_map(|(c, i)| {
 7241                    if c == '\n' {
 7242                        Some(
 7243                            snapshot.buffer_snapshot().anchor_after(i)
 7244                                ..snapshot.buffer_snapshot().anchor_before(i + 1usize),
 7245                        )
 7246                    } else {
 7247                        None
 7248                    }
 7249                })
 7250                .collect::<Vec<_>>();
 7251            let existing_newlines = snapshot
 7252                .folds_in_range(MultiBufferOffset(0)..snapshot.buffer_snapshot().len())
 7253                .filter_map(|fold| {
 7254                    if fold.placeholder.type_tag == Some(type_id) {
 7255                        Some(fold.range.start..fold.range.end)
 7256                    } else {
 7257                        None
 7258                    }
 7259                })
 7260                .collect::<Vec<_>>();
 7261
 7262            (new_newlines, existing_newlines)
 7263        });
 7264        self.folding_newlines = cx.spawn(async move |this, cx| {
 7265            let (new_newlines, existing_newlines) = task.await;
 7266            if new_newlines == existing_newlines {
 7267                return;
 7268            }
 7269            let placeholder = FoldPlaceholder {
 7270                render: Arc::new(move |_, _, cx| {
 7271                    div()
 7272                        .bg(cx.theme().status().hint_background)
 7273                        .border_b_1()
 7274                        .size_full()
 7275                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7276                        .border_color(cx.theme().status().hint)
 7277                        .child("\\n")
 7278                        .into_any()
 7279                }),
 7280                constrain_width: false,
 7281                merge_adjacent: false,
 7282                type_tag: Some(type_id),
 7283            };
 7284            let creases = new_newlines
 7285                .into_iter()
 7286                .map(|range| Crease::simple(range, placeholder.clone()))
 7287                .collect();
 7288            this.update(cx, |this, cx| {
 7289                this.display_map.update(cx, |display_map, cx| {
 7290                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7291                    display_map.fold(creases, cx);
 7292                });
 7293            })
 7294            .ok();
 7295        });
 7296    }
 7297
 7298    #[ztracing::instrument(skip_all)]
 7299    fn refresh_selected_text_highlights(
 7300        &mut self,
 7301        on_buffer_edit: bool,
 7302        window: &mut Window,
 7303        cx: &mut Context<Editor>,
 7304    ) {
 7305        let Some((query_text, query_range)) =
 7306            self.prepare_highlight_query_from_selection(window, cx)
 7307        else {
 7308            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7309            self.quick_selection_highlight_task.take();
 7310            self.debounced_selection_highlight_task.take();
 7311            return;
 7312        };
 7313        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7314        if on_buffer_edit
 7315            || self
 7316                .quick_selection_highlight_task
 7317                .as_ref()
 7318                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7319        {
 7320            let multi_buffer_visible_start = self
 7321                .scroll_manager
 7322                .anchor()
 7323                .anchor
 7324                .to_point(&multi_buffer_snapshot);
 7325            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7326                multi_buffer_visible_start
 7327                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7328                Bias::Left,
 7329            );
 7330            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7331            self.quick_selection_highlight_task = Some((
 7332                query_range.clone(),
 7333                self.update_selection_occurrence_highlights(
 7334                    query_text.clone(),
 7335                    query_range.clone(),
 7336                    multi_buffer_visible_range,
 7337                    false,
 7338                    window,
 7339                    cx,
 7340                ),
 7341            ));
 7342        }
 7343        if on_buffer_edit
 7344            || self
 7345                .debounced_selection_highlight_task
 7346                .as_ref()
 7347                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7348        {
 7349            let multi_buffer_start = multi_buffer_snapshot
 7350                .anchor_before(MultiBufferOffset(0))
 7351                .to_point(&multi_buffer_snapshot);
 7352            let multi_buffer_end = multi_buffer_snapshot
 7353                .anchor_after(multi_buffer_snapshot.len())
 7354                .to_point(&multi_buffer_snapshot);
 7355            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7356            self.debounced_selection_highlight_task = Some((
 7357                query_range.clone(),
 7358                self.update_selection_occurrence_highlights(
 7359                    query_text,
 7360                    query_range,
 7361                    multi_buffer_full_range,
 7362                    true,
 7363                    window,
 7364                    cx,
 7365                ),
 7366            ));
 7367        }
 7368    }
 7369
 7370    pub fn refresh_edit_prediction(
 7371        &mut self,
 7372        debounce: bool,
 7373        user_requested: bool,
 7374        window: &mut Window,
 7375        cx: &mut Context<Self>,
 7376    ) -> Option<()> {
 7377        if DisableAiSettings::get_global(cx).disable_ai {
 7378            return None;
 7379        }
 7380
 7381        let provider = self.edit_prediction_provider()?;
 7382        let cursor = self.selections.newest_anchor().head();
 7383        let (buffer, cursor_buffer_position) =
 7384            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7385
 7386        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7387            self.discard_edit_prediction(false, cx);
 7388            return None;
 7389        }
 7390
 7391        self.update_visible_edit_prediction(window, cx);
 7392
 7393        if !user_requested
 7394            && (!self.should_show_edit_predictions()
 7395                || !self.is_focused(window)
 7396                || buffer.read(cx).is_empty())
 7397        {
 7398            self.discard_edit_prediction(false, cx);
 7399            return None;
 7400        }
 7401
 7402        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7403        Some(())
 7404    }
 7405
 7406    fn show_edit_predictions_in_menu(&self) -> bool {
 7407        match self.edit_prediction_settings {
 7408            EditPredictionSettings::Disabled => false,
 7409            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7410        }
 7411    }
 7412
 7413    pub fn edit_predictions_enabled(&self) -> bool {
 7414        match self.edit_prediction_settings {
 7415            EditPredictionSettings::Disabled => false,
 7416            EditPredictionSettings::Enabled { .. } => true,
 7417        }
 7418    }
 7419
 7420    fn edit_prediction_requires_modifier(&self) -> bool {
 7421        match self.edit_prediction_settings {
 7422            EditPredictionSettings::Disabled => false,
 7423            EditPredictionSettings::Enabled {
 7424                preview_requires_modifier,
 7425                ..
 7426            } => preview_requires_modifier,
 7427        }
 7428    }
 7429
 7430    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7431        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7432            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7433            self.discard_edit_prediction(false, cx);
 7434        } else {
 7435            let selection = self.selections.newest_anchor();
 7436            let cursor = selection.head();
 7437
 7438            if let Some((buffer, cursor_buffer_position)) =
 7439                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7440            {
 7441                self.edit_prediction_settings =
 7442                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7443            }
 7444        }
 7445    }
 7446
 7447    fn edit_prediction_settings_at_position(
 7448        &self,
 7449        buffer: &Entity<Buffer>,
 7450        buffer_position: language::Anchor,
 7451        cx: &App,
 7452    ) -> EditPredictionSettings {
 7453        if !self.mode.is_full()
 7454            || !self.show_edit_predictions_override.unwrap_or(true)
 7455            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7456        {
 7457            return EditPredictionSettings::Disabled;
 7458        }
 7459
 7460        let buffer = buffer.read(cx);
 7461
 7462        let file = buffer.file();
 7463
 7464        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7465            return EditPredictionSettings::Disabled;
 7466        };
 7467
 7468        let by_provider = matches!(
 7469            self.menu_edit_predictions_policy,
 7470            MenuEditPredictionsPolicy::ByProvider
 7471        );
 7472
 7473        let show_in_menu = by_provider
 7474            && self
 7475                .edit_prediction_provider
 7476                .as_ref()
 7477                .is_some_and(|provider| provider.provider.show_predictions_in_menu());
 7478
 7479        let preview_requires_modifier =
 7480            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7481
 7482        EditPredictionSettings::Enabled {
 7483            show_in_menu,
 7484            preview_requires_modifier,
 7485        }
 7486    }
 7487
 7488    fn should_show_edit_predictions(&self) -> bool {
 7489        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7490    }
 7491
 7492    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7493        matches!(
 7494            self.edit_prediction_preview,
 7495            EditPredictionPreview::Active { .. }
 7496        )
 7497    }
 7498
 7499    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7500        let cursor = self.selections.newest_anchor().head();
 7501        if let Some((buffer, cursor_position)) =
 7502            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7503        {
 7504            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7505        } else {
 7506            false
 7507        }
 7508    }
 7509
 7510    pub fn supports_minimap(&self, cx: &App) -> bool {
 7511        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7512    }
 7513
 7514    fn edit_predictions_enabled_in_buffer(
 7515        &self,
 7516        buffer: &Entity<Buffer>,
 7517        buffer_position: language::Anchor,
 7518        cx: &App,
 7519    ) -> bool {
 7520        maybe!({
 7521            if self.read_only(cx) {
 7522                return Some(false);
 7523            }
 7524            let provider = self.edit_prediction_provider()?;
 7525            if !provider.is_enabled(buffer, buffer_position, cx) {
 7526                return Some(false);
 7527            }
 7528            let buffer = buffer.read(cx);
 7529            let Some(file) = buffer.file() else {
 7530                return Some(true);
 7531            };
 7532            let settings = all_language_settings(Some(file), cx);
 7533            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7534        })
 7535        .unwrap_or(false)
 7536    }
 7537
 7538    fn cycle_edit_prediction(
 7539        &mut self,
 7540        direction: Direction,
 7541        window: &mut Window,
 7542        cx: &mut Context<Self>,
 7543    ) -> Option<()> {
 7544        let provider = self.edit_prediction_provider()?;
 7545        let cursor = self.selections.newest_anchor().head();
 7546        let (buffer, cursor_buffer_position) =
 7547            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7548        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7549            return None;
 7550        }
 7551
 7552        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7553        self.update_visible_edit_prediction(window, cx);
 7554
 7555        Some(())
 7556    }
 7557
 7558    pub fn show_edit_prediction(
 7559        &mut self,
 7560        _: &ShowEditPrediction,
 7561        window: &mut Window,
 7562        cx: &mut Context<Self>,
 7563    ) {
 7564        if !self.has_active_edit_prediction() {
 7565            self.refresh_edit_prediction(false, true, window, cx);
 7566            return;
 7567        }
 7568
 7569        self.update_visible_edit_prediction(window, cx);
 7570    }
 7571
 7572    pub fn display_cursor_names(
 7573        &mut self,
 7574        _: &DisplayCursorNames,
 7575        window: &mut Window,
 7576        cx: &mut Context<Self>,
 7577    ) {
 7578        self.show_cursor_names(window, cx);
 7579    }
 7580
 7581    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7582        self.show_cursor_names = true;
 7583        cx.notify();
 7584        cx.spawn_in(window, async move |this, cx| {
 7585            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7586            this.update(cx, |this, cx| {
 7587                this.show_cursor_names = false;
 7588                cx.notify()
 7589            })
 7590            .ok()
 7591        })
 7592        .detach();
 7593    }
 7594
 7595    pub fn next_edit_prediction(
 7596        &mut self,
 7597        _: &NextEditPrediction,
 7598        window: &mut Window,
 7599        cx: &mut Context<Self>,
 7600    ) {
 7601        if self.has_active_edit_prediction() {
 7602            self.cycle_edit_prediction(Direction::Next, window, cx);
 7603        } else {
 7604            let is_copilot_disabled = self
 7605                .refresh_edit_prediction(false, true, window, cx)
 7606                .is_none();
 7607            if is_copilot_disabled {
 7608                cx.propagate();
 7609            }
 7610        }
 7611    }
 7612
 7613    pub fn previous_edit_prediction(
 7614        &mut self,
 7615        _: &PreviousEditPrediction,
 7616        window: &mut Window,
 7617        cx: &mut Context<Self>,
 7618    ) {
 7619        if self.has_active_edit_prediction() {
 7620            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7621        } else {
 7622            let is_copilot_disabled = self
 7623                .refresh_edit_prediction(false, true, window, cx)
 7624                .is_none();
 7625            if is_copilot_disabled {
 7626                cx.propagate();
 7627            }
 7628        }
 7629    }
 7630
 7631    pub fn accept_partial_edit_prediction(
 7632        &mut self,
 7633        granularity: EditPredictionGranularity,
 7634        window: &mut Window,
 7635        cx: &mut Context<Self>,
 7636    ) {
 7637        if self.show_edit_predictions_in_menu() {
 7638            self.hide_context_menu(window, cx);
 7639        }
 7640
 7641        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7642            return;
 7643        };
 7644
 7645        if !matches!(granularity, EditPredictionGranularity::Full) && self.selections.count() != 1 {
 7646            return;
 7647        }
 7648
 7649        match &active_edit_prediction.completion {
 7650            EditPrediction::MoveWithin { target, .. } => {
 7651                let target = *target;
 7652
 7653                if matches!(granularity, EditPredictionGranularity::Full) {
 7654                    if let Some(position_map) = &self.last_position_map {
 7655                        let target_row = target.to_display_point(&position_map.snapshot).row();
 7656                        let is_visible = position_map.visible_row_range.contains(&target_row);
 7657
 7658                        if is_visible || !self.edit_prediction_requires_modifier() {
 7659                            self.unfold_ranges(&[target..target], true, false, cx);
 7660                            self.change_selections(
 7661                                SelectionEffects::scroll(Autoscroll::newest()),
 7662                                window,
 7663                                cx,
 7664                                |selections| {
 7665                                    selections.select_anchor_ranges([target..target]);
 7666                                },
 7667                            );
 7668                            self.clear_row_highlights::<EditPredictionPreview>();
 7669                            self.edit_prediction_preview
 7670                                .set_previous_scroll_position(None);
 7671                        } else {
 7672                            // Highlight and request scroll
 7673                            self.edit_prediction_preview
 7674                                .set_previous_scroll_position(Some(
 7675                                    position_map.snapshot.scroll_anchor,
 7676                                ));
 7677                            self.highlight_rows::<EditPredictionPreview>(
 7678                                target..target,
 7679                                cx.theme().colors().editor_highlighted_line_background,
 7680                                RowHighlightOptions {
 7681                                    autoscroll: true,
 7682                                    ..Default::default()
 7683                                },
 7684                                cx,
 7685                            );
 7686                            self.request_autoscroll(Autoscroll::fit(), cx);
 7687                        }
 7688                    }
 7689                } else {
 7690                    self.change_selections(
 7691                        SelectionEffects::scroll(Autoscroll::newest()),
 7692                        window,
 7693                        cx,
 7694                        |selections| {
 7695                            selections.select_anchor_ranges([target..target]);
 7696                        },
 7697                    );
 7698                }
 7699            }
 7700            EditPrediction::MoveOutside { snapshot, target } => {
 7701                if let Some(workspace) = self.workspace() {
 7702                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7703                        .detach_and_log_err(cx);
 7704                }
 7705            }
 7706            EditPrediction::Edit { edits, .. } => {
 7707                self.report_edit_prediction_event(
 7708                    active_edit_prediction.completion_id.clone(),
 7709                    true,
 7710                    cx,
 7711                );
 7712
 7713                match granularity {
 7714                    EditPredictionGranularity::Full => {
 7715                        if let Some(provider) = self.edit_prediction_provider() {
 7716                            provider.accept(cx);
 7717                        }
 7718
 7719                        let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7720                        let snapshot = self.buffer.read(cx).snapshot(cx);
 7721                        let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7722
 7723                        self.buffer.update(cx, |buffer, cx| {
 7724                            buffer.edit(edits.iter().cloned(), None, cx)
 7725                        });
 7726
 7727                        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7728                            s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7729                        });
 7730
 7731                        let selections = self.selections.disjoint_anchors_arc();
 7732                        if let Some(transaction_id_now) =
 7733                            self.buffer.read(cx).last_transaction_id(cx)
 7734                        {
 7735                            if transaction_id_prev != Some(transaction_id_now) {
 7736                                self.selection_history
 7737                                    .insert_transaction(transaction_id_now, selections);
 7738                            }
 7739                        }
 7740
 7741                        self.update_visible_edit_prediction(window, cx);
 7742                        if self.active_edit_prediction.is_none() {
 7743                            self.refresh_edit_prediction(true, true, window, cx);
 7744                        }
 7745                        cx.notify();
 7746                    }
 7747                    _ => {
 7748                        let snapshot = self.buffer.read(cx).snapshot(cx);
 7749                        let cursor_offset = self
 7750                            .selections
 7751                            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 7752                            .head();
 7753
 7754                        let insertion = edits.iter().find_map(|(range, text)| {
 7755                            let range = range.to_offset(&snapshot);
 7756                            if range.is_empty() && range.start == cursor_offset {
 7757                                Some(text)
 7758                            } else {
 7759                                None
 7760                            }
 7761                        });
 7762
 7763                        if let Some(text) = insertion {
 7764                            let text_to_insert = match granularity {
 7765                                EditPredictionGranularity::Word => {
 7766                                    let mut partial = text
 7767                                        .chars()
 7768                                        .by_ref()
 7769                                        .take_while(|c| c.is_alphabetic())
 7770                                        .collect::<String>();
 7771                                    if partial.is_empty() {
 7772                                        partial = text
 7773                                            .chars()
 7774                                            .by_ref()
 7775                                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7776                                            .collect::<String>();
 7777                                    }
 7778                                    partial
 7779                                }
 7780                                EditPredictionGranularity::Line => {
 7781                                    if let Some(line) = text.split_inclusive('\n').next() {
 7782                                        line.to_string()
 7783                                    } else {
 7784                                        text.to_string()
 7785                                    }
 7786                                }
 7787                                EditPredictionGranularity::Full => unreachable!(),
 7788                            };
 7789
 7790                            cx.emit(EditorEvent::InputHandled {
 7791                                utf16_range_to_replace: None,
 7792                                text: text_to_insert.clone().into(),
 7793                            });
 7794
 7795                            self.insert_with_autoindent_mode(&text_to_insert, None, window, cx);
 7796                            self.refresh_edit_prediction(true, true, window, cx);
 7797                            cx.notify();
 7798                        } else {
 7799                            self.accept_partial_edit_prediction(
 7800                                EditPredictionGranularity::Full,
 7801                                window,
 7802                                cx,
 7803                            );
 7804                        }
 7805                    }
 7806                }
 7807            }
 7808        }
 7809
 7810        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7811    }
 7812
 7813    pub fn accept_next_word_edit_prediction(
 7814        &mut self,
 7815        _: &AcceptNextWordEditPrediction,
 7816        window: &mut Window,
 7817        cx: &mut Context<Self>,
 7818    ) {
 7819        self.accept_partial_edit_prediction(EditPredictionGranularity::Word, window, cx);
 7820    }
 7821
 7822    pub fn accept_next_line_edit_prediction(
 7823        &mut self,
 7824        _: &AcceptNextLineEditPrediction,
 7825        window: &mut Window,
 7826        cx: &mut Context<Self>,
 7827    ) {
 7828        self.accept_partial_edit_prediction(EditPredictionGranularity::Line, window, cx);
 7829    }
 7830
 7831    pub fn accept_edit_prediction(
 7832        &mut self,
 7833        _: &AcceptEditPrediction,
 7834        window: &mut Window,
 7835        cx: &mut Context<Self>,
 7836    ) {
 7837        self.accept_partial_edit_prediction(EditPredictionGranularity::Full, window, cx);
 7838    }
 7839
 7840    fn discard_edit_prediction(
 7841        &mut self,
 7842        should_report_edit_prediction_event: bool,
 7843        cx: &mut Context<Self>,
 7844    ) -> bool {
 7845        if should_report_edit_prediction_event {
 7846            let completion_id = self
 7847                .active_edit_prediction
 7848                .as_ref()
 7849                .and_then(|active_completion| active_completion.completion_id.clone());
 7850
 7851            self.report_edit_prediction_event(completion_id, false, cx);
 7852        }
 7853
 7854        if let Some(provider) = self.edit_prediction_provider() {
 7855            provider.discard(cx);
 7856        }
 7857
 7858        self.take_active_edit_prediction(cx)
 7859    }
 7860
 7861    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7862        let Some(provider) = self.edit_prediction_provider() else {
 7863            return;
 7864        };
 7865
 7866        let Some((_, buffer, _)) = self
 7867            .buffer
 7868            .read(cx)
 7869            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7870        else {
 7871            return;
 7872        };
 7873
 7874        let extension = buffer
 7875            .read(cx)
 7876            .file()
 7877            .and_then(|file| Some(file.path().extension()?.to_string()));
 7878
 7879        let event_type = match accepted {
 7880            true => "Edit Prediction Accepted",
 7881            false => "Edit Prediction Discarded",
 7882        };
 7883        telemetry::event!(
 7884            event_type,
 7885            provider = provider.name(),
 7886            prediction_id = id,
 7887            suggestion_accepted = accepted,
 7888            file_extension = extension,
 7889        );
 7890    }
 7891
 7892    fn open_editor_at_anchor(
 7893        snapshot: &language::BufferSnapshot,
 7894        target: language::Anchor,
 7895        workspace: &Entity<Workspace>,
 7896        window: &mut Window,
 7897        cx: &mut App,
 7898    ) -> Task<Result<()>> {
 7899        workspace.update(cx, |workspace, cx| {
 7900            let path = snapshot.file().map(|file| file.full_path(cx));
 7901            let Some(path) =
 7902                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7903            else {
 7904                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7905            };
 7906            let target = text::ToPoint::to_point(&target, snapshot);
 7907            let item = workspace.open_path(path, None, true, window, cx);
 7908            window.spawn(cx, async move |cx| {
 7909                let Some(editor) = item.await?.downcast::<Editor>() else {
 7910                    return Ok(());
 7911                };
 7912                editor
 7913                    .update_in(cx, |editor, window, cx| {
 7914                        editor.go_to_singleton_buffer_point(target, window, cx);
 7915                    })
 7916                    .ok();
 7917                anyhow::Ok(())
 7918            })
 7919        })
 7920    }
 7921
 7922    pub fn has_active_edit_prediction(&self) -> bool {
 7923        self.active_edit_prediction.is_some()
 7924    }
 7925
 7926    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7927        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7928            return false;
 7929        };
 7930
 7931        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7932        self.clear_highlights::<EditPredictionHighlight>(cx);
 7933        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7934        true
 7935    }
 7936
 7937    /// Returns true when we're displaying the edit prediction popover below the cursor
 7938    /// like we are not previewing and the LSP autocomplete menu is visible
 7939    /// or we are in `when_holding_modifier` mode.
 7940    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7941        if self.edit_prediction_preview_is_active()
 7942            || !self.show_edit_predictions_in_menu()
 7943            || !self.edit_predictions_enabled()
 7944        {
 7945            return false;
 7946        }
 7947
 7948        if self.has_visible_completions_menu() {
 7949            return true;
 7950        }
 7951
 7952        has_completion && self.edit_prediction_requires_modifier()
 7953    }
 7954
 7955    fn handle_modifiers_changed(
 7956        &mut self,
 7957        modifiers: Modifiers,
 7958        position_map: &PositionMap,
 7959        window: &mut Window,
 7960        cx: &mut Context<Self>,
 7961    ) {
 7962        // Ensure that the edit prediction preview is updated, even when not
 7963        // enabled, if there's an active edit prediction preview.
 7964        if self.show_edit_predictions_in_menu()
 7965            || matches!(
 7966                self.edit_prediction_preview,
 7967                EditPredictionPreview::Active { .. }
 7968            )
 7969        {
 7970            self.update_edit_prediction_preview(&modifiers, window, cx);
 7971        }
 7972
 7973        self.update_selection_mode(&modifiers, position_map, window, cx);
 7974
 7975        let mouse_position = window.mouse_position();
 7976        if !position_map.text_hitbox.is_hovered(window) {
 7977            return;
 7978        }
 7979
 7980        self.update_hovered_link(
 7981            position_map.point_for_position(mouse_position),
 7982            &position_map.snapshot,
 7983            modifiers,
 7984            window,
 7985            cx,
 7986        )
 7987    }
 7988
 7989    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7990        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7991            MultiCursorModifier::Alt => modifiers.secondary(),
 7992            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 7993        }
 7994    }
 7995
 7996    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 7997        match EditorSettings::get_global(cx).multi_cursor_modifier {
 7998            MultiCursorModifier::Alt => modifiers.alt,
 7999            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 8000        }
 8001    }
 8002
 8003    fn columnar_selection_mode(
 8004        modifiers: &Modifiers,
 8005        cx: &mut Context<Self>,
 8006    ) -> Option<ColumnarMode> {
 8007        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 8008            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 8009                Some(ColumnarMode::FromMouse)
 8010            } else if Self::is_alt_pressed(modifiers, cx) {
 8011                Some(ColumnarMode::FromSelection)
 8012            } else {
 8013                None
 8014            }
 8015        } else {
 8016            None
 8017        }
 8018    }
 8019
 8020    fn update_selection_mode(
 8021        &mut self,
 8022        modifiers: &Modifiers,
 8023        position_map: &PositionMap,
 8024        window: &mut Window,
 8025        cx: &mut Context<Self>,
 8026    ) {
 8027        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 8028            return;
 8029        };
 8030        if self.selections.pending_anchor().is_none() {
 8031            return;
 8032        }
 8033
 8034        let mouse_position = window.mouse_position();
 8035        let point_for_position = position_map.point_for_position(mouse_position);
 8036        let position = point_for_position.previous_valid;
 8037
 8038        self.select(
 8039            SelectPhase::BeginColumnar {
 8040                position,
 8041                reset: false,
 8042                mode,
 8043                goal_column: point_for_position.exact_unclipped.column(),
 8044            },
 8045            window,
 8046            cx,
 8047        );
 8048    }
 8049
 8050    fn update_edit_prediction_preview(
 8051        &mut self,
 8052        modifiers: &Modifiers,
 8053        window: &mut Window,
 8054        cx: &mut Context<Self>,
 8055    ) {
 8056        let mut modifiers_held = false;
 8057
 8058        // Check bindings for all granularities.
 8059        // If the user holds the key for Word, Line, or Full, we want to show the preview.
 8060        let granularities = [
 8061            EditPredictionGranularity::Full,
 8062            EditPredictionGranularity::Line,
 8063            EditPredictionGranularity::Word,
 8064        ];
 8065
 8066        for granularity in granularities {
 8067            if let Some(keystroke) = self
 8068                .accept_edit_prediction_keybind(granularity, window, cx)
 8069                .keystroke()
 8070            {
 8071                modifiers_held = modifiers_held
 8072                    || (keystroke.modifiers() == modifiers && keystroke.modifiers().modified());
 8073            }
 8074        }
 8075
 8076        if modifiers_held {
 8077            if matches!(
 8078                self.edit_prediction_preview,
 8079                EditPredictionPreview::Inactive { .. }
 8080            ) {
 8081                if let Some(provider) = self.edit_prediction_provider.as_ref() {
 8082                    provider.provider.did_show(cx)
 8083                }
 8084
 8085                self.edit_prediction_preview = EditPredictionPreview::Active {
 8086                    previous_scroll_position: None,
 8087                    since: Instant::now(),
 8088                };
 8089
 8090                self.update_visible_edit_prediction(window, cx);
 8091                cx.notify();
 8092            }
 8093        } else if let EditPredictionPreview::Active {
 8094            previous_scroll_position,
 8095            since,
 8096        } = self.edit_prediction_preview
 8097        {
 8098            if let (Some(previous_scroll_position), Some(position_map)) =
 8099                (previous_scroll_position, self.last_position_map.as_ref())
 8100            {
 8101                self.set_scroll_position(
 8102                    previous_scroll_position
 8103                        .scroll_position(&position_map.snapshot.display_snapshot),
 8104                    window,
 8105                    cx,
 8106                );
 8107            }
 8108
 8109            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 8110                released_too_fast: since.elapsed() < Duration::from_millis(200),
 8111            };
 8112            self.clear_row_highlights::<EditPredictionPreview>();
 8113            self.update_visible_edit_prediction(window, cx);
 8114            cx.notify();
 8115        }
 8116    }
 8117
 8118    fn update_visible_edit_prediction(
 8119        &mut self,
 8120        _window: &mut Window,
 8121        cx: &mut Context<Self>,
 8122    ) -> Option<()> {
 8123        if DisableAiSettings::get_global(cx).disable_ai {
 8124            return None;
 8125        }
 8126
 8127        if self.ime_transaction.is_some() {
 8128            self.discard_edit_prediction(false, cx);
 8129            return None;
 8130        }
 8131
 8132        let selection = self.selections.newest_anchor();
 8133        let cursor = selection.head();
 8134        let multibuffer = self.buffer.read(cx).snapshot(cx);
 8135        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 8136        let excerpt_id = cursor.excerpt_id;
 8137
 8138        let show_in_menu = self.show_edit_predictions_in_menu();
 8139        let completions_menu_has_precedence = !show_in_menu
 8140            && (self.context_menu.borrow().is_some()
 8141                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 8142
 8143        if completions_menu_has_precedence
 8144            || !offset_selection.is_empty()
 8145            || self
 8146                .active_edit_prediction
 8147                .as_ref()
 8148                .is_some_and(|completion| {
 8149                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 8150                        return false;
 8151                    };
 8152                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 8153                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 8154                    !invalidation_range.contains(&offset_selection.head())
 8155                })
 8156        {
 8157            self.discard_edit_prediction(false, cx);
 8158            return None;
 8159        }
 8160
 8161        self.take_active_edit_prediction(cx);
 8162        let Some(provider) = self.edit_prediction_provider() else {
 8163            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8164            return None;
 8165        };
 8166
 8167        let (buffer, cursor_buffer_position) =
 8168            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 8169
 8170        self.edit_prediction_settings =
 8171            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 8172
 8173        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 8174
 8175        if self.edit_prediction_indent_conflict {
 8176            let cursor_point = cursor.to_point(&multibuffer);
 8177            let mut suggested_indent = None;
 8178            multibuffer.suggested_indents_callback(
 8179                cursor_point.row..cursor_point.row + 1,
 8180                |_, indent| {
 8181                    suggested_indent = Some(indent);
 8182                    ControlFlow::Break(())
 8183                },
 8184                cx,
 8185            );
 8186
 8187            if let Some(indent) = suggested_indent
 8188                && indent.len == cursor_point.column
 8189            {
 8190                self.edit_prediction_indent_conflict = false;
 8191            }
 8192        }
 8193
 8194        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 8195
 8196        let (completion_id, edits, edit_preview) = match edit_prediction {
 8197            edit_prediction_types::EditPrediction::Local {
 8198                id,
 8199                edits,
 8200                edit_preview,
 8201            } => (id, edits, edit_preview),
 8202            edit_prediction_types::EditPrediction::Jump {
 8203                id,
 8204                snapshot,
 8205                target,
 8206            } => {
 8207                self.stale_edit_prediction_in_menu = None;
 8208                self.active_edit_prediction = Some(EditPredictionState {
 8209                    inlay_ids: vec![],
 8210                    completion: EditPrediction::MoveOutside { snapshot, target },
 8211                    completion_id: id,
 8212                    invalidation_range: None,
 8213                });
 8214                cx.notify();
 8215                return Some(());
 8216            }
 8217        };
 8218
 8219        let edits = edits
 8220            .into_iter()
 8221            .flat_map(|(range, new_text)| {
 8222                Some((
 8223                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8224                    new_text,
 8225                ))
 8226            })
 8227            .collect::<Vec<_>>();
 8228        if edits.is_empty() {
 8229            return None;
 8230        }
 8231
 8232        let first_edit_start = edits.first().unwrap().0.start;
 8233        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8234        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8235
 8236        let last_edit_end = edits.last().unwrap().0.end;
 8237        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8238        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8239
 8240        let cursor_row = cursor.to_point(&multibuffer).row;
 8241
 8242        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8243
 8244        let mut inlay_ids = Vec::new();
 8245        let invalidation_row_range;
 8246        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8247            Some(cursor_row..edit_end_row)
 8248        } else if cursor_row > edit_end_row {
 8249            Some(edit_start_row..cursor_row)
 8250        } else {
 8251            None
 8252        };
 8253        let supports_jump = self
 8254            .edit_prediction_provider
 8255            .as_ref()
 8256            .map(|provider| provider.provider.supports_jump_to_edit())
 8257            .unwrap_or(true);
 8258
 8259        let is_move = supports_jump
 8260            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8261        let completion = if is_move {
 8262            invalidation_row_range =
 8263                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8264            let target = first_edit_start;
 8265            EditPrediction::MoveWithin { target, snapshot }
 8266        } else {
 8267            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8268                && !self.edit_predictions_hidden_for_vim_mode;
 8269
 8270            if show_completions_in_buffer {
 8271                if let Some(provider) = &self.edit_prediction_provider {
 8272                    provider.provider.did_show(cx);
 8273                }
 8274                if edits
 8275                    .iter()
 8276                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8277                {
 8278                    let mut inlays = Vec::new();
 8279                    for (range, new_text) in &edits {
 8280                        let inlay = Inlay::edit_prediction(
 8281                            post_inc(&mut self.next_inlay_id),
 8282                            range.start,
 8283                            new_text.as_ref(),
 8284                        );
 8285                        inlay_ids.push(inlay.id);
 8286                        inlays.push(inlay);
 8287                    }
 8288
 8289                    self.splice_inlays(&[], inlays, cx);
 8290                } else {
 8291                    let background_color = cx.theme().status().deleted_background;
 8292                    self.highlight_text::<EditPredictionHighlight>(
 8293                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8294                        HighlightStyle {
 8295                            background_color: Some(background_color),
 8296                            ..Default::default()
 8297                        },
 8298                        cx,
 8299                    );
 8300                }
 8301            }
 8302
 8303            invalidation_row_range = edit_start_row..edit_end_row;
 8304
 8305            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8306                if provider.show_tab_accept_marker() {
 8307                    EditDisplayMode::TabAccept
 8308                } else {
 8309                    EditDisplayMode::Inline
 8310                }
 8311            } else {
 8312                EditDisplayMode::DiffPopover
 8313            };
 8314
 8315            EditPrediction::Edit {
 8316                edits,
 8317                edit_preview,
 8318                display_mode,
 8319                snapshot,
 8320            }
 8321        };
 8322
 8323        let invalidation_range = multibuffer
 8324            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8325            ..multibuffer.anchor_after(Point::new(
 8326                invalidation_row_range.end,
 8327                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8328            ));
 8329
 8330        self.stale_edit_prediction_in_menu = None;
 8331        self.active_edit_prediction = Some(EditPredictionState {
 8332            inlay_ids,
 8333            completion,
 8334            completion_id,
 8335            invalidation_range: Some(invalidation_range),
 8336        });
 8337
 8338        cx.notify();
 8339
 8340        Some(())
 8341    }
 8342
 8343    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionDelegateHandle>> {
 8344        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8345    }
 8346
 8347    fn clear_tasks(&mut self) {
 8348        self.tasks.clear()
 8349    }
 8350
 8351    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8352        if self.tasks.insert(key, value).is_some() {
 8353            // This case should hopefully be rare, but just in case...
 8354            log::error!(
 8355                "multiple different run targets found on a single line, only the last target will be rendered"
 8356            )
 8357        }
 8358    }
 8359
 8360    /// Get all display points of breakpoints that will be rendered within editor
 8361    ///
 8362    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8363    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8364    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8365    fn active_breakpoints(
 8366        &self,
 8367        range: Range<DisplayRow>,
 8368        window: &mut Window,
 8369        cx: &mut Context<Self>,
 8370    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8371        let mut breakpoint_display_points = HashMap::default();
 8372
 8373        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8374            return breakpoint_display_points;
 8375        };
 8376
 8377        let snapshot = self.snapshot(window, cx);
 8378
 8379        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8380        let Some(project) = self.project() else {
 8381            return breakpoint_display_points;
 8382        };
 8383
 8384        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8385            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8386
 8387        for (buffer_snapshot, range, excerpt_id) in
 8388            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8389        {
 8390            let Some(buffer) = project
 8391                .read(cx)
 8392                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8393            else {
 8394                continue;
 8395            };
 8396            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8397                &buffer,
 8398                Some(
 8399                    buffer_snapshot.anchor_before(range.start)
 8400                        ..buffer_snapshot.anchor_after(range.end),
 8401                ),
 8402                buffer_snapshot,
 8403                cx,
 8404            );
 8405            for (breakpoint, state) in breakpoints {
 8406                let multi_buffer_anchor = Anchor::in_buffer(excerpt_id, breakpoint.position);
 8407                let position = multi_buffer_anchor
 8408                    .to_point(&multi_buffer_snapshot)
 8409                    .to_display_point(&snapshot);
 8410
 8411                breakpoint_display_points.insert(
 8412                    position.row(),
 8413                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8414                );
 8415            }
 8416        }
 8417
 8418        breakpoint_display_points
 8419    }
 8420
 8421    fn breakpoint_context_menu(
 8422        &self,
 8423        anchor: Anchor,
 8424        window: &mut Window,
 8425        cx: &mut Context<Self>,
 8426    ) -> Entity<ui::ContextMenu> {
 8427        let weak_editor = cx.weak_entity();
 8428        let focus_handle = self.focus_handle(cx);
 8429
 8430        let row = self
 8431            .buffer
 8432            .read(cx)
 8433            .snapshot(cx)
 8434            .summary_for_anchor::<Point>(&anchor)
 8435            .row;
 8436
 8437        let breakpoint = self
 8438            .breakpoint_at_row(row, window, cx)
 8439            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8440
 8441        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8442            "Edit Log Breakpoint"
 8443        } else {
 8444            "Set Log Breakpoint"
 8445        };
 8446
 8447        let condition_breakpoint_msg = if breakpoint
 8448            .as_ref()
 8449            .is_some_and(|bp| bp.1.condition.is_some())
 8450        {
 8451            "Edit Condition Breakpoint"
 8452        } else {
 8453            "Set Condition Breakpoint"
 8454        };
 8455
 8456        let hit_condition_breakpoint_msg = if breakpoint
 8457            .as_ref()
 8458            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8459        {
 8460            "Edit Hit Condition Breakpoint"
 8461        } else {
 8462            "Set Hit Condition Breakpoint"
 8463        };
 8464
 8465        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8466            "Unset Breakpoint"
 8467        } else {
 8468            "Set Breakpoint"
 8469        };
 8470
 8471        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8472
 8473        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8474            BreakpointState::Enabled => Some("Disable"),
 8475            BreakpointState::Disabled => Some("Enable"),
 8476        });
 8477
 8478        let (anchor, breakpoint) =
 8479            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8480
 8481        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8482            menu.on_blur_subscription(Subscription::new(|| {}))
 8483                .context(focus_handle)
 8484                .when(run_to_cursor, |this| {
 8485                    let weak_editor = weak_editor.clone();
 8486                    this.entry("Run to cursor", None, move |window, cx| {
 8487                        weak_editor
 8488                            .update(cx, |editor, cx| {
 8489                                editor.change_selections(
 8490                                    SelectionEffects::no_scroll(),
 8491                                    window,
 8492                                    cx,
 8493                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8494                                );
 8495                            })
 8496                            .ok();
 8497
 8498                        window.dispatch_action(Box::new(RunToCursor), cx);
 8499                    })
 8500                    .separator()
 8501                })
 8502                .when_some(toggle_state_msg, |this, msg| {
 8503                    this.entry(msg, None, {
 8504                        let weak_editor = weak_editor.clone();
 8505                        let breakpoint = breakpoint.clone();
 8506                        move |_window, cx| {
 8507                            weak_editor
 8508                                .update(cx, |this, cx| {
 8509                                    this.edit_breakpoint_at_anchor(
 8510                                        anchor,
 8511                                        breakpoint.as_ref().clone(),
 8512                                        BreakpointEditAction::InvertState,
 8513                                        cx,
 8514                                    );
 8515                                })
 8516                                .log_err();
 8517                        }
 8518                    })
 8519                })
 8520                .entry(set_breakpoint_msg, None, {
 8521                    let weak_editor = weak_editor.clone();
 8522                    let breakpoint = breakpoint.clone();
 8523                    move |_window, cx| {
 8524                        weak_editor
 8525                            .update(cx, |this, cx| {
 8526                                this.edit_breakpoint_at_anchor(
 8527                                    anchor,
 8528                                    breakpoint.as_ref().clone(),
 8529                                    BreakpointEditAction::Toggle,
 8530                                    cx,
 8531                                );
 8532                            })
 8533                            .log_err();
 8534                    }
 8535                })
 8536                .entry(log_breakpoint_msg, None, {
 8537                    let breakpoint = breakpoint.clone();
 8538                    let weak_editor = weak_editor.clone();
 8539                    move |window, cx| {
 8540                        weak_editor
 8541                            .update(cx, |this, cx| {
 8542                                this.add_edit_breakpoint_block(
 8543                                    anchor,
 8544                                    breakpoint.as_ref(),
 8545                                    BreakpointPromptEditAction::Log,
 8546                                    window,
 8547                                    cx,
 8548                                );
 8549                            })
 8550                            .log_err();
 8551                    }
 8552                })
 8553                .entry(condition_breakpoint_msg, None, {
 8554                    let breakpoint = breakpoint.clone();
 8555                    let weak_editor = weak_editor.clone();
 8556                    move |window, cx| {
 8557                        weak_editor
 8558                            .update(cx, |this, cx| {
 8559                                this.add_edit_breakpoint_block(
 8560                                    anchor,
 8561                                    breakpoint.as_ref(),
 8562                                    BreakpointPromptEditAction::Condition,
 8563                                    window,
 8564                                    cx,
 8565                                );
 8566                            })
 8567                            .log_err();
 8568                    }
 8569                })
 8570                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8571                    weak_editor
 8572                        .update(cx, |this, cx| {
 8573                            this.add_edit_breakpoint_block(
 8574                                anchor,
 8575                                breakpoint.as_ref(),
 8576                                BreakpointPromptEditAction::HitCondition,
 8577                                window,
 8578                                cx,
 8579                            );
 8580                        })
 8581                        .log_err();
 8582                })
 8583        })
 8584    }
 8585
 8586    fn render_breakpoint(
 8587        &self,
 8588        position: Anchor,
 8589        row: DisplayRow,
 8590        breakpoint: &Breakpoint,
 8591        state: Option<BreakpointSessionState>,
 8592        cx: &mut Context<Self>,
 8593    ) -> IconButton {
 8594        let is_rejected = state.is_some_and(|s| !s.verified);
 8595        // Is it a breakpoint that shows up when hovering over gutter?
 8596        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8597            (false, false),
 8598            |PhantomBreakpointIndicator {
 8599                 is_active,
 8600                 display_row,
 8601                 collides_with_existing_breakpoint,
 8602             }| {
 8603                (
 8604                    is_active && display_row == row,
 8605                    collides_with_existing_breakpoint,
 8606                )
 8607            },
 8608        );
 8609
 8610        let (color, icon) = {
 8611            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8612                (false, false) => ui::IconName::DebugBreakpoint,
 8613                (true, false) => ui::IconName::DebugLogBreakpoint,
 8614                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8615                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8616            };
 8617
 8618            let color = cx.theme().colors();
 8619
 8620            let color = if is_phantom {
 8621                if collides_with_existing {
 8622                    Color::Custom(color.debugger_accent.blend(color.text.opacity(0.6)))
 8623                } else {
 8624                    Color::Hint
 8625                }
 8626            } else if is_rejected {
 8627                Color::Disabled
 8628            } else {
 8629                Color::Debugger
 8630            };
 8631
 8632            (color, icon)
 8633        };
 8634
 8635        let breakpoint = Arc::from(breakpoint.clone());
 8636
 8637        let alt_as_text = gpui::Keystroke {
 8638            modifiers: Modifiers::secondary_key(),
 8639            ..Default::default()
 8640        };
 8641        let primary_action_text = if breakpoint.is_disabled() {
 8642            "Enable breakpoint"
 8643        } else if is_phantom && !collides_with_existing {
 8644            "Set breakpoint"
 8645        } else {
 8646            "Unset breakpoint"
 8647        };
 8648        let focus_handle = self.focus_handle.clone();
 8649
 8650        let meta = if is_rejected {
 8651            SharedString::from("No executable code is associated with this line.")
 8652        } else if collides_with_existing && !breakpoint.is_disabled() {
 8653            SharedString::from(format!(
 8654                "{alt_as_text}-click to disable,\nright-click for more options."
 8655            ))
 8656        } else {
 8657            SharedString::from("Right-click for more options.")
 8658        };
 8659        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8660            .icon_size(IconSize::XSmall)
 8661            .size(ui::ButtonSize::None)
 8662            .when(is_rejected, |this| {
 8663                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8664            })
 8665            .icon_color(color)
 8666            .style(ButtonStyle::Transparent)
 8667            .on_click(cx.listener({
 8668                move |editor, event: &ClickEvent, window, cx| {
 8669                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8670                        BreakpointEditAction::InvertState
 8671                    } else {
 8672                        BreakpointEditAction::Toggle
 8673                    };
 8674
 8675                    window.focus(&editor.focus_handle(cx));
 8676                    editor.edit_breakpoint_at_anchor(
 8677                        position,
 8678                        breakpoint.as_ref().clone(),
 8679                        edit_action,
 8680                        cx,
 8681                    );
 8682                }
 8683            }))
 8684            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8685                editor.set_breakpoint_context_menu(
 8686                    row,
 8687                    Some(position),
 8688                    event.position(),
 8689                    window,
 8690                    cx,
 8691                );
 8692            }))
 8693            .tooltip(move |_window, cx| {
 8694                Tooltip::with_meta_in(
 8695                    primary_action_text,
 8696                    Some(&ToggleBreakpoint),
 8697                    meta.clone(),
 8698                    &focus_handle,
 8699                    cx,
 8700                )
 8701            })
 8702    }
 8703
 8704    fn build_tasks_context(
 8705        project: &Entity<Project>,
 8706        buffer: &Entity<Buffer>,
 8707        buffer_row: u32,
 8708        tasks: &Arc<RunnableTasks>,
 8709        cx: &mut Context<Self>,
 8710    ) -> Task<Option<task::TaskContext>> {
 8711        let position = Point::new(buffer_row, tasks.column);
 8712        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8713        let location = Location {
 8714            buffer: buffer.clone(),
 8715            range: range_start..range_start,
 8716        };
 8717        // Fill in the environmental variables from the tree-sitter captures
 8718        let mut captured_task_variables = TaskVariables::default();
 8719        for (capture_name, value) in tasks.extra_variables.clone() {
 8720            captured_task_variables.insert(
 8721                task::VariableName::Custom(capture_name.into()),
 8722                value.clone(),
 8723            );
 8724        }
 8725        project.update(cx, |project, cx| {
 8726            project.task_store().update(cx, |task_store, cx| {
 8727                task_store.task_context_for_location(captured_task_variables, location, cx)
 8728            })
 8729        })
 8730    }
 8731
 8732    pub fn spawn_nearest_task(
 8733        &mut self,
 8734        action: &SpawnNearestTask,
 8735        window: &mut Window,
 8736        cx: &mut Context<Self>,
 8737    ) {
 8738        let Some((workspace, _)) = self.workspace.clone() else {
 8739            return;
 8740        };
 8741        let Some(project) = self.project.clone() else {
 8742            return;
 8743        };
 8744
 8745        // Try to find a closest, enclosing node using tree-sitter that has a task
 8746        let Some((buffer, buffer_row, tasks)) = self
 8747            .find_enclosing_node_task(cx)
 8748            // Or find the task that's closest in row-distance.
 8749            .or_else(|| self.find_closest_task(cx))
 8750        else {
 8751            return;
 8752        };
 8753
 8754        let reveal_strategy = action.reveal;
 8755        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8756        cx.spawn_in(window, async move |_, cx| {
 8757            let context = task_context.await?;
 8758            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8759
 8760            let resolved = &mut resolved_task.resolved;
 8761            resolved.reveal = reveal_strategy;
 8762
 8763            workspace
 8764                .update_in(cx, |workspace, window, cx| {
 8765                    workspace.schedule_resolved_task(
 8766                        task_source_kind,
 8767                        resolved_task,
 8768                        false,
 8769                        window,
 8770                        cx,
 8771                    );
 8772                })
 8773                .ok()
 8774        })
 8775        .detach();
 8776    }
 8777
 8778    fn find_closest_task(
 8779        &mut self,
 8780        cx: &mut Context<Self>,
 8781    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8782        let cursor_row = self
 8783            .selections
 8784            .newest_adjusted(&self.display_snapshot(cx))
 8785            .head()
 8786            .row;
 8787
 8788        let ((buffer_id, row), tasks) = self
 8789            .tasks
 8790            .iter()
 8791            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8792
 8793        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8794        let tasks = Arc::new(tasks.to_owned());
 8795        Some((buffer, *row, tasks))
 8796    }
 8797
 8798    fn find_enclosing_node_task(
 8799        &mut self,
 8800        cx: &mut Context<Self>,
 8801    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8802        let snapshot = self.buffer.read(cx).snapshot(cx);
 8803        let offset = self
 8804            .selections
 8805            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 8806            .head();
 8807        let mut excerpt = snapshot.excerpt_containing(offset..offset)?;
 8808        let offset = excerpt.map_offset_to_buffer(offset);
 8809        let buffer_id = excerpt.buffer().remote_id();
 8810
 8811        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8812        let mut cursor = layer.node().walk();
 8813
 8814        while cursor.goto_first_child_for_byte(offset.0).is_some() {
 8815            if cursor.node().end_byte() == offset.0 {
 8816                cursor.goto_next_sibling();
 8817            }
 8818        }
 8819
 8820        // Ascend to the smallest ancestor that contains the range and has a task.
 8821        loop {
 8822            let node = cursor.node();
 8823            let node_range = node.byte_range();
 8824            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8825
 8826            // Check if this node contains our offset
 8827            if node_range.start <= offset.0 && node_range.end >= offset.0 {
 8828                // If it contains offset, check for task
 8829                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8830                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8831                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8832                }
 8833            }
 8834
 8835            if !cursor.goto_parent() {
 8836                break;
 8837            }
 8838        }
 8839        None
 8840    }
 8841
 8842    fn render_run_indicator(
 8843        &self,
 8844        _style: &EditorStyle,
 8845        is_active: bool,
 8846        row: DisplayRow,
 8847        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8848        cx: &mut Context<Self>,
 8849    ) -> IconButton {
 8850        let color = Color::Muted;
 8851        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8852
 8853        IconButton::new(
 8854            ("run_indicator", row.0 as usize),
 8855            ui::IconName::PlayOutlined,
 8856        )
 8857        .shape(ui::IconButtonShape::Square)
 8858        .icon_size(IconSize::XSmall)
 8859        .icon_color(color)
 8860        .toggle_state(is_active)
 8861        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8862            let quick_launch = match e {
 8863                ClickEvent::Keyboard(_) => true,
 8864                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8865            };
 8866
 8867            window.focus(&editor.focus_handle(cx));
 8868            editor.toggle_code_actions(
 8869                &ToggleCodeActions {
 8870                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8871                    quick_launch,
 8872                },
 8873                window,
 8874                cx,
 8875            );
 8876        }))
 8877        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8878            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8879        }))
 8880    }
 8881
 8882    pub fn context_menu_visible(&self) -> bool {
 8883        !self.edit_prediction_preview_is_active()
 8884            && self
 8885                .context_menu
 8886                .borrow()
 8887                .as_ref()
 8888                .is_some_and(|menu| menu.visible())
 8889    }
 8890
 8891    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8892        self.context_menu
 8893            .borrow()
 8894            .as_ref()
 8895            .map(|menu| menu.origin())
 8896    }
 8897
 8898    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8899        self.context_menu_options = Some(options);
 8900    }
 8901
 8902    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8903    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8904
 8905    fn render_edit_prediction_popover(
 8906        &mut self,
 8907        text_bounds: &Bounds<Pixels>,
 8908        content_origin: gpui::Point<Pixels>,
 8909        right_margin: Pixels,
 8910        editor_snapshot: &EditorSnapshot,
 8911        visible_row_range: Range<DisplayRow>,
 8912        scroll_top: ScrollOffset,
 8913        scroll_bottom: ScrollOffset,
 8914        line_layouts: &[LineWithInvisibles],
 8915        line_height: Pixels,
 8916        scroll_position: gpui::Point<ScrollOffset>,
 8917        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8918        newest_selection_head: Option<DisplayPoint>,
 8919        editor_width: Pixels,
 8920        style: &EditorStyle,
 8921        window: &mut Window,
 8922        cx: &mut App,
 8923    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8924        if self.mode().is_minimap() {
 8925            return None;
 8926        }
 8927        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8928
 8929        if self.edit_prediction_visible_in_cursor_popover(true) {
 8930            return None;
 8931        }
 8932
 8933        match &active_edit_prediction.completion {
 8934            EditPrediction::MoveWithin { target, .. } => {
 8935                let target_display_point = target.to_display_point(editor_snapshot);
 8936
 8937                if self.edit_prediction_requires_modifier() {
 8938                    if !self.edit_prediction_preview_is_active() {
 8939                        return None;
 8940                    }
 8941
 8942                    self.render_edit_prediction_modifier_jump_popover(
 8943                        text_bounds,
 8944                        content_origin,
 8945                        visible_row_range,
 8946                        line_layouts,
 8947                        line_height,
 8948                        scroll_pixel_position,
 8949                        newest_selection_head,
 8950                        target_display_point,
 8951                        window,
 8952                        cx,
 8953                    )
 8954                } else {
 8955                    self.render_edit_prediction_eager_jump_popover(
 8956                        text_bounds,
 8957                        content_origin,
 8958                        editor_snapshot,
 8959                        visible_row_range,
 8960                        scroll_top,
 8961                        scroll_bottom,
 8962                        line_height,
 8963                        scroll_pixel_position,
 8964                        target_display_point,
 8965                        editor_width,
 8966                        window,
 8967                        cx,
 8968                    )
 8969                }
 8970            }
 8971            EditPrediction::Edit {
 8972                display_mode: EditDisplayMode::Inline,
 8973                ..
 8974            } => None,
 8975            EditPrediction::Edit {
 8976                display_mode: EditDisplayMode::TabAccept,
 8977                edits,
 8978                ..
 8979            } => {
 8980                let range = &edits.first()?.0;
 8981                let target_display_point = range.end.to_display_point(editor_snapshot);
 8982
 8983                self.render_edit_prediction_end_of_line_popover(
 8984                    "Accept",
 8985                    editor_snapshot,
 8986                    visible_row_range,
 8987                    target_display_point,
 8988                    line_height,
 8989                    scroll_pixel_position,
 8990                    content_origin,
 8991                    editor_width,
 8992                    window,
 8993                    cx,
 8994                )
 8995            }
 8996            EditPrediction::Edit {
 8997                edits,
 8998                edit_preview,
 8999                display_mode: EditDisplayMode::DiffPopover,
 9000                snapshot,
 9001            } => self.render_edit_prediction_diff_popover(
 9002                text_bounds,
 9003                content_origin,
 9004                right_margin,
 9005                editor_snapshot,
 9006                visible_row_range,
 9007                line_layouts,
 9008                line_height,
 9009                scroll_position,
 9010                scroll_pixel_position,
 9011                newest_selection_head,
 9012                editor_width,
 9013                style,
 9014                edits,
 9015                edit_preview,
 9016                snapshot,
 9017                window,
 9018                cx,
 9019            ),
 9020            EditPrediction::MoveOutside { snapshot, .. } => {
 9021                let mut element = self
 9022                    .render_edit_prediction_jump_outside_popover(snapshot, window, cx)
 9023                    .into_any();
 9024
 9025                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9026                let origin_x = text_bounds.size.width - size.width - px(30.);
 9027                let origin = text_bounds.origin + gpui::Point::new(origin_x, px(16.));
 9028                element.prepaint_at(origin, window, cx);
 9029
 9030                Some((element, origin))
 9031            }
 9032        }
 9033    }
 9034
 9035    fn render_edit_prediction_modifier_jump_popover(
 9036        &mut self,
 9037        text_bounds: &Bounds<Pixels>,
 9038        content_origin: gpui::Point<Pixels>,
 9039        visible_row_range: Range<DisplayRow>,
 9040        line_layouts: &[LineWithInvisibles],
 9041        line_height: Pixels,
 9042        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9043        newest_selection_head: Option<DisplayPoint>,
 9044        target_display_point: DisplayPoint,
 9045        window: &mut Window,
 9046        cx: &mut App,
 9047    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9048        let scrolled_content_origin =
 9049            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 9050
 9051        const SCROLL_PADDING_Y: Pixels = px(12.);
 9052
 9053        if target_display_point.row() < visible_row_range.start {
 9054            return self.render_edit_prediction_scroll_popover(
 9055                |_| SCROLL_PADDING_Y,
 9056                IconName::ArrowUp,
 9057                visible_row_range,
 9058                line_layouts,
 9059                newest_selection_head,
 9060                scrolled_content_origin,
 9061                window,
 9062                cx,
 9063            );
 9064        } else if target_display_point.row() >= visible_row_range.end {
 9065            return self.render_edit_prediction_scroll_popover(
 9066                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 9067                IconName::ArrowDown,
 9068                visible_row_range,
 9069                line_layouts,
 9070                newest_selection_head,
 9071                scrolled_content_origin,
 9072                window,
 9073                cx,
 9074            );
 9075        }
 9076
 9077        const POLE_WIDTH: Pixels = px(2.);
 9078
 9079        let line_layout =
 9080            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 9081        let target_column = target_display_point.column() as usize;
 9082
 9083        let target_x = line_layout.x_for_index(target_column);
 9084        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 9085            - scroll_pixel_position.y;
 9086
 9087        let flag_on_right = target_x < text_bounds.size.width / 2.;
 9088
 9089        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 9090        border_color.l += 0.001;
 9091
 9092        let mut element = v_flex()
 9093            .items_end()
 9094            .when(flag_on_right, |el| el.items_start())
 9095            .child(if flag_on_right {
 9096                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9097                    .rounded_bl(px(0.))
 9098                    .rounded_tl(px(0.))
 9099                    .border_l_2()
 9100                    .border_color(border_color)
 9101            } else {
 9102                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9103                    .rounded_br(px(0.))
 9104                    .rounded_tr(px(0.))
 9105                    .border_r_2()
 9106                    .border_color(border_color)
 9107            })
 9108            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 9109            .into_any();
 9110
 9111        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9112
 9113        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 9114            - point(
 9115                if flag_on_right {
 9116                    POLE_WIDTH
 9117                } else {
 9118                    size.width - POLE_WIDTH
 9119                },
 9120                size.height - line_height,
 9121            );
 9122
 9123        origin.x = origin.x.max(content_origin.x);
 9124
 9125        element.prepaint_at(origin, window, cx);
 9126
 9127        Some((element, origin))
 9128    }
 9129
 9130    fn render_edit_prediction_scroll_popover(
 9131        &mut self,
 9132        to_y: impl Fn(Size<Pixels>) -> Pixels,
 9133        scroll_icon: IconName,
 9134        visible_row_range: Range<DisplayRow>,
 9135        line_layouts: &[LineWithInvisibles],
 9136        newest_selection_head: Option<DisplayPoint>,
 9137        scrolled_content_origin: gpui::Point<Pixels>,
 9138        window: &mut Window,
 9139        cx: &mut App,
 9140    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9141        let mut element = self
 9142            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 9143            .into_any();
 9144
 9145        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9146
 9147        let cursor = newest_selection_head?;
 9148        let cursor_row_layout =
 9149            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 9150        let cursor_column = cursor.column() as usize;
 9151
 9152        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 9153
 9154        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 9155
 9156        element.prepaint_at(origin, window, cx);
 9157        Some((element, origin))
 9158    }
 9159
 9160    fn render_edit_prediction_eager_jump_popover(
 9161        &mut self,
 9162        text_bounds: &Bounds<Pixels>,
 9163        content_origin: gpui::Point<Pixels>,
 9164        editor_snapshot: &EditorSnapshot,
 9165        visible_row_range: Range<DisplayRow>,
 9166        scroll_top: ScrollOffset,
 9167        scroll_bottom: ScrollOffset,
 9168        line_height: Pixels,
 9169        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9170        target_display_point: DisplayPoint,
 9171        editor_width: Pixels,
 9172        window: &mut Window,
 9173        cx: &mut App,
 9174    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9175        if target_display_point.row().as_f64() < scroll_top {
 9176            let mut element = self
 9177                .render_edit_prediction_line_popover(
 9178                    "Jump to Edit",
 9179                    Some(IconName::ArrowUp),
 9180                    window,
 9181                    cx,
 9182                )
 9183                .into_any();
 9184
 9185            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9186            let offset = point(
 9187                (text_bounds.size.width - size.width) / 2.,
 9188                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9189            );
 9190
 9191            let origin = text_bounds.origin + offset;
 9192            element.prepaint_at(origin, window, cx);
 9193            Some((element, origin))
 9194        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 9195            let mut element = self
 9196                .render_edit_prediction_line_popover(
 9197                    "Jump to Edit",
 9198                    Some(IconName::ArrowDown),
 9199                    window,
 9200                    cx,
 9201                )
 9202                .into_any();
 9203
 9204            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9205            let offset = point(
 9206                (text_bounds.size.width - size.width) / 2.,
 9207                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9208            );
 9209
 9210            let origin = text_bounds.origin + offset;
 9211            element.prepaint_at(origin, window, cx);
 9212            Some((element, origin))
 9213        } else {
 9214            self.render_edit_prediction_end_of_line_popover(
 9215                "Jump to Edit",
 9216                editor_snapshot,
 9217                visible_row_range,
 9218                target_display_point,
 9219                line_height,
 9220                scroll_pixel_position,
 9221                content_origin,
 9222                editor_width,
 9223                window,
 9224                cx,
 9225            )
 9226        }
 9227    }
 9228
 9229    fn render_edit_prediction_end_of_line_popover(
 9230        self: &mut Editor,
 9231        label: &'static str,
 9232        editor_snapshot: &EditorSnapshot,
 9233        visible_row_range: Range<DisplayRow>,
 9234        target_display_point: DisplayPoint,
 9235        line_height: Pixels,
 9236        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9237        content_origin: gpui::Point<Pixels>,
 9238        editor_width: Pixels,
 9239        window: &mut Window,
 9240        cx: &mut App,
 9241    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9242        let target_line_end = DisplayPoint::new(
 9243            target_display_point.row(),
 9244            editor_snapshot.line_len(target_display_point.row()),
 9245        );
 9246
 9247        let mut element = self
 9248            .render_edit_prediction_line_popover(label, None, window, cx)
 9249            .into_any();
 9250
 9251        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9252
 9253        let line_origin =
 9254            self.display_to_pixel_point(target_line_end, editor_snapshot, window, cx)?;
 9255
 9256        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9257        let mut origin = start_point
 9258            + line_origin
 9259            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9260        origin.x = origin.x.max(content_origin.x);
 9261
 9262        let max_x = content_origin.x + editor_width - size.width;
 9263
 9264        if origin.x > max_x {
 9265            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9266
 9267            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9268                origin.y += offset;
 9269                IconName::ArrowUp
 9270            } else {
 9271                origin.y -= offset;
 9272                IconName::ArrowDown
 9273            };
 9274
 9275            element = self
 9276                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9277                .into_any();
 9278
 9279            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9280
 9281            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9282        }
 9283
 9284        element.prepaint_at(origin, window, cx);
 9285        Some((element, origin))
 9286    }
 9287
 9288    fn render_edit_prediction_diff_popover(
 9289        self: &Editor,
 9290        text_bounds: &Bounds<Pixels>,
 9291        content_origin: gpui::Point<Pixels>,
 9292        right_margin: Pixels,
 9293        editor_snapshot: &EditorSnapshot,
 9294        visible_row_range: Range<DisplayRow>,
 9295        line_layouts: &[LineWithInvisibles],
 9296        line_height: Pixels,
 9297        scroll_position: gpui::Point<ScrollOffset>,
 9298        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9299        newest_selection_head: Option<DisplayPoint>,
 9300        editor_width: Pixels,
 9301        style: &EditorStyle,
 9302        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9303        edit_preview: &Option<language::EditPreview>,
 9304        snapshot: &language::BufferSnapshot,
 9305        window: &mut Window,
 9306        cx: &mut App,
 9307    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9308        let edit_start = edits
 9309            .first()
 9310            .unwrap()
 9311            .0
 9312            .start
 9313            .to_display_point(editor_snapshot);
 9314        let edit_end = edits
 9315            .last()
 9316            .unwrap()
 9317            .0
 9318            .end
 9319            .to_display_point(editor_snapshot);
 9320
 9321        let is_visible = visible_row_range.contains(&edit_start.row())
 9322            || visible_row_range.contains(&edit_end.row());
 9323        if !is_visible {
 9324            return None;
 9325        }
 9326
 9327        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9328            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9329        } else {
 9330            // Fallback for providers without edit_preview
 9331            crate::edit_prediction_fallback_text(edits, cx)
 9332        };
 9333
 9334        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9335        let line_count = highlighted_edits.text.lines().count();
 9336
 9337        const BORDER_WIDTH: Pixels = px(1.);
 9338
 9339        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9340        let has_keybind = keybind.is_some();
 9341
 9342        let mut element = h_flex()
 9343            .items_start()
 9344            .child(
 9345                h_flex()
 9346                    .bg(cx.theme().colors().editor_background)
 9347                    .border(BORDER_WIDTH)
 9348                    .shadow_xs()
 9349                    .border_color(cx.theme().colors().border)
 9350                    .rounded_l_lg()
 9351                    .when(line_count > 1, |el| el.rounded_br_lg())
 9352                    .pr_1()
 9353                    .child(styled_text),
 9354            )
 9355            .child(
 9356                h_flex()
 9357                    .h(line_height + BORDER_WIDTH * 2.)
 9358                    .px_1p5()
 9359                    .gap_1()
 9360                    // Workaround: For some reason, there's a gap if we don't do this
 9361                    .ml(-BORDER_WIDTH)
 9362                    .shadow(vec![gpui::BoxShadow {
 9363                        color: gpui::black().opacity(0.05),
 9364                        offset: point(px(1.), px(1.)),
 9365                        blur_radius: px(2.),
 9366                        spread_radius: px(0.),
 9367                    }])
 9368                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9369                    .border(BORDER_WIDTH)
 9370                    .border_color(cx.theme().colors().border)
 9371                    .rounded_r_lg()
 9372                    .id("edit_prediction_diff_popover_keybind")
 9373                    .when(!has_keybind, |el| {
 9374                        let status_colors = cx.theme().status();
 9375
 9376                        el.bg(status_colors.error_background)
 9377                            .border_color(status_colors.error.opacity(0.6))
 9378                            .child(Icon::new(IconName::Info).color(Color::Error))
 9379                            .cursor_default()
 9380                            .hoverable_tooltip(move |_window, cx| {
 9381                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9382                            })
 9383                    })
 9384                    .children(keybind),
 9385            )
 9386            .into_any();
 9387
 9388        let longest_row =
 9389            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9390        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9391            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9392        } else {
 9393            layout_line(
 9394                longest_row,
 9395                editor_snapshot,
 9396                style,
 9397                editor_width,
 9398                |_| false,
 9399                window,
 9400                cx,
 9401            )
 9402            .width
 9403        };
 9404
 9405        let viewport_bounds =
 9406            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9407                right: -right_margin,
 9408                ..Default::default()
 9409            });
 9410
 9411        let x_after_longest = Pixels::from(
 9412            ScrollPixelOffset::from(
 9413                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9414            ) - scroll_pixel_position.x,
 9415        );
 9416
 9417        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9418
 9419        // Fully visible if it can be displayed within the window (allow overlapping other
 9420        // panes). However, this is only allowed if the popover starts within text_bounds.
 9421        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9422            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9423
 9424        let mut origin = if can_position_to_the_right {
 9425            point(
 9426                x_after_longest,
 9427                text_bounds.origin.y
 9428                    + Pixels::from(
 9429                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9430                            - scroll_pixel_position.y,
 9431                    ),
 9432            )
 9433        } else {
 9434            let cursor_row = newest_selection_head.map(|head| head.row());
 9435            let above_edit = edit_start
 9436                .row()
 9437                .0
 9438                .checked_sub(line_count as u32)
 9439                .map(DisplayRow);
 9440            let below_edit = Some(edit_end.row() + 1);
 9441            let above_cursor =
 9442                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9443            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9444
 9445            // Place the edit popover adjacent to the edit if there is a location
 9446            // available that is onscreen and does not obscure the cursor. Otherwise,
 9447            // place it adjacent to the cursor.
 9448            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9449                .into_iter()
 9450                .flatten()
 9451                .find(|&start_row| {
 9452                    let end_row = start_row + line_count as u32;
 9453                    visible_row_range.contains(&start_row)
 9454                        && visible_row_range.contains(&end_row)
 9455                        && cursor_row
 9456                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9457                })?;
 9458
 9459            content_origin
 9460                + point(
 9461                    Pixels::from(-scroll_pixel_position.x),
 9462                    Pixels::from(
 9463                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9464                    ),
 9465                )
 9466        };
 9467
 9468        origin.x -= BORDER_WIDTH;
 9469
 9470        window.defer_draw(element, origin, 1);
 9471
 9472        // Do not return an element, since it will already be drawn due to defer_draw.
 9473        None
 9474    }
 9475
 9476    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9477        px(30.)
 9478    }
 9479
 9480    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9481        if self.read_only(cx) {
 9482            cx.theme().players().read_only()
 9483        } else {
 9484            self.style.as_ref().unwrap().local_player
 9485        }
 9486    }
 9487
 9488    fn render_edit_prediction_accept_keybind(
 9489        &self,
 9490        window: &mut Window,
 9491        cx: &mut App,
 9492    ) -> Option<AnyElement> {
 9493        let accept_binding =
 9494            self.accept_edit_prediction_keybind(EditPredictionGranularity::Full, window, cx);
 9495        let accept_keystroke = accept_binding.keystroke()?;
 9496
 9497        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9498
 9499        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9500            Color::Accent
 9501        } else {
 9502            Color::Muted
 9503        };
 9504
 9505        h_flex()
 9506            .px_0p5()
 9507            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9508            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9509            .text_size(TextSize::XSmall.rems(cx))
 9510            .child(h_flex().children(ui::render_modifiers(
 9511                accept_keystroke.modifiers(),
 9512                PlatformStyle::platform(),
 9513                Some(modifiers_color),
 9514                Some(IconSize::XSmall.rems().into()),
 9515                true,
 9516            )))
 9517            .when(is_platform_style_mac, |parent| {
 9518                parent.child(accept_keystroke.key().to_string())
 9519            })
 9520            .when(!is_platform_style_mac, |parent| {
 9521                parent.child(
 9522                    Key::new(
 9523                        util::capitalize(accept_keystroke.key()),
 9524                        Some(Color::Default),
 9525                    )
 9526                    .size(Some(IconSize::XSmall.rems().into())),
 9527                )
 9528            })
 9529            .into_any()
 9530            .into()
 9531    }
 9532
 9533    fn render_edit_prediction_line_popover(
 9534        &self,
 9535        label: impl Into<SharedString>,
 9536        icon: Option<IconName>,
 9537        window: &mut Window,
 9538        cx: &mut App,
 9539    ) -> Stateful<Div> {
 9540        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9541
 9542        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9543        let has_keybind = keybind.is_some();
 9544
 9545        h_flex()
 9546            .id("ep-line-popover")
 9547            .py_0p5()
 9548            .pl_1()
 9549            .pr(padding_right)
 9550            .gap_1()
 9551            .rounded_md()
 9552            .border_1()
 9553            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9554            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9555            .shadow_xs()
 9556            .when(!has_keybind, |el| {
 9557                let status_colors = cx.theme().status();
 9558
 9559                el.bg(status_colors.error_background)
 9560                    .border_color(status_colors.error.opacity(0.6))
 9561                    .pl_2()
 9562                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9563                    .cursor_default()
 9564                    .hoverable_tooltip(move |_window, cx| {
 9565                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9566                    })
 9567            })
 9568            .children(keybind)
 9569            .child(
 9570                Label::new(label)
 9571                    .size(LabelSize::Small)
 9572                    .when(!has_keybind, |el| {
 9573                        el.color(cx.theme().status().error.into()).strikethrough()
 9574                    }),
 9575            )
 9576            .when(!has_keybind, |el| {
 9577                el.child(
 9578                    h_flex().ml_1().child(
 9579                        Icon::new(IconName::Info)
 9580                            .size(IconSize::Small)
 9581                            .color(cx.theme().status().error.into()),
 9582                    ),
 9583                )
 9584            })
 9585            .when_some(icon, |element, icon| {
 9586                element.child(
 9587                    div()
 9588                        .mt(px(1.5))
 9589                        .child(Icon::new(icon).size(IconSize::Small)),
 9590                )
 9591            })
 9592    }
 9593
 9594    fn render_edit_prediction_jump_outside_popover(
 9595        &self,
 9596        snapshot: &BufferSnapshot,
 9597        window: &mut Window,
 9598        cx: &mut App,
 9599    ) -> Stateful<Div> {
 9600        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9601        let has_keybind = keybind.is_some();
 9602
 9603        let file_name = snapshot
 9604            .file()
 9605            .map(|file| SharedString::new(file.file_name(cx)))
 9606            .unwrap_or(SharedString::new_static("untitled"));
 9607
 9608        h_flex()
 9609            .id("ep-jump-outside-popover")
 9610            .py_1()
 9611            .px_2()
 9612            .gap_1()
 9613            .rounded_md()
 9614            .border_1()
 9615            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9616            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9617            .shadow_xs()
 9618            .when(!has_keybind, |el| {
 9619                let status_colors = cx.theme().status();
 9620
 9621                el.bg(status_colors.error_background)
 9622                    .border_color(status_colors.error.opacity(0.6))
 9623                    .pl_2()
 9624                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9625                    .cursor_default()
 9626                    .hoverable_tooltip(move |_window, cx| {
 9627                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9628                    })
 9629            })
 9630            .children(keybind)
 9631            .child(
 9632                Label::new(file_name)
 9633                    .size(LabelSize::Small)
 9634                    .buffer_font(cx)
 9635                    .when(!has_keybind, |el| {
 9636                        el.color(cx.theme().status().error.into()).strikethrough()
 9637                    }),
 9638            )
 9639            .when(!has_keybind, |el| {
 9640                el.child(
 9641                    h_flex().ml_1().child(
 9642                        Icon::new(IconName::Info)
 9643                            .size(IconSize::Small)
 9644                            .color(cx.theme().status().error.into()),
 9645                    ),
 9646                )
 9647            })
 9648            .child(
 9649                div()
 9650                    .mt(px(1.5))
 9651                    .child(Icon::new(IconName::ArrowUpRight).size(IconSize::Small)),
 9652            )
 9653    }
 9654
 9655    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9656        let accent_color = cx.theme().colors().text_accent;
 9657        let editor_bg_color = cx.theme().colors().editor_background;
 9658        editor_bg_color.blend(accent_color.opacity(0.1))
 9659    }
 9660
 9661    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9662        let accent_color = cx.theme().colors().text_accent;
 9663        let editor_bg_color = cx.theme().colors().editor_background;
 9664        editor_bg_color.blend(accent_color.opacity(0.6))
 9665    }
 9666    fn get_prediction_provider_icon_name(
 9667        provider: &Option<RegisteredEditPredictionDelegate>,
 9668    ) -> IconName {
 9669        match provider {
 9670            Some(provider) => match provider.provider.name() {
 9671                "copilot" => IconName::Copilot,
 9672                "supermaven" => IconName::Supermaven,
 9673                _ => IconName::ZedPredict,
 9674            },
 9675            None => IconName::ZedPredict,
 9676        }
 9677    }
 9678
 9679    fn render_edit_prediction_cursor_popover(
 9680        &self,
 9681        min_width: Pixels,
 9682        max_width: Pixels,
 9683        cursor_point: Point,
 9684        style: &EditorStyle,
 9685        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9686        _window: &Window,
 9687        cx: &mut Context<Editor>,
 9688    ) -> Option<AnyElement> {
 9689        let provider = self.edit_prediction_provider.as_ref()?;
 9690        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9691
 9692        let is_refreshing = provider.provider.is_refreshing(cx);
 9693
 9694        fn pending_completion_container(icon: IconName) -> Div {
 9695            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9696        }
 9697
 9698        let completion = match &self.active_edit_prediction {
 9699            Some(prediction) => {
 9700                if !self.has_visible_completions_menu() {
 9701                    const RADIUS: Pixels = px(6.);
 9702                    const BORDER_WIDTH: Pixels = px(1.);
 9703
 9704                    return Some(
 9705                        h_flex()
 9706                            .elevation_2(cx)
 9707                            .border(BORDER_WIDTH)
 9708                            .border_color(cx.theme().colors().border)
 9709                            .when(accept_keystroke.is_none(), |el| {
 9710                                el.border_color(cx.theme().status().error)
 9711                            })
 9712                            .rounded(RADIUS)
 9713                            .rounded_tl(px(0.))
 9714                            .overflow_hidden()
 9715                            .child(div().px_1p5().child(match &prediction.completion {
 9716                                EditPrediction::MoveWithin { target, snapshot } => {
 9717                                    use text::ToPoint as _;
 9718                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9719                                    {
 9720                                        Icon::new(IconName::ZedPredictDown)
 9721                                    } else {
 9722                                        Icon::new(IconName::ZedPredictUp)
 9723                                    }
 9724                                }
 9725                                EditPrediction::MoveOutside { .. } => {
 9726                                    // TODO [zeta2] custom icon for external jump?
 9727                                    Icon::new(provider_icon)
 9728                                }
 9729                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9730                            }))
 9731                            .child(
 9732                                h_flex()
 9733                                    .gap_1()
 9734                                    .py_1()
 9735                                    .px_2()
 9736                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9737                                    .border_l_1()
 9738                                    .border_color(cx.theme().colors().border)
 9739                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9740                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9741                                        el.child(
 9742                                            Label::new("Hold")
 9743                                                .size(LabelSize::Small)
 9744                                                .when(accept_keystroke.is_none(), |el| {
 9745                                                    el.strikethrough()
 9746                                                })
 9747                                                .line_height_style(LineHeightStyle::UiLabel),
 9748                                        )
 9749                                    })
 9750                                    .id("edit_prediction_cursor_popover_keybind")
 9751                                    .when(accept_keystroke.is_none(), |el| {
 9752                                        let status_colors = cx.theme().status();
 9753
 9754                                        el.bg(status_colors.error_background)
 9755                                            .border_color(status_colors.error.opacity(0.6))
 9756                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9757                                            .cursor_default()
 9758                                            .hoverable_tooltip(move |_window, cx| {
 9759                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9760                                                    .into()
 9761                                            })
 9762                                    })
 9763                                    .when_some(
 9764                                        accept_keystroke.as_ref(),
 9765                                        |el, accept_keystroke| {
 9766                                            el.child(h_flex().children(ui::render_modifiers(
 9767                                                accept_keystroke.modifiers(),
 9768                                                PlatformStyle::platform(),
 9769                                                Some(Color::Default),
 9770                                                Some(IconSize::XSmall.rems().into()),
 9771                                                false,
 9772                                            )))
 9773                                        },
 9774                                    ),
 9775                            )
 9776                            .into_any(),
 9777                    );
 9778                }
 9779
 9780                self.render_edit_prediction_cursor_popover_preview(
 9781                    prediction,
 9782                    cursor_point,
 9783                    style,
 9784                    cx,
 9785                )?
 9786            }
 9787
 9788            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9789                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9790                    stale_completion,
 9791                    cursor_point,
 9792                    style,
 9793                    cx,
 9794                )?,
 9795
 9796                None => pending_completion_container(provider_icon)
 9797                    .child(Label::new("...").size(LabelSize::Small)),
 9798            },
 9799
 9800            None => pending_completion_container(provider_icon)
 9801                .child(Label::new("...").size(LabelSize::Small)),
 9802        };
 9803
 9804        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9805            completion
 9806                .with_animation(
 9807                    "loading-completion",
 9808                    Animation::new(Duration::from_secs(2))
 9809                        .repeat()
 9810                        .with_easing(pulsating_between(0.4, 0.8)),
 9811                    |label, delta| label.opacity(delta),
 9812                )
 9813                .into_any_element()
 9814        } else {
 9815            completion.into_any_element()
 9816        };
 9817
 9818        let has_completion = self.active_edit_prediction.is_some();
 9819
 9820        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9821        Some(
 9822            h_flex()
 9823                .min_w(min_width)
 9824                .max_w(max_width)
 9825                .flex_1()
 9826                .elevation_2(cx)
 9827                .border_color(cx.theme().colors().border)
 9828                .child(
 9829                    div()
 9830                        .flex_1()
 9831                        .py_1()
 9832                        .px_2()
 9833                        .overflow_hidden()
 9834                        .child(completion),
 9835                )
 9836                .when_some(accept_keystroke, |el, accept_keystroke| {
 9837                    if !accept_keystroke.modifiers().modified() {
 9838                        return el;
 9839                    }
 9840
 9841                    el.child(
 9842                        h_flex()
 9843                            .h_full()
 9844                            .border_l_1()
 9845                            .rounded_r_lg()
 9846                            .border_color(cx.theme().colors().border)
 9847                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9848                            .gap_1()
 9849                            .py_1()
 9850                            .px_2()
 9851                            .child(
 9852                                h_flex()
 9853                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9854                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9855                                    .child(h_flex().children(ui::render_modifiers(
 9856                                        accept_keystroke.modifiers(),
 9857                                        PlatformStyle::platform(),
 9858                                        Some(if !has_completion {
 9859                                            Color::Muted
 9860                                        } else {
 9861                                            Color::Default
 9862                                        }),
 9863                                        None,
 9864                                        false,
 9865                                    ))),
 9866                            )
 9867                            .child(Label::new("Preview").into_any_element())
 9868                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9869                    )
 9870                })
 9871                .into_any(),
 9872        )
 9873    }
 9874
 9875    fn render_edit_prediction_cursor_popover_preview(
 9876        &self,
 9877        completion: &EditPredictionState,
 9878        cursor_point: Point,
 9879        style: &EditorStyle,
 9880        cx: &mut Context<Editor>,
 9881    ) -> Option<Div> {
 9882        use text::ToPoint as _;
 9883
 9884        fn render_relative_row_jump(
 9885            prefix: impl Into<String>,
 9886            current_row: u32,
 9887            target_row: u32,
 9888        ) -> Div {
 9889            let (row_diff, arrow) = if target_row < current_row {
 9890                (current_row - target_row, IconName::ArrowUp)
 9891            } else {
 9892                (target_row - current_row, IconName::ArrowDown)
 9893            };
 9894
 9895            h_flex()
 9896                .child(
 9897                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9898                        .color(Color::Muted)
 9899                        .size(LabelSize::Small),
 9900                )
 9901                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9902        }
 9903
 9904        let supports_jump = self
 9905            .edit_prediction_provider
 9906            .as_ref()
 9907            .map(|provider| provider.provider.supports_jump_to_edit())
 9908            .unwrap_or(true);
 9909
 9910        match &completion.completion {
 9911            EditPrediction::MoveWithin {
 9912                target, snapshot, ..
 9913            } => {
 9914                if !supports_jump {
 9915                    return None;
 9916                }
 9917
 9918                Some(
 9919                    h_flex()
 9920                        .px_2()
 9921                        .gap_2()
 9922                        .flex_1()
 9923                        .child(
 9924                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9925                                Icon::new(IconName::ZedPredictDown)
 9926                            } else {
 9927                                Icon::new(IconName::ZedPredictUp)
 9928                            },
 9929                        )
 9930                        .child(Label::new("Jump to Edit")),
 9931                )
 9932            }
 9933            EditPrediction::MoveOutside { snapshot, .. } => {
 9934                let file_name = snapshot
 9935                    .file()
 9936                    .map(|file| file.file_name(cx))
 9937                    .unwrap_or("untitled");
 9938                Some(
 9939                    h_flex()
 9940                        .px_2()
 9941                        .gap_2()
 9942                        .flex_1()
 9943                        .child(Icon::new(IconName::ZedPredict))
 9944                        .child(Label::new(format!("Jump to {file_name}"))),
 9945                )
 9946            }
 9947            EditPrediction::Edit {
 9948                edits,
 9949                edit_preview,
 9950                snapshot,
 9951                display_mode: _,
 9952            } => {
 9953                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9954
 9955                let (highlighted_edits, has_more_lines) =
 9956                    if let Some(edit_preview) = edit_preview.as_ref() {
 9957                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9958                            .first_line_preview()
 9959                    } else {
 9960                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
 9961                    };
 9962
 9963                let styled_text = gpui::StyledText::new(highlighted_edits.text)
 9964                    .with_default_highlights(&style.text, highlighted_edits.highlights);
 9965
 9966                let preview = h_flex()
 9967                    .gap_1()
 9968                    .min_w_16()
 9969                    .child(styled_text)
 9970                    .when(has_more_lines, |parent| parent.child(""));
 9971
 9972                let left = if supports_jump && first_edit_row != cursor_point.row {
 9973                    render_relative_row_jump("", cursor_point.row, first_edit_row)
 9974                        .into_any_element()
 9975                } else {
 9976                    let icon_name =
 9977                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9978                    Icon::new(icon_name).into_any_element()
 9979                };
 9980
 9981                Some(
 9982                    h_flex()
 9983                        .h_full()
 9984                        .flex_1()
 9985                        .gap_2()
 9986                        .pr_1()
 9987                        .overflow_x_hidden()
 9988                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9989                        .child(left)
 9990                        .child(preview),
 9991                )
 9992            }
 9993        }
 9994    }
 9995
 9996    pub fn render_context_menu(
 9997        &mut self,
 9998        max_height_in_lines: u32,
 9999        window: &mut Window,
10000        cx: &mut Context<Editor>,
10001    ) -> Option<AnyElement> {
10002        let menu = self.context_menu.borrow();
10003        let menu = menu.as_ref()?;
10004        if !menu.visible() {
10005            return None;
10006        };
10007        self.style
10008            .as_ref()
10009            .map(|style| menu.render(style, max_height_in_lines, window, cx))
10010    }
10011
10012    fn render_context_menu_aside(
10013        &mut self,
10014        max_size: Size<Pixels>,
10015        window: &mut Window,
10016        cx: &mut Context<Editor>,
10017    ) -> Option<AnyElement> {
10018        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
10019            if menu.visible() {
10020                menu.render_aside(max_size, window, cx)
10021            } else {
10022                None
10023            }
10024        })
10025    }
10026
10027    fn hide_context_menu(
10028        &mut self,
10029        window: &mut Window,
10030        cx: &mut Context<Self>,
10031    ) -> Option<CodeContextMenu> {
10032        cx.notify();
10033        self.completion_tasks.clear();
10034        let context_menu = self.context_menu.borrow_mut().take();
10035        self.stale_edit_prediction_in_menu.take();
10036        self.update_visible_edit_prediction(window, cx);
10037        if let Some(CodeContextMenu::Completions(_)) = &context_menu
10038            && let Some(completion_provider) = &self.completion_provider
10039        {
10040            completion_provider.selection_changed(None, window, cx);
10041        }
10042        context_menu
10043    }
10044
10045    fn show_snippet_choices(
10046        &mut self,
10047        choices: &Vec<String>,
10048        selection: Range<Anchor>,
10049        cx: &mut Context<Self>,
10050    ) {
10051        let Some((_, buffer, _)) = self
10052            .buffer()
10053            .read(cx)
10054            .excerpt_containing(selection.start, cx)
10055        else {
10056            return;
10057        };
10058        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
10059        else {
10060            return;
10061        };
10062        if buffer != end_buffer {
10063            log::error!("expected anchor range to have matching buffer IDs");
10064            return;
10065        }
10066
10067        let id = post_inc(&mut self.next_completion_id);
10068        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
10069        let mut context_menu = self.context_menu.borrow_mut();
10070        let old_menu = context_menu.take();
10071        *context_menu = Some(CodeContextMenu::Completions(
10072            CompletionsMenu::new_snippet_choices(
10073                id,
10074                true,
10075                choices,
10076                selection,
10077                buffer,
10078                old_menu.map(|menu| menu.primary_scroll_handle()),
10079                snippet_sort_order,
10080            ),
10081        ));
10082    }
10083
10084    pub fn insert_snippet(
10085        &mut self,
10086        insertion_ranges: &[Range<MultiBufferOffset>],
10087        snippet: Snippet,
10088        window: &mut Window,
10089        cx: &mut Context<Self>,
10090    ) -> Result<()> {
10091        struct Tabstop<T> {
10092            is_end_tabstop: bool,
10093            ranges: Vec<Range<T>>,
10094            choices: Option<Vec<String>>,
10095        }
10096
10097        let tabstops = self.buffer.update(cx, |buffer, cx| {
10098            let snippet_text: Arc<str> = snippet.text.clone().into();
10099            let edits = insertion_ranges
10100                .iter()
10101                .cloned()
10102                .map(|range| (range, snippet_text.clone()));
10103            let autoindent_mode = AutoindentMode::Block {
10104                original_indent_columns: Vec::new(),
10105            };
10106            buffer.edit(edits, Some(autoindent_mode), cx);
10107
10108            let snapshot = &*buffer.read(cx);
10109            let snippet = &snippet;
10110            snippet
10111                .tabstops
10112                .iter()
10113                .map(|tabstop| {
10114                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
10115                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
10116                    });
10117                    let mut tabstop_ranges = tabstop
10118                        .ranges
10119                        .iter()
10120                        .flat_map(|tabstop_range| {
10121                            let mut delta = 0_isize;
10122                            insertion_ranges.iter().map(move |insertion_range| {
10123                                let insertion_start = insertion_range.start + delta;
10124                                delta += snippet.text.len() as isize
10125                                    - (insertion_range.end - insertion_range.start) as isize;
10126
10127                                let start =
10128                                    (insertion_start + tabstop_range.start).min(snapshot.len());
10129                                let end = (insertion_start + tabstop_range.end).min(snapshot.len());
10130                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
10131                            })
10132                        })
10133                        .collect::<Vec<_>>();
10134                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
10135
10136                    Tabstop {
10137                        is_end_tabstop,
10138                        ranges: tabstop_ranges,
10139                        choices: tabstop.choices.clone(),
10140                    }
10141                })
10142                .collect::<Vec<_>>()
10143        });
10144        if let Some(tabstop) = tabstops.first() {
10145            self.change_selections(Default::default(), window, cx, |s| {
10146                // Reverse order so that the first range is the newest created selection.
10147                // Completions will use it and autoscroll will prioritize it.
10148                s.select_ranges(tabstop.ranges.iter().rev().cloned());
10149            });
10150
10151            if let Some(choices) = &tabstop.choices
10152                && let Some(selection) = tabstop.ranges.first()
10153            {
10154                self.show_snippet_choices(choices, selection.clone(), cx)
10155            }
10156
10157            // If we're already at the last tabstop and it's at the end of the snippet,
10158            // we're done, we don't need to keep the state around.
10159            if !tabstop.is_end_tabstop {
10160                let choices = tabstops
10161                    .iter()
10162                    .map(|tabstop| tabstop.choices.clone())
10163                    .collect();
10164
10165                let ranges = tabstops
10166                    .into_iter()
10167                    .map(|tabstop| tabstop.ranges)
10168                    .collect::<Vec<_>>();
10169
10170                self.snippet_stack.push(SnippetState {
10171                    active_index: 0,
10172                    ranges,
10173                    choices,
10174                });
10175            }
10176
10177            // Check whether the just-entered snippet ends with an auto-closable bracket.
10178            if self.autoclose_regions.is_empty() {
10179                let snapshot = self.buffer.read(cx).snapshot(cx);
10180                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
10181                    let selection_head = selection.head();
10182                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
10183                        continue;
10184                    };
10185
10186                    let mut bracket_pair = None;
10187                    let max_lookup_length = scope
10188                        .brackets()
10189                        .map(|(pair, _)| {
10190                            pair.start
10191                                .as_str()
10192                                .chars()
10193                                .count()
10194                                .max(pair.end.as_str().chars().count())
10195                        })
10196                        .max();
10197                    if let Some(max_lookup_length) = max_lookup_length {
10198                        let next_text = snapshot
10199                            .chars_at(selection_head)
10200                            .take(max_lookup_length)
10201                            .collect::<String>();
10202                        let prev_text = snapshot
10203                            .reversed_chars_at(selection_head)
10204                            .take(max_lookup_length)
10205                            .collect::<String>();
10206
10207                        for (pair, enabled) in scope.brackets() {
10208                            if enabled
10209                                && pair.close
10210                                && prev_text.starts_with(pair.start.as_str())
10211                                && next_text.starts_with(pair.end.as_str())
10212                            {
10213                                bracket_pair = Some(pair.clone());
10214                                break;
10215                            }
10216                        }
10217                    }
10218
10219                    if let Some(pair) = bracket_pair {
10220                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
10221                        let autoclose_enabled =
10222                            self.use_autoclose && snapshot_settings.use_autoclose;
10223                        if autoclose_enabled {
10224                            let start = snapshot.anchor_after(selection_head);
10225                            let end = snapshot.anchor_after(selection_head);
10226                            self.autoclose_regions.push(AutocloseRegion {
10227                                selection_id: selection.id,
10228                                range: start..end,
10229                                pair,
10230                            });
10231                        }
10232                    }
10233                }
10234            }
10235        }
10236        Ok(())
10237    }
10238
10239    pub fn move_to_next_snippet_tabstop(
10240        &mut self,
10241        window: &mut Window,
10242        cx: &mut Context<Self>,
10243    ) -> bool {
10244        self.move_to_snippet_tabstop(Bias::Right, window, cx)
10245    }
10246
10247    pub fn move_to_prev_snippet_tabstop(
10248        &mut self,
10249        window: &mut Window,
10250        cx: &mut Context<Self>,
10251    ) -> bool {
10252        self.move_to_snippet_tabstop(Bias::Left, window, cx)
10253    }
10254
10255    pub fn move_to_snippet_tabstop(
10256        &mut self,
10257        bias: Bias,
10258        window: &mut Window,
10259        cx: &mut Context<Self>,
10260    ) -> bool {
10261        if let Some(mut snippet) = self.snippet_stack.pop() {
10262            match bias {
10263                Bias::Left => {
10264                    if snippet.active_index > 0 {
10265                        snippet.active_index -= 1;
10266                    } else {
10267                        self.snippet_stack.push(snippet);
10268                        return false;
10269                    }
10270                }
10271                Bias::Right => {
10272                    if snippet.active_index + 1 < snippet.ranges.len() {
10273                        snippet.active_index += 1;
10274                    } else {
10275                        self.snippet_stack.push(snippet);
10276                        return false;
10277                    }
10278                }
10279            }
10280            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10281                self.change_selections(Default::default(), window, cx, |s| {
10282                    // Reverse order so that the first range is the newest created selection.
10283                    // Completions will use it and autoscroll will prioritize it.
10284                    s.select_ranges(current_ranges.iter().rev().cloned())
10285                });
10286
10287                if let Some(choices) = &snippet.choices[snippet.active_index]
10288                    && let Some(selection) = current_ranges.first()
10289                {
10290                    self.show_snippet_choices(choices, selection.clone(), cx);
10291                }
10292
10293                // If snippet state is not at the last tabstop, push it back on the stack
10294                if snippet.active_index + 1 < snippet.ranges.len() {
10295                    self.snippet_stack.push(snippet);
10296                }
10297                return true;
10298            }
10299        }
10300
10301        false
10302    }
10303
10304    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10305        self.transact(window, cx, |this, window, cx| {
10306            this.select_all(&SelectAll, window, cx);
10307            this.insert("", window, cx);
10308        });
10309    }
10310
10311    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10312        if self.read_only(cx) {
10313            return;
10314        }
10315        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10316        self.transact(window, cx, |this, window, cx| {
10317            this.select_autoclose_pair(window, cx);
10318
10319            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10320
10321            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10322            if !this.linked_edit_ranges.is_empty() {
10323                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
10324                let snapshot = this.buffer.read(cx).snapshot(cx);
10325
10326                for selection in selections.iter() {
10327                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10328                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10329                    if selection_start.buffer_id != selection_end.buffer_id {
10330                        continue;
10331                    }
10332                    if let Some(ranges) =
10333                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10334                    {
10335                        for (buffer, entries) in ranges {
10336                            linked_ranges.entry(buffer).or_default().extend(entries);
10337                        }
10338                    }
10339                }
10340            }
10341
10342            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10343            for selection in &mut selections {
10344                if selection.is_empty() {
10345                    let old_head = selection.head();
10346                    let mut new_head =
10347                        movement::left(&display_map, old_head.to_display_point(&display_map))
10348                            .to_point(&display_map);
10349                    if let Some((buffer, line_buffer_range)) = display_map
10350                        .buffer_snapshot()
10351                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10352                    {
10353                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10354                        let indent_len = match indent_size.kind {
10355                            IndentKind::Space => {
10356                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10357                            }
10358                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10359                        };
10360                        if old_head.column <= indent_size.len && old_head.column > 0 {
10361                            let indent_len = indent_len.get();
10362                            new_head = cmp::min(
10363                                new_head,
10364                                MultiBufferPoint::new(
10365                                    old_head.row,
10366                                    ((old_head.column - 1) / indent_len) * indent_len,
10367                                ),
10368                            );
10369                        }
10370                    }
10371
10372                    selection.set_head(new_head, SelectionGoal::None);
10373                }
10374            }
10375
10376            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10377            this.insert("", window, cx);
10378            let empty_str: Arc<str> = Arc::from("");
10379            for (buffer, edits) in linked_ranges {
10380                let snapshot = buffer.read(cx).snapshot();
10381                use text::ToPoint as TP;
10382
10383                let edits = edits
10384                    .into_iter()
10385                    .map(|range| {
10386                        let end_point = TP::to_point(&range.end, &snapshot);
10387                        let mut start_point = TP::to_point(&range.start, &snapshot);
10388
10389                        if end_point == start_point {
10390                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10391                                .saturating_sub(1);
10392                            start_point =
10393                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10394                        };
10395
10396                        (start_point..end_point, empty_str.clone())
10397                    })
10398                    .sorted_by_key(|(range, _)| range.start)
10399                    .collect::<Vec<_>>();
10400                buffer.update(cx, |this, cx| {
10401                    this.edit(edits, None, cx);
10402                })
10403            }
10404            this.refresh_edit_prediction(true, false, window, cx);
10405            refresh_linked_ranges(this, window, cx);
10406        });
10407    }
10408
10409    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10410        if self.read_only(cx) {
10411            return;
10412        }
10413        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10414        self.transact(window, cx, |this, window, cx| {
10415            this.change_selections(Default::default(), window, cx, |s| {
10416                s.move_with(|map, selection| {
10417                    if selection.is_empty() {
10418                        let cursor = movement::right(map, selection.head());
10419                        selection.end = cursor;
10420                        selection.reversed = true;
10421                        selection.goal = SelectionGoal::None;
10422                    }
10423                })
10424            });
10425            this.insert("", window, cx);
10426            this.refresh_edit_prediction(true, false, window, cx);
10427        });
10428    }
10429
10430    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10431        if self.mode.is_single_line() {
10432            cx.propagate();
10433            return;
10434        }
10435
10436        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10437        if self.move_to_prev_snippet_tabstop(window, cx) {
10438            return;
10439        }
10440        self.outdent(&Outdent, window, cx);
10441    }
10442
10443    pub fn next_snippet_tabstop(
10444        &mut self,
10445        _: &NextSnippetTabstop,
10446        window: &mut Window,
10447        cx: &mut Context<Self>,
10448    ) {
10449        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10450            cx.propagate();
10451            return;
10452        }
10453
10454        if self.move_to_next_snippet_tabstop(window, cx) {
10455            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10456            return;
10457        }
10458        cx.propagate();
10459    }
10460
10461    pub fn previous_snippet_tabstop(
10462        &mut self,
10463        _: &PreviousSnippetTabstop,
10464        window: &mut Window,
10465        cx: &mut Context<Self>,
10466    ) {
10467        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10468            cx.propagate();
10469            return;
10470        }
10471
10472        if self.move_to_prev_snippet_tabstop(window, cx) {
10473            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10474            return;
10475        }
10476        cx.propagate();
10477    }
10478
10479    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10480        if self.mode.is_single_line() {
10481            cx.propagate();
10482            return;
10483        }
10484
10485        if self.move_to_next_snippet_tabstop(window, cx) {
10486            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10487            return;
10488        }
10489        if self.read_only(cx) {
10490            return;
10491        }
10492        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10493        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10494        let buffer = self.buffer.read(cx);
10495        let snapshot = buffer.snapshot(cx);
10496        let rows_iter = selections.iter().map(|s| s.head().row);
10497        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10498
10499        let has_some_cursor_in_whitespace = selections
10500            .iter()
10501            .filter(|selection| selection.is_empty())
10502            .any(|selection| {
10503                let cursor = selection.head();
10504                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10505                cursor.column < current_indent.len
10506            });
10507
10508        let mut edits = Vec::new();
10509        let mut prev_edited_row = 0;
10510        let mut row_delta = 0;
10511        for selection in &mut selections {
10512            if selection.start.row != prev_edited_row {
10513                row_delta = 0;
10514            }
10515            prev_edited_row = selection.end.row;
10516
10517            // If the selection is non-empty, then increase the indentation of the selected lines.
10518            if !selection.is_empty() {
10519                row_delta =
10520                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10521                continue;
10522            }
10523
10524            let cursor = selection.head();
10525            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10526            if let Some(suggested_indent) =
10527                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10528            {
10529                // Don't do anything if already at suggested indent
10530                // and there is any other cursor which is not
10531                if has_some_cursor_in_whitespace
10532                    && cursor.column == current_indent.len
10533                    && current_indent.len == suggested_indent.len
10534                {
10535                    continue;
10536                }
10537
10538                // Adjust line and move cursor to suggested indent
10539                // if cursor is not at suggested indent
10540                if cursor.column < suggested_indent.len
10541                    && cursor.column <= current_indent.len
10542                    && current_indent.len <= suggested_indent.len
10543                {
10544                    selection.start = Point::new(cursor.row, suggested_indent.len);
10545                    selection.end = selection.start;
10546                    if row_delta == 0 {
10547                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10548                            cursor.row,
10549                            current_indent,
10550                            suggested_indent,
10551                        ));
10552                        row_delta = suggested_indent.len - current_indent.len;
10553                    }
10554                    continue;
10555                }
10556
10557                // If current indent is more than suggested indent
10558                // only move cursor to current indent and skip indent
10559                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10560                    selection.start = Point::new(cursor.row, current_indent.len);
10561                    selection.end = selection.start;
10562                    continue;
10563                }
10564            }
10565
10566            // Otherwise, insert a hard or soft tab.
10567            let settings = buffer.language_settings_at(cursor, cx);
10568            let tab_size = if settings.hard_tabs {
10569                IndentSize::tab()
10570            } else {
10571                let tab_size = settings.tab_size.get();
10572                let indent_remainder = snapshot
10573                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10574                    .flat_map(str::chars)
10575                    .fold(row_delta % tab_size, |counter: u32, c| {
10576                        if c == '\t' {
10577                            0
10578                        } else {
10579                            (counter + 1) % tab_size
10580                        }
10581                    });
10582
10583                let chars_to_next_tab_stop = tab_size - indent_remainder;
10584                IndentSize::spaces(chars_to_next_tab_stop)
10585            };
10586            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10587            selection.end = selection.start;
10588            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10589            row_delta += tab_size.len;
10590        }
10591
10592        self.transact(window, cx, |this, window, cx| {
10593            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10594            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10595            this.refresh_edit_prediction(true, false, window, cx);
10596        });
10597    }
10598
10599    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10600        if self.read_only(cx) {
10601            return;
10602        }
10603        if self.mode.is_single_line() {
10604            cx.propagate();
10605            return;
10606        }
10607
10608        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10609        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10610        let mut prev_edited_row = 0;
10611        let mut row_delta = 0;
10612        let mut edits = Vec::new();
10613        let buffer = self.buffer.read(cx);
10614        let snapshot = buffer.snapshot(cx);
10615        for selection in &mut selections {
10616            if selection.start.row != prev_edited_row {
10617                row_delta = 0;
10618            }
10619            prev_edited_row = selection.end.row;
10620
10621            row_delta =
10622                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10623        }
10624
10625        self.transact(window, cx, |this, window, cx| {
10626            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10627            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10628        });
10629    }
10630
10631    fn indent_selection(
10632        buffer: &MultiBuffer,
10633        snapshot: &MultiBufferSnapshot,
10634        selection: &mut Selection<Point>,
10635        edits: &mut Vec<(Range<Point>, String)>,
10636        delta_for_start_row: u32,
10637        cx: &App,
10638    ) -> u32 {
10639        let settings = buffer.language_settings_at(selection.start, cx);
10640        let tab_size = settings.tab_size.get();
10641        let indent_kind = if settings.hard_tabs {
10642            IndentKind::Tab
10643        } else {
10644            IndentKind::Space
10645        };
10646        let mut start_row = selection.start.row;
10647        let mut end_row = selection.end.row + 1;
10648
10649        // If a selection ends at the beginning of a line, don't indent
10650        // that last line.
10651        if selection.end.column == 0 && selection.end.row > selection.start.row {
10652            end_row -= 1;
10653        }
10654
10655        // Avoid re-indenting a row that has already been indented by a
10656        // previous selection, but still update this selection's column
10657        // to reflect that indentation.
10658        if delta_for_start_row > 0 {
10659            start_row += 1;
10660            selection.start.column += delta_for_start_row;
10661            if selection.end.row == selection.start.row {
10662                selection.end.column += delta_for_start_row;
10663            }
10664        }
10665
10666        let mut delta_for_end_row = 0;
10667        let has_multiple_rows = start_row + 1 != end_row;
10668        for row in start_row..end_row {
10669            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10670            let indent_delta = match (current_indent.kind, indent_kind) {
10671                (IndentKind::Space, IndentKind::Space) => {
10672                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10673                    IndentSize::spaces(columns_to_next_tab_stop)
10674                }
10675                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10676                (_, IndentKind::Tab) => IndentSize::tab(),
10677            };
10678
10679            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10680                0
10681            } else {
10682                selection.start.column
10683            };
10684            let row_start = Point::new(row, start);
10685            edits.push((
10686                row_start..row_start,
10687                indent_delta.chars().collect::<String>(),
10688            ));
10689
10690            // Update this selection's endpoints to reflect the indentation.
10691            if row == selection.start.row {
10692                selection.start.column += indent_delta.len;
10693            }
10694            if row == selection.end.row {
10695                selection.end.column += indent_delta.len;
10696                delta_for_end_row = indent_delta.len;
10697            }
10698        }
10699
10700        if selection.start.row == selection.end.row {
10701            delta_for_start_row + delta_for_end_row
10702        } else {
10703            delta_for_end_row
10704        }
10705    }
10706
10707    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10708        if self.read_only(cx) {
10709            return;
10710        }
10711        if self.mode.is_single_line() {
10712            cx.propagate();
10713            return;
10714        }
10715
10716        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10717        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10718        let selections = self.selections.all::<Point>(&display_map);
10719        let mut deletion_ranges = Vec::new();
10720        let mut last_outdent = None;
10721        {
10722            let buffer = self.buffer.read(cx);
10723            let snapshot = buffer.snapshot(cx);
10724            for selection in &selections {
10725                let settings = buffer.language_settings_at(selection.start, cx);
10726                let tab_size = settings.tab_size.get();
10727                let mut rows = selection.spanned_rows(false, &display_map);
10728
10729                // Avoid re-outdenting a row that has already been outdented by a
10730                // previous selection.
10731                if let Some(last_row) = last_outdent
10732                    && last_row == rows.start
10733                {
10734                    rows.start = rows.start.next_row();
10735                }
10736                let has_multiple_rows = rows.len() > 1;
10737                for row in rows.iter_rows() {
10738                    let indent_size = snapshot.indent_size_for_line(row);
10739                    if indent_size.len > 0 {
10740                        let deletion_len = match indent_size.kind {
10741                            IndentKind::Space => {
10742                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10743                                if columns_to_prev_tab_stop == 0 {
10744                                    tab_size
10745                                } else {
10746                                    columns_to_prev_tab_stop
10747                                }
10748                            }
10749                            IndentKind::Tab => 1,
10750                        };
10751                        let start = if has_multiple_rows
10752                            || deletion_len > selection.start.column
10753                            || indent_size.len < selection.start.column
10754                        {
10755                            0
10756                        } else {
10757                            selection.start.column - deletion_len
10758                        };
10759                        deletion_ranges.push(
10760                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10761                        );
10762                        last_outdent = Some(row);
10763                    }
10764                }
10765            }
10766        }
10767
10768        self.transact(window, cx, |this, window, cx| {
10769            this.buffer.update(cx, |buffer, cx| {
10770                let empty_str: Arc<str> = Arc::default();
10771                buffer.edit(
10772                    deletion_ranges
10773                        .into_iter()
10774                        .map(|range| (range, empty_str.clone())),
10775                    None,
10776                    cx,
10777                );
10778            });
10779            let selections = this
10780                .selections
10781                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10782            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10783        });
10784    }
10785
10786    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10787        if self.read_only(cx) {
10788            return;
10789        }
10790        if self.mode.is_single_line() {
10791            cx.propagate();
10792            return;
10793        }
10794
10795        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10796        let selections = self
10797            .selections
10798            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
10799            .into_iter()
10800            .map(|s| s.range());
10801
10802        self.transact(window, cx, |this, window, cx| {
10803            this.buffer.update(cx, |buffer, cx| {
10804                buffer.autoindent_ranges(selections, cx);
10805            });
10806            let selections = this
10807                .selections
10808                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10809            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10810        });
10811    }
10812
10813    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10814        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10815        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10816        let selections = self.selections.all::<Point>(&display_map);
10817
10818        let mut new_cursors = Vec::new();
10819        let mut edit_ranges = Vec::new();
10820        let mut selections = selections.iter().peekable();
10821        while let Some(selection) = selections.next() {
10822            let mut rows = selection.spanned_rows(false, &display_map);
10823
10824            // Accumulate contiguous regions of rows that we want to delete.
10825            while let Some(next_selection) = selections.peek() {
10826                let next_rows = next_selection.spanned_rows(false, &display_map);
10827                if next_rows.start <= rows.end {
10828                    rows.end = next_rows.end;
10829                    selections.next().unwrap();
10830                } else {
10831                    break;
10832                }
10833            }
10834
10835            let buffer = display_map.buffer_snapshot();
10836            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10837            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10838                // If there's a line after the range, delete the \n from the end of the row range
10839                (
10840                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10841                    rows.end,
10842                )
10843            } else {
10844                // If there isn't a line after the range, delete the \n from the line before the
10845                // start of the row range
10846                edit_start = edit_start.saturating_sub_usize(1);
10847                (buffer.len(), rows.start.previous_row())
10848            };
10849
10850            let text_layout_details = self.text_layout_details(window);
10851            let x = display_map.x_for_display_point(
10852                selection.head().to_display_point(&display_map),
10853                &text_layout_details,
10854            );
10855            let row = Point::new(target_row.0, 0)
10856                .to_display_point(&display_map)
10857                .row();
10858            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10859
10860            new_cursors.push((
10861                selection.id,
10862                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10863                SelectionGoal::None,
10864            ));
10865            edit_ranges.push(edit_start..edit_end);
10866        }
10867
10868        self.transact(window, cx, |this, window, cx| {
10869            let buffer = this.buffer.update(cx, |buffer, cx| {
10870                let empty_str: Arc<str> = Arc::default();
10871                buffer.edit(
10872                    edit_ranges
10873                        .into_iter()
10874                        .map(|range| (range, empty_str.clone())),
10875                    None,
10876                    cx,
10877                );
10878                buffer.snapshot(cx)
10879            });
10880            let new_selections = new_cursors
10881                .into_iter()
10882                .map(|(id, cursor, goal)| {
10883                    let cursor = cursor.to_point(&buffer);
10884                    Selection {
10885                        id,
10886                        start: cursor,
10887                        end: cursor,
10888                        reversed: false,
10889                        goal,
10890                    }
10891                })
10892                .collect();
10893
10894            this.change_selections(Default::default(), window, cx, |s| {
10895                s.select(new_selections);
10896            });
10897        });
10898    }
10899
10900    pub fn join_lines_impl(
10901        &mut self,
10902        insert_whitespace: bool,
10903        window: &mut Window,
10904        cx: &mut Context<Self>,
10905    ) {
10906        if self.read_only(cx) {
10907            return;
10908        }
10909        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10910        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10911            let start = MultiBufferRow(selection.start.row);
10912            // Treat single line selections as if they include the next line. Otherwise this action
10913            // would do nothing for single line selections individual cursors.
10914            let end = if selection.start.row == selection.end.row {
10915                MultiBufferRow(selection.start.row + 1)
10916            } else {
10917                MultiBufferRow(selection.end.row)
10918            };
10919
10920            if let Some(last_row_range) = row_ranges.last_mut()
10921                && start <= last_row_range.end
10922            {
10923                last_row_range.end = end;
10924                continue;
10925            }
10926            row_ranges.push(start..end);
10927        }
10928
10929        let snapshot = self.buffer.read(cx).snapshot(cx);
10930        let mut cursor_positions = Vec::new();
10931        for row_range in &row_ranges {
10932            let anchor = snapshot.anchor_before(Point::new(
10933                row_range.end.previous_row().0,
10934                snapshot.line_len(row_range.end.previous_row()),
10935            ));
10936            cursor_positions.push(anchor..anchor);
10937        }
10938
10939        self.transact(window, cx, |this, window, cx| {
10940            for row_range in row_ranges.into_iter().rev() {
10941                for row in row_range.iter_rows().rev() {
10942                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10943                    let next_line_row = row.next_row();
10944                    let indent = snapshot.indent_size_for_line(next_line_row);
10945                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10946
10947                    let replace =
10948                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10949                            " "
10950                        } else {
10951                            ""
10952                        };
10953
10954                    this.buffer.update(cx, |buffer, cx| {
10955                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10956                    });
10957                }
10958            }
10959
10960            this.change_selections(Default::default(), window, cx, |s| {
10961                s.select_anchor_ranges(cursor_positions)
10962            });
10963        });
10964    }
10965
10966    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
10967        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10968        self.join_lines_impl(true, window, cx);
10969    }
10970
10971    pub fn sort_lines_case_sensitive(
10972        &mut self,
10973        _: &SortLinesCaseSensitive,
10974        window: &mut Window,
10975        cx: &mut Context<Self>,
10976    ) {
10977        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
10978    }
10979
10980    pub fn sort_lines_by_length(
10981        &mut self,
10982        _: &SortLinesByLength,
10983        window: &mut Window,
10984        cx: &mut Context<Self>,
10985    ) {
10986        self.manipulate_immutable_lines(window, cx, |lines| {
10987            lines.sort_by_key(|&line| line.chars().count())
10988        })
10989    }
10990
10991    pub fn sort_lines_case_insensitive(
10992        &mut self,
10993        _: &SortLinesCaseInsensitive,
10994        window: &mut Window,
10995        cx: &mut Context<Self>,
10996    ) {
10997        self.manipulate_immutable_lines(window, cx, |lines| {
10998            lines.sort_by_key(|line| line.to_lowercase())
10999        })
11000    }
11001
11002    pub fn unique_lines_case_insensitive(
11003        &mut self,
11004        _: &UniqueLinesCaseInsensitive,
11005        window: &mut Window,
11006        cx: &mut Context<Self>,
11007    ) {
11008        self.manipulate_immutable_lines(window, cx, |lines| {
11009            let mut seen = HashSet::default();
11010            lines.retain(|line| seen.insert(line.to_lowercase()));
11011        })
11012    }
11013
11014    pub fn unique_lines_case_sensitive(
11015        &mut self,
11016        _: &UniqueLinesCaseSensitive,
11017        window: &mut Window,
11018        cx: &mut Context<Self>,
11019    ) {
11020        self.manipulate_immutable_lines(window, cx, |lines| {
11021            let mut seen = HashSet::default();
11022            lines.retain(|line| seen.insert(*line));
11023        })
11024    }
11025
11026    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
11027        let snapshot = self.buffer.read(cx).snapshot(cx);
11028        for selection in self.selections.disjoint_anchors_arc().iter() {
11029            if snapshot
11030                .language_at(selection.start)
11031                .and_then(|lang| lang.config().wrap_characters.as_ref())
11032                .is_some()
11033            {
11034                return true;
11035            }
11036        }
11037        false
11038    }
11039
11040    fn wrap_selections_in_tag(
11041        &mut self,
11042        _: &WrapSelectionsInTag,
11043        window: &mut Window,
11044        cx: &mut Context<Self>,
11045    ) {
11046        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11047
11048        let snapshot = self.buffer.read(cx).snapshot(cx);
11049
11050        let mut edits = Vec::new();
11051        let mut boundaries = Vec::new();
11052
11053        for selection in self
11054            .selections
11055            .all_adjusted(&self.display_snapshot(cx))
11056            .iter()
11057        {
11058            let Some(wrap_config) = snapshot
11059                .language_at(selection.start)
11060                .and_then(|lang| lang.config().wrap_characters.clone())
11061            else {
11062                continue;
11063            };
11064
11065            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
11066            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
11067
11068            let start_before = snapshot.anchor_before(selection.start);
11069            let end_after = snapshot.anchor_after(selection.end);
11070
11071            edits.push((start_before..start_before, open_tag));
11072            edits.push((end_after..end_after, close_tag));
11073
11074            boundaries.push((
11075                start_before,
11076                end_after,
11077                wrap_config.start_prefix.len(),
11078                wrap_config.end_suffix.len(),
11079            ));
11080        }
11081
11082        if edits.is_empty() {
11083            return;
11084        }
11085
11086        self.transact(window, cx, |this, window, cx| {
11087            let buffer = this.buffer.update(cx, |buffer, cx| {
11088                buffer.edit(edits, None, cx);
11089                buffer.snapshot(cx)
11090            });
11091
11092            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
11093            for (start_before, end_after, start_prefix_len, end_suffix_len) in
11094                boundaries.into_iter()
11095            {
11096                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
11097                let close_offset = end_after
11098                    .to_offset(&buffer)
11099                    .saturating_sub_usize(end_suffix_len);
11100                new_selections.push(open_offset..open_offset);
11101                new_selections.push(close_offset..close_offset);
11102            }
11103
11104            this.change_selections(Default::default(), window, cx, |s| {
11105                s.select_ranges(new_selections);
11106            });
11107
11108            this.request_autoscroll(Autoscroll::fit(), cx);
11109        });
11110    }
11111
11112    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
11113        let Some(project) = self.project.clone() else {
11114            return;
11115        };
11116        self.reload(project, window, cx)
11117            .detach_and_notify_err(window, cx);
11118    }
11119
11120    pub fn restore_file(
11121        &mut self,
11122        _: &::git::RestoreFile,
11123        window: &mut Window,
11124        cx: &mut Context<Self>,
11125    ) {
11126        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11127        let mut buffer_ids = HashSet::default();
11128        let snapshot = self.buffer().read(cx).snapshot(cx);
11129        for selection in self
11130            .selections
11131            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
11132        {
11133            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
11134        }
11135
11136        let buffer = self.buffer().read(cx);
11137        let ranges = buffer_ids
11138            .into_iter()
11139            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
11140            .collect::<Vec<_>>();
11141
11142        self.restore_hunks_in_ranges(ranges, window, cx);
11143    }
11144
11145    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
11146        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11147        let selections = self
11148            .selections
11149            .all(&self.display_snapshot(cx))
11150            .into_iter()
11151            .map(|s| s.range())
11152            .collect();
11153        self.restore_hunks_in_ranges(selections, window, cx);
11154    }
11155
11156    pub fn restore_hunks_in_ranges(
11157        &mut self,
11158        ranges: Vec<Range<Point>>,
11159        window: &mut Window,
11160        cx: &mut Context<Editor>,
11161    ) {
11162        let mut revert_changes = HashMap::default();
11163        let chunk_by = self
11164            .snapshot(window, cx)
11165            .hunks_for_ranges(ranges)
11166            .into_iter()
11167            .chunk_by(|hunk| hunk.buffer_id);
11168        for (buffer_id, hunks) in &chunk_by {
11169            let hunks = hunks.collect::<Vec<_>>();
11170            for hunk in &hunks {
11171                self.prepare_restore_change(&mut revert_changes, hunk, cx);
11172            }
11173            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
11174        }
11175        drop(chunk_by);
11176        if !revert_changes.is_empty() {
11177            self.transact(window, cx, |editor, window, cx| {
11178                editor.restore(revert_changes, window, cx);
11179            });
11180        }
11181    }
11182
11183    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
11184        if let Some(status) = self
11185            .addons
11186            .iter()
11187            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
11188        {
11189            return Some(status);
11190        }
11191        self.project
11192            .as_ref()?
11193            .read(cx)
11194            .status_for_buffer_id(buffer_id, cx)
11195    }
11196
11197    pub fn open_active_item_in_terminal(
11198        &mut self,
11199        _: &OpenInTerminal,
11200        window: &mut Window,
11201        cx: &mut Context<Self>,
11202    ) {
11203        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
11204            let project_path = buffer.read(cx).project_path(cx)?;
11205            let project = self.project()?.read(cx);
11206            let entry = project.entry_for_path(&project_path, cx)?;
11207            let parent = match &entry.canonical_path {
11208                Some(canonical_path) => canonical_path.to_path_buf(),
11209                None => project.absolute_path(&project_path, cx)?,
11210            }
11211            .parent()?
11212            .to_path_buf();
11213            Some(parent)
11214        }) {
11215            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
11216        }
11217    }
11218
11219    fn set_breakpoint_context_menu(
11220        &mut self,
11221        display_row: DisplayRow,
11222        position: Option<Anchor>,
11223        clicked_point: gpui::Point<Pixels>,
11224        window: &mut Window,
11225        cx: &mut Context<Self>,
11226    ) {
11227        let source = self
11228            .buffer
11229            .read(cx)
11230            .snapshot(cx)
11231            .anchor_before(Point::new(display_row.0, 0u32));
11232
11233        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
11234
11235        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
11236            self,
11237            source,
11238            clicked_point,
11239            context_menu,
11240            window,
11241            cx,
11242        );
11243    }
11244
11245    fn add_edit_breakpoint_block(
11246        &mut self,
11247        anchor: Anchor,
11248        breakpoint: &Breakpoint,
11249        edit_action: BreakpointPromptEditAction,
11250        window: &mut Window,
11251        cx: &mut Context<Self>,
11252    ) {
11253        let weak_editor = cx.weak_entity();
11254        let bp_prompt = cx.new(|cx| {
11255            BreakpointPromptEditor::new(
11256                weak_editor,
11257                anchor,
11258                breakpoint.clone(),
11259                edit_action,
11260                window,
11261                cx,
11262            )
11263        });
11264
11265        let height = bp_prompt.update(cx, |this, cx| {
11266            this.prompt
11267                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
11268        });
11269        let cloned_prompt = bp_prompt.clone();
11270        let blocks = vec![BlockProperties {
11271            style: BlockStyle::Sticky,
11272            placement: BlockPlacement::Above(anchor),
11273            height: Some(height),
11274            render: Arc::new(move |cx| {
11275                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
11276                cloned_prompt.clone().into_any_element()
11277            }),
11278            priority: 0,
11279        }];
11280
11281        let focus_handle = bp_prompt.focus_handle(cx);
11282        window.focus(&focus_handle);
11283
11284        let block_ids = self.insert_blocks(blocks, None, cx);
11285        bp_prompt.update(cx, |prompt, _| {
11286            prompt.add_block_ids(block_ids);
11287        });
11288    }
11289
11290    pub(crate) fn breakpoint_at_row(
11291        &self,
11292        row: u32,
11293        window: &mut Window,
11294        cx: &mut Context<Self>,
11295    ) -> Option<(Anchor, Breakpoint)> {
11296        let snapshot = self.snapshot(window, cx);
11297        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11298
11299        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11300    }
11301
11302    pub(crate) fn breakpoint_at_anchor(
11303        &self,
11304        breakpoint_position: Anchor,
11305        snapshot: &EditorSnapshot,
11306        cx: &mut Context<Self>,
11307    ) -> Option<(Anchor, Breakpoint)> {
11308        let buffer = self
11309            .buffer
11310            .read(cx)
11311            .buffer_for_anchor(breakpoint_position, cx)?;
11312
11313        let enclosing_excerpt = breakpoint_position.excerpt_id;
11314        let buffer_snapshot = buffer.read(cx).snapshot();
11315
11316        let row = buffer_snapshot
11317            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11318            .row;
11319
11320        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11321        let anchor_end = snapshot
11322            .buffer_snapshot()
11323            .anchor_after(Point::new(row, line_len));
11324
11325        self.breakpoint_store
11326            .as_ref()?
11327            .read_with(cx, |breakpoint_store, cx| {
11328                breakpoint_store
11329                    .breakpoints(
11330                        &buffer,
11331                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11332                        &buffer_snapshot,
11333                        cx,
11334                    )
11335                    .next()
11336                    .and_then(|(bp, _)| {
11337                        let breakpoint_row = buffer_snapshot
11338                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11339                            .row;
11340
11341                        if breakpoint_row == row {
11342                            snapshot
11343                                .buffer_snapshot()
11344                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11345                                .map(|position| (position, bp.bp.clone()))
11346                        } else {
11347                            None
11348                        }
11349                    })
11350            })
11351    }
11352
11353    pub fn edit_log_breakpoint(
11354        &mut self,
11355        _: &EditLogBreakpoint,
11356        window: &mut Window,
11357        cx: &mut Context<Self>,
11358    ) {
11359        if self.breakpoint_store.is_none() {
11360            return;
11361        }
11362
11363        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11364            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11365                message: None,
11366                state: BreakpointState::Enabled,
11367                condition: None,
11368                hit_condition: None,
11369            });
11370
11371            self.add_edit_breakpoint_block(
11372                anchor,
11373                &breakpoint,
11374                BreakpointPromptEditAction::Log,
11375                window,
11376                cx,
11377            );
11378        }
11379    }
11380
11381    fn breakpoints_at_cursors(
11382        &self,
11383        window: &mut Window,
11384        cx: &mut Context<Self>,
11385    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11386        let snapshot = self.snapshot(window, cx);
11387        let cursors = self
11388            .selections
11389            .disjoint_anchors_arc()
11390            .iter()
11391            .map(|selection| {
11392                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11393
11394                let breakpoint_position = self
11395                    .breakpoint_at_row(cursor_position.row, window, cx)
11396                    .map(|bp| bp.0)
11397                    .unwrap_or_else(|| {
11398                        snapshot
11399                            .display_snapshot
11400                            .buffer_snapshot()
11401                            .anchor_after(Point::new(cursor_position.row, 0))
11402                    });
11403
11404                let breakpoint = self
11405                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11406                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11407
11408                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11409            })
11410            // 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.
11411            .collect::<HashMap<Anchor, _>>();
11412
11413        cursors.into_iter().collect()
11414    }
11415
11416    pub fn enable_breakpoint(
11417        &mut self,
11418        _: &crate::actions::EnableBreakpoint,
11419        window: &mut Window,
11420        cx: &mut Context<Self>,
11421    ) {
11422        if self.breakpoint_store.is_none() {
11423            return;
11424        }
11425
11426        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11427            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11428                continue;
11429            };
11430            self.edit_breakpoint_at_anchor(
11431                anchor,
11432                breakpoint,
11433                BreakpointEditAction::InvertState,
11434                cx,
11435            );
11436        }
11437    }
11438
11439    pub fn disable_breakpoint(
11440        &mut self,
11441        _: &crate::actions::DisableBreakpoint,
11442        window: &mut Window,
11443        cx: &mut Context<Self>,
11444    ) {
11445        if self.breakpoint_store.is_none() {
11446            return;
11447        }
11448
11449        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11450            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11451                continue;
11452            };
11453            self.edit_breakpoint_at_anchor(
11454                anchor,
11455                breakpoint,
11456                BreakpointEditAction::InvertState,
11457                cx,
11458            );
11459        }
11460    }
11461
11462    pub fn toggle_breakpoint(
11463        &mut self,
11464        _: &crate::actions::ToggleBreakpoint,
11465        window: &mut Window,
11466        cx: &mut Context<Self>,
11467    ) {
11468        if self.breakpoint_store.is_none() {
11469            return;
11470        }
11471
11472        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11473            if let Some(breakpoint) = breakpoint {
11474                self.edit_breakpoint_at_anchor(
11475                    anchor,
11476                    breakpoint,
11477                    BreakpointEditAction::Toggle,
11478                    cx,
11479                );
11480            } else {
11481                self.edit_breakpoint_at_anchor(
11482                    anchor,
11483                    Breakpoint::new_standard(),
11484                    BreakpointEditAction::Toggle,
11485                    cx,
11486                );
11487            }
11488        }
11489    }
11490
11491    pub fn edit_breakpoint_at_anchor(
11492        &mut self,
11493        breakpoint_position: Anchor,
11494        breakpoint: Breakpoint,
11495        edit_action: BreakpointEditAction,
11496        cx: &mut Context<Self>,
11497    ) {
11498        let Some(breakpoint_store) = &self.breakpoint_store else {
11499            return;
11500        };
11501
11502        let Some(buffer) = self
11503            .buffer
11504            .read(cx)
11505            .buffer_for_anchor(breakpoint_position, cx)
11506        else {
11507            return;
11508        };
11509
11510        breakpoint_store.update(cx, |breakpoint_store, cx| {
11511            breakpoint_store.toggle_breakpoint(
11512                buffer,
11513                BreakpointWithPosition {
11514                    position: breakpoint_position.text_anchor,
11515                    bp: breakpoint,
11516                },
11517                edit_action,
11518                cx,
11519            );
11520        });
11521
11522        cx.notify();
11523    }
11524
11525    #[cfg(any(test, feature = "test-support"))]
11526    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11527        self.breakpoint_store.clone()
11528    }
11529
11530    pub fn prepare_restore_change(
11531        &self,
11532        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11533        hunk: &MultiBufferDiffHunk,
11534        cx: &mut App,
11535    ) -> Option<()> {
11536        if hunk.is_created_file() {
11537            return None;
11538        }
11539        let buffer = self.buffer.read(cx);
11540        let diff = buffer.diff_for(hunk.buffer_id)?;
11541        let buffer = buffer.buffer(hunk.buffer_id)?;
11542        let buffer = buffer.read(cx);
11543        let original_text = diff
11544            .read(cx)
11545            .base_text()
11546            .as_rope()
11547            .slice(hunk.diff_base_byte_range.start.0..hunk.diff_base_byte_range.end.0);
11548        let buffer_snapshot = buffer.snapshot();
11549        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11550        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11551            probe
11552                .0
11553                .start
11554                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11555                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11556        }) {
11557            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11558            Some(())
11559        } else {
11560            None
11561        }
11562    }
11563
11564    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11565        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11566    }
11567
11568    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11569        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11570    }
11571
11572    pub fn rotate_selections_forward(
11573        &mut self,
11574        _: &RotateSelectionsForward,
11575        window: &mut Window,
11576        cx: &mut Context<Self>,
11577    ) {
11578        self.rotate_selections(window, cx, false)
11579    }
11580
11581    pub fn rotate_selections_backward(
11582        &mut self,
11583        _: &RotateSelectionsBackward,
11584        window: &mut Window,
11585        cx: &mut Context<Self>,
11586    ) {
11587        self.rotate_selections(window, cx, true)
11588    }
11589
11590    fn rotate_selections(&mut self, window: &mut Window, cx: &mut Context<Self>, reverse: bool) {
11591        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11592        let display_snapshot = self.display_snapshot(cx);
11593        let selections = self.selections.all::<MultiBufferOffset>(&display_snapshot);
11594
11595        if selections.len() < 2 {
11596            return;
11597        }
11598
11599        let (edits, new_selections) = {
11600            let buffer = self.buffer.read(cx).read(cx);
11601            let has_selections = selections.iter().any(|s| !s.is_empty());
11602            if has_selections {
11603                let mut selected_texts: Vec<String> = selections
11604                    .iter()
11605                    .map(|selection| {
11606                        buffer
11607                            .text_for_range(selection.start..selection.end)
11608                            .collect()
11609                    })
11610                    .collect();
11611
11612                if reverse {
11613                    selected_texts.rotate_left(1);
11614                } else {
11615                    selected_texts.rotate_right(1);
11616                }
11617
11618                let mut offset_delta: i64 = 0;
11619                let mut new_selections = Vec::new();
11620                let edits: Vec<_> = selections
11621                    .iter()
11622                    .zip(selected_texts.iter())
11623                    .map(|(selection, new_text)| {
11624                        let old_len = (selection.end.0 - selection.start.0) as i64;
11625                        let new_len = new_text.len() as i64;
11626                        let adjusted_start =
11627                            MultiBufferOffset((selection.start.0 as i64 + offset_delta) as usize);
11628                        let adjusted_end =
11629                            MultiBufferOffset((adjusted_start.0 as i64 + new_len) as usize);
11630
11631                        new_selections.push(Selection {
11632                            id: selection.id,
11633                            start: adjusted_start,
11634                            end: adjusted_end,
11635                            reversed: selection.reversed,
11636                            goal: selection.goal,
11637                        });
11638
11639                        offset_delta += new_len - old_len;
11640                        (selection.start..selection.end, new_text.clone())
11641                    })
11642                    .collect();
11643                (edits, new_selections)
11644            } else {
11645                let mut all_rows: Vec<u32> = selections
11646                    .iter()
11647                    .map(|selection| buffer.offset_to_point(selection.start).row)
11648                    .collect();
11649                all_rows.sort_unstable();
11650                all_rows.dedup();
11651
11652                if all_rows.len() < 2 {
11653                    return;
11654                }
11655
11656                let line_ranges: Vec<Range<MultiBufferOffset>> = all_rows
11657                    .iter()
11658                    .map(|&row| {
11659                        let start = Point::new(row, 0);
11660                        let end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11661                        buffer.point_to_offset(start)..buffer.point_to_offset(end)
11662                    })
11663                    .collect();
11664
11665                let mut line_texts: Vec<String> = line_ranges
11666                    .iter()
11667                    .map(|range| buffer.text_for_range(range.clone()).collect())
11668                    .collect();
11669
11670                if reverse {
11671                    line_texts.rotate_left(1);
11672                } else {
11673                    line_texts.rotate_right(1);
11674                }
11675
11676                let edits = line_ranges
11677                    .iter()
11678                    .zip(line_texts.iter())
11679                    .map(|(range, new_text)| (range.clone(), new_text.clone()))
11680                    .collect();
11681
11682                let num_rows = all_rows.len();
11683                let row_to_index: std::collections::HashMap<u32, usize> = all_rows
11684                    .iter()
11685                    .enumerate()
11686                    .map(|(i, &row)| (row, i))
11687                    .collect();
11688
11689                // Compute new line start offsets after rotation (handles CRLF)
11690                let newline_len = line_ranges[1].start.0 - line_ranges[0].end.0;
11691                let first_line_start = line_ranges[0].start.0;
11692                let mut new_line_starts: Vec<usize> = vec![first_line_start];
11693                for text in line_texts.iter().take(num_rows - 1) {
11694                    let prev_start = *new_line_starts.last().unwrap();
11695                    new_line_starts.push(prev_start + text.len() + newline_len);
11696                }
11697
11698                let new_selections = selections
11699                    .iter()
11700                    .map(|selection| {
11701                        let point = buffer.offset_to_point(selection.start);
11702                        let old_index = row_to_index[&point.row];
11703                        let new_index = if reverse {
11704                            (old_index + num_rows - 1) % num_rows
11705                        } else {
11706                            (old_index + 1) % num_rows
11707                        };
11708                        let new_offset =
11709                            MultiBufferOffset(new_line_starts[new_index] + point.column as usize);
11710                        Selection {
11711                            id: selection.id,
11712                            start: new_offset,
11713                            end: new_offset,
11714                            reversed: selection.reversed,
11715                            goal: selection.goal,
11716                        }
11717                    })
11718                    .collect();
11719
11720                (edits, new_selections)
11721            }
11722        };
11723
11724        self.transact(window, cx, |this, window, cx| {
11725            this.buffer.update(cx, |buffer, cx| {
11726                buffer.edit(edits, None, cx);
11727            });
11728            this.change_selections(Default::default(), window, cx, |s| {
11729                s.select(new_selections);
11730            });
11731        });
11732    }
11733
11734    fn manipulate_lines<M>(
11735        &mut self,
11736        window: &mut Window,
11737        cx: &mut Context<Self>,
11738        mut manipulate: M,
11739    ) where
11740        M: FnMut(&str) -> LineManipulationResult,
11741    {
11742        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11743
11744        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11745        let buffer = self.buffer.read(cx).snapshot(cx);
11746
11747        let mut edits = Vec::new();
11748
11749        let selections = self.selections.all::<Point>(&display_map);
11750        let mut selections = selections.iter().peekable();
11751        let mut contiguous_row_selections = Vec::new();
11752        let mut new_selections = Vec::new();
11753        let mut added_lines = 0;
11754        let mut removed_lines = 0;
11755
11756        while let Some(selection) = selections.next() {
11757            let (start_row, end_row) = consume_contiguous_rows(
11758                &mut contiguous_row_selections,
11759                selection,
11760                &display_map,
11761                &mut selections,
11762            );
11763
11764            let start_point = Point::new(start_row.0, 0);
11765            let end_point = Point::new(
11766                end_row.previous_row().0,
11767                buffer.line_len(end_row.previous_row()),
11768            );
11769            let text = buffer
11770                .text_for_range(start_point..end_point)
11771                .collect::<String>();
11772
11773            let LineManipulationResult {
11774                new_text,
11775                line_count_before,
11776                line_count_after,
11777            } = manipulate(&text);
11778
11779            edits.push((start_point..end_point, new_text));
11780
11781            // Selections must change based on added and removed line count
11782            let start_row =
11783                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11784            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11785            new_selections.push(Selection {
11786                id: selection.id,
11787                start: start_row,
11788                end: end_row,
11789                goal: SelectionGoal::None,
11790                reversed: selection.reversed,
11791            });
11792
11793            if line_count_after > line_count_before {
11794                added_lines += line_count_after - line_count_before;
11795            } else if line_count_before > line_count_after {
11796                removed_lines += line_count_before - line_count_after;
11797            }
11798        }
11799
11800        self.transact(window, cx, |this, window, cx| {
11801            let buffer = this.buffer.update(cx, |buffer, cx| {
11802                buffer.edit(edits, None, cx);
11803                buffer.snapshot(cx)
11804            });
11805
11806            // Recalculate offsets on newly edited buffer
11807            let new_selections = new_selections
11808                .iter()
11809                .map(|s| {
11810                    let start_point = Point::new(s.start.0, 0);
11811                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11812                    Selection {
11813                        id: s.id,
11814                        start: buffer.point_to_offset(start_point),
11815                        end: buffer.point_to_offset(end_point),
11816                        goal: s.goal,
11817                        reversed: s.reversed,
11818                    }
11819                })
11820                .collect();
11821
11822            this.change_selections(Default::default(), window, cx, |s| {
11823                s.select(new_selections);
11824            });
11825
11826            this.request_autoscroll(Autoscroll::fit(), cx);
11827        });
11828    }
11829
11830    fn manipulate_immutable_lines<Fn>(
11831        &mut self,
11832        window: &mut Window,
11833        cx: &mut Context<Self>,
11834        mut callback: Fn,
11835    ) where
11836        Fn: FnMut(&mut Vec<&str>),
11837    {
11838        self.manipulate_lines(window, cx, |text| {
11839            let mut lines: Vec<&str> = text.split('\n').collect();
11840            let line_count_before = lines.len();
11841
11842            callback(&mut lines);
11843
11844            LineManipulationResult {
11845                new_text: lines.join("\n"),
11846                line_count_before,
11847                line_count_after: lines.len(),
11848            }
11849        });
11850    }
11851
11852    fn manipulate_mutable_lines<Fn>(
11853        &mut self,
11854        window: &mut Window,
11855        cx: &mut Context<Self>,
11856        mut callback: Fn,
11857    ) where
11858        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11859    {
11860        self.manipulate_lines(window, cx, |text| {
11861            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11862            let line_count_before = lines.len();
11863
11864            callback(&mut lines);
11865
11866            LineManipulationResult {
11867                new_text: lines.join("\n"),
11868                line_count_before,
11869                line_count_after: lines.len(),
11870            }
11871        });
11872    }
11873
11874    pub fn convert_indentation_to_spaces(
11875        &mut self,
11876        _: &ConvertIndentationToSpaces,
11877        window: &mut Window,
11878        cx: &mut Context<Self>,
11879    ) {
11880        let settings = self.buffer.read(cx).language_settings(cx);
11881        let tab_size = settings.tab_size.get() as usize;
11882
11883        self.manipulate_mutable_lines(window, cx, |lines| {
11884            // Allocates a reasonably sized scratch buffer once for the whole loop
11885            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11886            // Avoids recomputing spaces that could be inserted many times
11887            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11888                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11889                .collect();
11890
11891            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11892                let mut chars = line.as_ref().chars();
11893                let mut col = 0;
11894                let mut changed = false;
11895
11896                for ch in chars.by_ref() {
11897                    match ch {
11898                        ' ' => {
11899                            reindented_line.push(' ');
11900                            col += 1;
11901                        }
11902                        '\t' => {
11903                            // \t are converted to spaces depending on the current column
11904                            let spaces_len = tab_size - (col % tab_size);
11905                            reindented_line.extend(&space_cache[spaces_len - 1]);
11906                            col += spaces_len;
11907                            changed = true;
11908                        }
11909                        _ => {
11910                            // If we dont append before break, the character is consumed
11911                            reindented_line.push(ch);
11912                            break;
11913                        }
11914                    }
11915                }
11916
11917                if !changed {
11918                    reindented_line.clear();
11919                    continue;
11920                }
11921                // Append the rest of the line and replace old reference with new one
11922                reindented_line.extend(chars);
11923                *line = Cow::Owned(reindented_line.clone());
11924                reindented_line.clear();
11925            }
11926        });
11927    }
11928
11929    pub fn convert_indentation_to_tabs(
11930        &mut self,
11931        _: &ConvertIndentationToTabs,
11932        window: &mut Window,
11933        cx: &mut Context<Self>,
11934    ) {
11935        let settings = self.buffer.read(cx).language_settings(cx);
11936        let tab_size = settings.tab_size.get() as usize;
11937
11938        self.manipulate_mutable_lines(window, cx, |lines| {
11939            // Allocates a reasonably sized buffer once for the whole loop
11940            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11941            // Avoids recomputing spaces that could be inserted many times
11942            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11943                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11944                .collect();
11945
11946            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11947                let mut chars = line.chars();
11948                let mut spaces_count = 0;
11949                let mut first_non_indent_char = None;
11950                let mut changed = false;
11951
11952                for ch in chars.by_ref() {
11953                    match ch {
11954                        ' ' => {
11955                            // Keep track of spaces. Append \t when we reach tab_size
11956                            spaces_count += 1;
11957                            changed = true;
11958                            if spaces_count == tab_size {
11959                                reindented_line.push('\t');
11960                                spaces_count = 0;
11961                            }
11962                        }
11963                        '\t' => {
11964                            reindented_line.push('\t');
11965                            spaces_count = 0;
11966                        }
11967                        _ => {
11968                            // Dont append it yet, we might have remaining spaces
11969                            first_non_indent_char = Some(ch);
11970                            break;
11971                        }
11972                    }
11973                }
11974
11975                if !changed {
11976                    reindented_line.clear();
11977                    continue;
11978                }
11979                // Remaining spaces that didn't make a full tab stop
11980                if spaces_count > 0 {
11981                    reindented_line.extend(&space_cache[spaces_count - 1]);
11982                }
11983                // If we consume an extra character that was not indentation, add it back
11984                if let Some(extra_char) = first_non_indent_char {
11985                    reindented_line.push(extra_char);
11986                }
11987                // Append the rest of the line and replace old reference with new one
11988                reindented_line.extend(chars);
11989                *line = Cow::Owned(reindented_line.clone());
11990                reindented_line.clear();
11991            }
11992        });
11993    }
11994
11995    pub fn convert_to_upper_case(
11996        &mut self,
11997        _: &ConvertToUpperCase,
11998        window: &mut Window,
11999        cx: &mut Context<Self>,
12000    ) {
12001        self.manipulate_text(window, cx, |text| text.to_uppercase())
12002    }
12003
12004    pub fn convert_to_lower_case(
12005        &mut self,
12006        _: &ConvertToLowerCase,
12007        window: &mut Window,
12008        cx: &mut Context<Self>,
12009    ) {
12010        self.manipulate_text(window, cx, |text| text.to_lowercase())
12011    }
12012
12013    pub fn convert_to_title_case(
12014        &mut self,
12015        _: &ConvertToTitleCase,
12016        window: &mut Window,
12017        cx: &mut Context<Self>,
12018    ) {
12019        self.manipulate_text(window, cx, |text| {
12020            text.split('\n')
12021                .map(|line| line.to_case(Case::Title))
12022                .join("\n")
12023        })
12024    }
12025
12026    pub fn convert_to_snake_case(
12027        &mut self,
12028        _: &ConvertToSnakeCase,
12029        window: &mut Window,
12030        cx: &mut Context<Self>,
12031    ) {
12032        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
12033    }
12034
12035    pub fn convert_to_kebab_case(
12036        &mut self,
12037        _: &ConvertToKebabCase,
12038        window: &mut Window,
12039        cx: &mut Context<Self>,
12040    ) {
12041        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
12042    }
12043
12044    pub fn convert_to_upper_camel_case(
12045        &mut self,
12046        _: &ConvertToUpperCamelCase,
12047        window: &mut Window,
12048        cx: &mut Context<Self>,
12049    ) {
12050        self.manipulate_text(window, cx, |text| {
12051            text.split('\n')
12052                .map(|line| line.to_case(Case::UpperCamel))
12053                .join("\n")
12054        })
12055    }
12056
12057    pub fn convert_to_lower_camel_case(
12058        &mut self,
12059        _: &ConvertToLowerCamelCase,
12060        window: &mut Window,
12061        cx: &mut Context<Self>,
12062    ) {
12063        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
12064    }
12065
12066    pub fn convert_to_opposite_case(
12067        &mut self,
12068        _: &ConvertToOppositeCase,
12069        window: &mut Window,
12070        cx: &mut Context<Self>,
12071    ) {
12072        self.manipulate_text(window, cx, |text| {
12073            text.chars()
12074                .fold(String::with_capacity(text.len()), |mut t, c| {
12075                    if c.is_uppercase() {
12076                        t.extend(c.to_lowercase());
12077                    } else {
12078                        t.extend(c.to_uppercase());
12079                    }
12080                    t
12081                })
12082        })
12083    }
12084
12085    pub fn convert_to_sentence_case(
12086        &mut self,
12087        _: &ConvertToSentenceCase,
12088        window: &mut Window,
12089        cx: &mut Context<Self>,
12090    ) {
12091        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
12092    }
12093
12094    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
12095        self.manipulate_text(window, cx, |text| {
12096            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
12097            if has_upper_case_characters {
12098                text.to_lowercase()
12099            } else {
12100                text.to_uppercase()
12101            }
12102        })
12103    }
12104
12105    pub fn convert_to_rot13(
12106        &mut self,
12107        _: &ConvertToRot13,
12108        window: &mut Window,
12109        cx: &mut Context<Self>,
12110    ) {
12111        self.manipulate_text(window, cx, |text| {
12112            text.chars()
12113                .map(|c| match c {
12114                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
12115                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
12116                    _ => c,
12117                })
12118                .collect()
12119        })
12120    }
12121
12122    pub fn convert_to_rot47(
12123        &mut self,
12124        _: &ConvertToRot47,
12125        window: &mut Window,
12126        cx: &mut Context<Self>,
12127    ) {
12128        self.manipulate_text(window, cx, |text| {
12129            text.chars()
12130                .map(|c| {
12131                    let code_point = c as u32;
12132                    if code_point >= 33 && code_point <= 126 {
12133                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
12134                    }
12135                    c
12136                })
12137                .collect()
12138        })
12139    }
12140
12141    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
12142    where
12143        Fn: FnMut(&str) -> String,
12144    {
12145        let buffer = self.buffer.read(cx).snapshot(cx);
12146
12147        let mut new_selections = Vec::new();
12148        let mut edits = Vec::new();
12149        let mut selection_adjustment = 0isize;
12150
12151        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
12152            let selection_is_empty = selection.is_empty();
12153
12154            let (start, end) = if selection_is_empty {
12155                let (word_range, _) = buffer.surrounding_word(selection.start, None);
12156                (word_range.start, word_range.end)
12157            } else {
12158                (
12159                    buffer.point_to_offset(selection.start),
12160                    buffer.point_to_offset(selection.end),
12161                )
12162            };
12163
12164            let text = buffer.text_for_range(start..end).collect::<String>();
12165            let old_length = text.len() as isize;
12166            let text = callback(&text);
12167
12168            new_selections.push(Selection {
12169                start: MultiBufferOffset((start.0 as isize - selection_adjustment) as usize),
12170                end: MultiBufferOffset(
12171                    ((start.0 + text.len()) as isize - selection_adjustment) as usize,
12172                ),
12173                goal: SelectionGoal::None,
12174                id: selection.id,
12175                reversed: selection.reversed,
12176            });
12177
12178            selection_adjustment += old_length - text.len() as isize;
12179
12180            edits.push((start..end, text));
12181        }
12182
12183        self.transact(window, cx, |this, window, cx| {
12184            this.buffer.update(cx, |buffer, cx| {
12185                buffer.edit(edits, None, cx);
12186            });
12187
12188            this.change_selections(Default::default(), window, cx, |s| {
12189                s.select(new_selections);
12190            });
12191
12192            this.request_autoscroll(Autoscroll::fit(), cx);
12193        });
12194    }
12195
12196    pub fn move_selection_on_drop(
12197        &mut self,
12198        selection: &Selection<Anchor>,
12199        target: DisplayPoint,
12200        is_cut: bool,
12201        window: &mut Window,
12202        cx: &mut Context<Self>,
12203    ) {
12204        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12205        let buffer = display_map.buffer_snapshot();
12206        let mut edits = Vec::new();
12207        let insert_point = display_map
12208            .clip_point(target, Bias::Left)
12209            .to_point(&display_map);
12210        let text = buffer
12211            .text_for_range(selection.start..selection.end)
12212            .collect::<String>();
12213        if is_cut {
12214            edits.push(((selection.start..selection.end), String::new()));
12215        }
12216        let insert_anchor = buffer.anchor_before(insert_point);
12217        edits.push(((insert_anchor..insert_anchor), text));
12218        let last_edit_start = insert_anchor.bias_left(buffer);
12219        let last_edit_end = insert_anchor.bias_right(buffer);
12220        self.transact(window, cx, |this, window, cx| {
12221            this.buffer.update(cx, |buffer, cx| {
12222                buffer.edit(edits, None, cx);
12223            });
12224            this.change_selections(Default::default(), window, cx, |s| {
12225                s.select_anchor_ranges([last_edit_start..last_edit_end]);
12226            });
12227        });
12228    }
12229
12230    pub fn clear_selection_drag_state(&mut self) {
12231        self.selection_drag_state = SelectionDragState::None;
12232    }
12233
12234    pub fn duplicate(
12235        &mut self,
12236        upwards: bool,
12237        whole_lines: bool,
12238        window: &mut Window,
12239        cx: &mut Context<Self>,
12240    ) {
12241        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12242
12243        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12244        let buffer = display_map.buffer_snapshot();
12245        let selections = self.selections.all::<Point>(&display_map);
12246
12247        let mut edits = Vec::new();
12248        let mut selections_iter = selections.iter().peekable();
12249        while let Some(selection) = selections_iter.next() {
12250            let mut rows = selection.spanned_rows(false, &display_map);
12251            // duplicate line-wise
12252            if whole_lines || selection.start == selection.end {
12253                // Avoid duplicating the same lines twice.
12254                while let Some(next_selection) = selections_iter.peek() {
12255                    let next_rows = next_selection.spanned_rows(false, &display_map);
12256                    if next_rows.start < rows.end {
12257                        rows.end = next_rows.end;
12258                        selections_iter.next().unwrap();
12259                    } else {
12260                        break;
12261                    }
12262                }
12263
12264                // Copy the text from the selected row region and splice it either at the start
12265                // or end of the region.
12266                let start = Point::new(rows.start.0, 0);
12267                let end = Point::new(
12268                    rows.end.previous_row().0,
12269                    buffer.line_len(rows.end.previous_row()),
12270                );
12271
12272                let mut text = buffer.text_for_range(start..end).collect::<String>();
12273
12274                let insert_location = if upwards {
12275                    // When duplicating upward, we need to insert before the current line.
12276                    // If we're on the last line and it doesn't end with a newline,
12277                    // we need to add a newline before the duplicated content.
12278                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
12279                        && buffer.max_point().column > 0
12280                        && !text.ends_with('\n');
12281
12282                    if needs_leading_newline {
12283                        text.insert(0, '\n');
12284                        end
12285                    } else {
12286                        text.push('\n');
12287                        Point::new(rows.start.0, 0)
12288                    }
12289                } else {
12290                    text.push('\n');
12291                    start
12292                };
12293                edits.push((insert_location..insert_location, text));
12294            } else {
12295                // duplicate character-wise
12296                let start = selection.start;
12297                let end = selection.end;
12298                let text = buffer.text_for_range(start..end).collect::<String>();
12299                edits.push((selection.end..selection.end, text));
12300            }
12301        }
12302
12303        self.transact(window, cx, |this, window, cx| {
12304            this.buffer.update(cx, |buffer, cx| {
12305                buffer.edit(edits, None, cx);
12306            });
12307
12308            // When duplicating upward with whole lines, move the cursor to the duplicated line
12309            if upwards && whole_lines {
12310                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
12311
12312                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12313                    let mut new_ranges = Vec::new();
12314                    let selections = s.all::<Point>(&display_map);
12315                    let mut selections_iter = selections.iter().peekable();
12316
12317                    while let Some(first_selection) = selections_iter.next() {
12318                        // Group contiguous selections together to find the total row span
12319                        let mut group_selections = vec![first_selection];
12320                        let mut rows = first_selection.spanned_rows(false, &display_map);
12321
12322                        while let Some(next_selection) = selections_iter.peek() {
12323                            let next_rows = next_selection.spanned_rows(false, &display_map);
12324                            if next_rows.start < rows.end {
12325                                rows.end = next_rows.end;
12326                                group_selections.push(selections_iter.next().unwrap());
12327                            } else {
12328                                break;
12329                            }
12330                        }
12331
12332                        let row_count = rows.end.0 - rows.start.0;
12333
12334                        // Move all selections in this group up by the total number of duplicated rows
12335                        for selection in group_selections {
12336                            let new_start = Point::new(
12337                                selection.start.row.saturating_sub(row_count),
12338                                selection.start.column,
12339                            );
12340
12341                            let new_end = Point::new(
12342                                selection.end.row.saturating_sub(row_count),
12343                                selection.end.column,
12344                            );
12345
12346                            new_ranges.push(new_start..new_end);
12347                        }
12348                    }
12349
12350                    s.select_ranges(new_ranges);
12351                });
12352            }
12353
12354            this.request_autoscroll(Autoscroll::fit(), cx);
12355        });
12356    }
12357
12358    pub fn duplicate_line_up(
12359        &mut self,
12360        _: &DuplicateLineUp,
12361        window: &mut Window,
12362        cx: &mut Context<Self>,
12363    ) {
12364        self.duplicate(true, true, window, cx);
12365    }
12366
12367    pub fn duplicate_line_down(
12368        &mut self,
12369        _: &DuplicateLineDown,
12370        window: &mut Window,
12371        cx: &mut Context<Self>,
12372    ) {
12373        self.duplicate(false, true, window, cx);
12374    }
12375
12376    pub fn duplicate_selection(
12377        &mut self,
12378        _: &DuplicateSelection,
12379        window: &mut Window,
12380        cx: &mut Context<Self>,
12381    ) {
12382        self.duplicate(false, false, window, cx);
12383    }
12384
12385    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
12386        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12387        if self.mode.is_single_line() {
12388            cx.propagate();
12389            return;
12390        }
12391
12392        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12393        let buffer = self.buffer.read(cx).snapshot(cx);
12394
12395        let mut edits = Vec::new();
12396        let mut unfold_ranges = Vec::new();
12397        let mut refold_creases = Vec::new();
12398
12399        let selections = self.selections.all::<Point>(&display_map);
12400        let mut selections = selections.iter().peekable();
12401        let mut contiguous_row_selections = Vec::new();
12402        let mut new_selections = Vec::new();
12403
12404        while let Some(selection) = selections.next() {
12405            // Find all the selections that span a contiguous row range
12406            let (start_row, end_row) = consume_contiguous_rows(
12407                &mut contiguous_row_selections,
12408                selection,
12409                &display_map,
12410                &mut selections,
12411            );
12412
12413            // Move the text spanned by the row range to be before the line preceding the row range
12414            if start_row.0 > 0 {
12415                let range_to_move = Point::new(
12416                    start_row.previous_row().0,
12417                    buffer.line_len(start_row.previous_row()),
12418                )
12419                    ..Point::new(
12420                        end_row.previous_row().0,
12421                        buffer.line_len(end_row.previous_row()),
12422                    );
12423                let insertion_point = display_map
12424                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
12425                    .0;
12426
12427                // Don't move lines across excerpts
12428                if buffer
12429                    .excerpt_containing(insertion_point..range_to_move.end)
12430                    .is_some()
12431                {
12432                    let text = buffer
12433                        .text_for_range(range_to_move.clone())
12434                        .flat_map(|s| s.chars())
12435                        .skip(1)
12436                        .chain(['\n'])
12437                        .collect::<String>();
12438
12439                    edits.push((
12440                        buffer.anchor_after(range_to_move.start)
12441                            ..buffer.anchor_before(range_to_move.end),
12442                        String::new(),
12443                    ));
12444                    let insertion_anchor = buffer.anchor_after(insertion_point);
12445                    edits.push((insertion_anchor..insertion_anchor, text));
12446
12447                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
12448
12449                    // Move selections up
12450                    new_selections.extend(contiguous_row_selections.drain(..).map(
12451                        |mut selection| {
12452                            selection.start.row -= row_delta;
12453                            selection.end.row -= row_delta;
12454                            selection
12455                        },
12456                    ));
12457
12458                    // Move folds up
12459                    unfold_ranges.push(range_to_move.clone());
12460                    for fold in display_map.folds_in_range(
12461                        buffer.anchor_before(range_to_move.start)
12462                            ..buffer.anchor_after(range_to_move.end),
12463                    ) {
12464                        let mut start = fold.range.start.to_point(&buffer);
12465                        let mut end = fold.range.end.to_point(&buffer);
12466                        start.row -= row_delta;
12467                        end.row -= row_delta;
12468                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12469                    }
12470                }
12471            }
12472
12473            // If we didn't move line(s), preserve the existing selections
12474            new_selections.append(&mut contiguous_row_selections);
12475        }
12476
12477        self.transact(window, cx, |this, window, cx| {
12478            this.unfold_ranges(&unfold_ranges, true, true, cx);
12479            this.buffer.update(cx, |buffer, cx| {
12480                for (range, text) in edits {
12481                    buffer.edit([(range, text)], None, cx);
12482                }
12483            });
12484            this.fold_creases(refold_creases, true, window, cx);
12485            this.change_selections(Default::default(), window, cx, |s| {
12486                s.select(new_selections);
12487            })
12488        });
12489    }
12490
12491    pub fn move_line_down(
12492        &mut self,
12493        _: &MoveLineDown,
12494        window: &mut Window,
12495        cx: &mut Context<Self>,
12496    ) {
12497        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12498        if self.mode.is_single_line() {
12499            cx.propagate();
12500            return;
12501        }
12502
12503        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12504        let buffer = self.buffer.read(cx).snapshot(cx);
12505
12506        let mut edits = Vec::new();
12507        let mut unfold_ranges = Vec::new();
12508        let mut refold_creases = Vec::new();
12509
12510        let selections = self.selections.all::<Point>(&display_map);
12511        let mut selections = selections.iter().peekable();
12512        let mut contiguous_row_selections = Vec::new();
12513        let mut new_selections = Vec::new();
12514
12515        while let Some(selection) = selections.next() {
12516            // Find all the selections that span a contiguous row range
12517            let (start_row, end_row) = consume_contiguous_rows(
12518                &mut contiguous_row_selections,
12519                selection,
12520                &display_map,
12521                &mut selections,
12522            );
12523
12524            // Move the text spanned by the row range to be after the last line of the row range
12525            if end_row.0 <= buffer.max_point().row {
12526                let range_to_move =
12527                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
12528                let insertion_point = display_map
12529                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
12530                    .0;
12531
12532                // Don't move lines across excerpt boundaries
12533                if buffer
12534                    .excerpt_containing(range_to_move.start..insertion_point)
12535                    .is_some()
12536                {
12537                    let mut text = String::from("\n");
12538                    text.extend(buffer.text_for_range(range_to_move.clone()));
12539                    text.pop(); // Drop trailing newline
12540                    edits.push((
12541                        buffer.anchor_after(range_to_move.start)
12542                            ..buffer.anchor_before(range_to_move.end),
12543                        String::new(),
12544                    ));
12545                    let insertion_anchor = buffer.anchor_after(insertion_point);
12546                    edits.push((insertion_anchor..insertion_anchor, text));
12547
12548                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12549
12550                    // Move selections down
12551                    new_selections.extend(contiguous_row_selections.drain(..).map(
12552                        |mut selection| {
12553                            selection.start.row += row_delta;
12554                            selection.end.row += row_delta;
12555                            selection
12556                        },
12557                    ));
12558
12559                    // Move folds down
12560                    unfold_ranges.push(range_to_move.clone());
12561                    for fold in display_map.folds_in_range(
12562                        buffer.anchor_before(range_to_move.start)
12563                            ..buffer.anchor_after(range_to_move.end),
12564                    ) {
12565                        let mut start = fold.range.start.to_point(&buffer);
12566                        let mut end = fold.range.end.to_point(&buffer);
12567                        start.row += row_delta;
12568                        end.row += row_delta;
12569                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12570                    }
12571                }
12572            }
12573
12574            // If we didn't move line(s), preserve the existing selections
12575            new_selections.append(&mut contiguous_row_selections);
12576        }
12577
12578        self.transact(window, cx, |this, window, cx| {
12579            this.unfold_ranges(&unfold_ranges, true, true, cx);
12580            this.buffer.update(cx, |buffer, cx| {
12581                for (range, text) in edits {
12582                    buffer.edit([(range, text)], None, cx);
12583                }
12584            });
12585            this.fold_creases(refold_creases, true, window, cx);
12586            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12587        });
12588    }
12589
12590    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12591        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12592        let text_layout_details = &self.text_layout_details(window);
12593        self.transact(window, cx, |this, window, cx| {
12594            let edits = this.change_selections(Default::default(), window, cx, |s| {
12595                let mut edits: Vec<(Range<MultiBufferOffset>, String)> = Default::default();
12596                s.move_with(|display_map, selection| {
12597                    if !selection.is_empty() {
12598                        return;
12599                    }
12600
12601                    let mut head = selection.head();
12602                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12603                    if head.column() == display_map.line_len(head.row()) {
12604                        transpose_offset = display_map
12605                            .buffer_snapshot()
12606                            .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12607                    }
12608
12609                    if transpose_offset == MultiBufferOffset(0) {
12610                        return;
12611                    }
12612
12613                    *head.column_mut() += 1;
12614                    head = display_map.clip_point(head, Bias::Right);
12615                    let goal = SelectionGoal::HorizontalPosition(
12616                        display_map
12617                            .x_for_display_point(head, text_layout_details)
12618                            .into(),
12619                    );
12620                    selection.collapse_to(head, goal);
12621
12622                    let transpose_start = display_map
12623                        .buffer_snapshot()
12624                        .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12625                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12626                        let transpose_end = display_map
12627                            .buffer_snapshot()
12628                            .clip_offset(transpose_offset + 1usize, Bias::Right);
12629                        if let Some(ch) = display_map
12630                            .buffer_snapshot()
12631                            .chars_at(transpose_start)
12632                            .next()
12633                        {
12634                            edits.push((transpose_start..transpose_offset, String::new()));
12635                            edits.push((transpose_end..transpose_end, ch.to_string()));
12636                        }
12637                    }
12638                });
12639                edits
12640            });
12641            this.buffer
12642                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12643            let selections = this
12644                .selections
12645                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
12646            this.change_selections(Default::default(), window, cx, |s| {
12647                s.select(selections);
12648            });
12649        });
12650    }
12651
12652    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12653        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12654        if self.mode.is_single_line() {
12655            cx.propagate();
12656            return;
12657        }
12658
12659        self.rewrap_impl(RewrapOptions::default(), cx)
12660    }
12661
12662    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12663        let buffer = self.buffer.read(cx).snapshot(cx);
12664        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12665
12666        #[derive(Clone, Debug, PartialEq)]
12667        enum CommentFormat {
12668            /// single line comment, with prefix for line
12669            Line(String),
12670            /// single line within a block comment, with prefix for line
12671            BlockLine(String),
12672            /// a single line of a block comment that includes the initial delimiter
12673            BlockCommentWithStart(BlockCommentConfig),
12674            /// a single line of a block comment that includes the ending delimiter
12675            BlockCommentWithEnd(BlockCommentConfig),
12676        }
12677
12678        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12679        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12680            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12681                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12682                .peekable();
12683
12684            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12685                row
12686            } else {
12687                return Vec::new();
12688            };
12689
12690            let language_settings = buffer.language_settings_at(selection.head(), cx);
12691            let language_scope = buffer.language_scope_at(selection.head());
12692
12693            let indent_and_prefix_for_row =
12694                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12695                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12696                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12697                        &language_scope
12698                    {
12699                        let indent_end = Point::new(row, indent.len);
12700                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12701                        let line_text_after_indent = buffer
12702                            .text_for_range(indent_end..line_end)
12703                            .collect::<String>();
12704
12705                        let is_within_comment_override = buffer
12706                            .language_scope_at(indent_end)
12707                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12708                        let comment_delimiters = if is_within_comment_override {
12709                            // we are within a comment syntax node, but we don't
12710                            // yet know what kind of comment: block, doc or line
12711                            match (
12712                                language_scope.documentation_comment(),
12713                                language_scope.block_comment(),
12714                            ) {
12715                                (Some(config), _) | (_, Some(config))
12716                                    if buffer.contains_str_at(indent_end, &config.start) =>
12717                                {
12718                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12719                                }
12720                                (Some(config), _) | (_, Some(config))
12721                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12722                                {
12723                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12724                                }
12725                                (Some(config), _) | (_, Some(config))
12726                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12727                                {
12728                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12729                                }
12730                                (_, _) => language_scope
12731                                    .line_comment_prefixes()
12732                                    .iter()
12733                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12734                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12735                            }
12736                        } else {
12737                            // we not in an overridden comment node, but we may
12738                            // be within a non-overridden line comment node
12739                            language_scope
12740                                .line_comment_prefixes()
12741                                .iter()
12742                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12743                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12744                        };
12745
12746                        let rewrap_prefix = language_scope
12747                            .rewrap_prefixes()
12748                            .iter()
12749                            .find_map(|prefix_regex| {
12750                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12751                                    if mat.start() == 0 {
12752                                        Some(mat.as_str().to_string())
12753                                    } else {
12754                                        None
12755                                    }
12756                                })
12757                            })
12758                            .flatten();
12759                        (comment_delimiters, rewrap_prefix)
12760                    } else {
12761                        (None, None)
12762                    };
12763                    (indent, comment_prefix, rewrap_prefix)
12764                };
12765
12766            let mut ranges = Vec::new();
12767            let from_empty_selection = selection.is_empty();
12768
12769            let mut current_range_start = first_row;
12770            let mut prev_row = first_row;
12771            let (
12772                mut current_range_indent,
12773                mut current_range_comment_delimiters,
12774                mut current_range_rewrap_prefix,
12775            ) = indent_and_prefix_for_row(first_row);
12776
12777            for row in non_blank_rows_iter.skip(1) {
12778                let has_paragraph_break = row > prev_row + 1;
12779
12780                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12781                    indent_and_prefix_for_row(row);
12782
12783                let has_indent_change = row_indent != current_range_indent;
12784                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12785
12786                let has_boundary_change = has_comment_change
12787                    || row_rewrap_prefix.is_some()
12788                    || (has_indent_change && current_range_comment_delimiters.is_some());
12789
12790                if has_paragraph_break || has_boundary_change {
12791                    ranges.push((
12792                        language_settings.clone(),
12793                        Point::new(current_range_start, 0)
12794                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12795                        current_range_indent,
12796                        current_range_comment_delimiters.clone(),
12797                        current_range_rewrap_prefix.clone(),
12798                        from_empty_selection,
12799                    ));
12800                    current_range_start = row;
12801                    current_range_indent = row_indent;
12802                    current_range_comment_delimiters = row_comment_delimiters;
12803                    current_range_rewrap_prefix = row_rewrap_prefix;
12804                }
12805                prev_row = row;
12806            }
12807
12808            ranges.push((
12809                language_settings.clone(),
12810                Point::new(current_range_start, 0)
12811                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12812                current_range_indent,
12813                current_range_comment_delimiters,
12814                current_range_rewrap_prefix,
12815                from_empty_selection,
12816            ));
12817
12818            ranges
12819        });
12820
12821        let mut edits = Vec::new();
12822        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12823
12824        for (
12825            language_settings,
12826            wrap_range,
12827            mut indent_size,
12828            comment_prefix,
12829            rewrap_prefix,
12830            from_empty_selection,
12831        ) in wrap_ranges
12832        {
12833            let mut start_row = wrap_range.start.row;
12834            let mut end_row = wrap_range.end.row;
12835
12836            // Skip selections that overlap with a range that has already been rewrapped.
12837            let selection_range = start_row..end_row;
12838            if rewrapped_row_ranges
12839                .iter()
12840                .any(|range| range.overlaps(&selection_range))
12841            {
12842                continue;
12843            }
12844
12845            let tab_size = language_settings.tab_size;
12846
12847            let (line_prefix, inside_comment) = match &comment_prefix {
12848                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12849                    (Some(prefix.as_str()), true)
12850                }
12851                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12852                    (Some(prefix.as_ref()), true)
12853                }
12854                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12855                    start: _,
12856                    end: _,
12857                    prefix,
12858                    tab_size,
12859                })) => {
12860                    indent_size.len += tab_size;
12861                    (Some(prefix.as_ref()), true)
12862                }
12863                None => (None, false),
12864            };
12865            let indent_prefix = indent_size.chars().collect::<String>();
12866            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12867
12868            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12869                RewrapBehavior::InComments => inside_comment,
12870                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12871                RewrapBehavior::Anywhere => true,
12872            };
12873
12874            let should_rewrap = options.override_language_settings
12875                || allow_rewrap_based_on_language
12876                || self.hard_wrap.is_some();
12877            if !should_rewrap {
12878                continue;
12879            }
12880
12881            if from_empty_selection {
12882                'expand_upwards: while start_row > 0 {
12883                    let prev_row = start_row - 1;
12884                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12885                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12886                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12887                    {
12888                        start_row = prev_row;
12889                    } else {
12890                        break 'expand_upwards;
12891                    }
12892                }
12893
12894                'expand_downwards: while end_row < buffer.max_point().row {
12895                    let next_row = end_row + 1;
12896                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12897                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12898                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12899                    {
12900                        end_row = next_row;
12901                    } else {
12902                        break 'expand_downwards;
12903                    }
12904                }
12905            }
12906
12907            let start = Point::new(start_row, 0);
12908            let start_offset = ToOffset::to_offset(&start, &buffer);
12909            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12910            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12911            let mut first_line_delimiter = None;
12912            let mut last_line_delimiter = None;
12913            let Some(lines_without_prefixes) = selection_text
12914                .lines()
12915                .enumerate()
12916                .map(|(ix, line)| {
12917                    let line_trimmed = line.trim_start();
12918                    if rewrap_prefix.is_some() && ix > 0 {
12919                        Ok(line_trimmed)
12920                    } else if let Some(
12921                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12922                            start,
12923                            prefix,
12924                            end,
12925                            tab_size,
12926                        })
12927                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12928                            start,
12929                            prefix,
12930                            end,
12931                            tab_size,
12932                        }),
12933                    ) = &comment_prefix
12934                    {
12935                        let line_trimmed = line_trimmed
12936                            .strip_prefix(start.as_ref())
12937                            .map(|s| {
12938                                let mut indent_size = indent_size;
12939                                indent_size.len -= tab_size;
12940                                let indent_prefix: String = indent_size.chars().collect();
12941                                first_line_delimiter = Some((indent_prefix, start));
12942                                s.trim_start()
12943                            })
12944                            .unwrap_or(line_trimmed);
12945                        let line_trimmed = line_trimmed
12946                            .strip_suffix(end.as_ref())
12947                            .map(|s| {
12948                                last_line_delimiter = Some(end);
12949                                s.trim_end()
12950                            })
12951                            .unwrap_or(line_trimmed);
12952                        let line_trimmed = line_trimmed
12953                            .strip_prefix(prefix.as_ref())
12954                            .unwrap_or(line_trimmed);
12955                        Ok(line_trimmed)
12956                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12957                        line_trimmed.strip_prefix(prefix).with_context(|| {
12958                            format!("line did not start with prefix {prefix:?}: {line:?}")
12959                        })
12960                    } else {
12961                        line_trimmed
12962                            .strip_prefix(&line_prefix.trim_start())
12963                            .with_context(|| {
12964                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
12965                            })
12966                    }
12967                })
12968                .collect::<Result<Vec<_>, _>>()
12969                .log_err()
12970            else {
12971                continue;
12972            };
12973
12974            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
12975                buffer
12976                    .language_settings_at(Point::new(start_row, 0), cx)
12977                    .preferred_line_length as usize
12978            });
12979
12980            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
12981                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
12982            } else {
12983                line_prefix.clone()
12984            };
12985
12986            let wrapped_text = {
12987                let mut wrapped_text = wrap_with_prefix(
12988                    line_prefix,
12989                    subsequent_lines_prefix,
12990                    lines_without_prefixes.join("\n"),
12991                    wrap_column,
12992                    tab_size,
12993                    options.preserve_existing_whitespace,
12994                );
12995
12996                if let Some((indent, delimiter)) = first_line_delimiter {
12997                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
12998                }
12999                if let Some(last_line) = last_line_delimiter {
13000                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
13001                }
13002
13003                wrapped_text
13004            };
13005
13006            // TODO: should always use char-based diff while still supporting cursor behavior that
13007            // matches vim.
13008            let mut diff_options = DiffOptions::default();
13009            if options.override_language_settings {
13010                diff_options.max_word_diff_len = 0;
13011                diff_options.max_word_diff_line_count = 0;
13012            } else {
13013                diff_options.max_word_diff_len = usize::MAX;
13014                diff_options.max_word_diff_line_count = usize::MAX;
13015            }
13016
13017            for (old_range, new_text) in
13018                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
13019            {
13020                let edit_start = buffer.anchor_after(start_offset + old_range.start);
13021                let edit_end = buffer.anchor_after(start_offset + old_range.end);
13022                edits.push((edit_start..edit_end, new_text));
13023            }
13024
13025            rewrapped_row_ranges.push(start_row..=end_row);
13026        }
13027
13028        self.buffer
13029            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
13030    }
13031
13032    pub fn cut_common(
13033        &mut self,
13034        cut_no_selection_line: bool,
13035        window: &mut Window,
13036        cx: &mut Context<Self>,
13037    ) -> ClipboardItem {
13038        let mut text = String::new();
13039        let buffer = self.buffer.read(cx).snapshot(cx);
13040        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13041        let mut clipboard_selections = Vec::with_capacity(selections.len());
13042        {
13043            let max_point = buffer.max_point();
13044            let mut is_first = true;
13045            let mut prev_selection_was_entire_line = false;
13046            for selection in &mut selections {
13047                let is_entire_line =
13048                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
13049                if is_entire_line {
13050                    selection.start = Point::new(selection.start.row, 0);
13051                    if !selection.is_empty() && selection.end.column == 0 {
13052                        selection.end = cmp::min(max_point, selection.end);
13053                    } else {
13054                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
13055                    }
13056                    selection.goal = SelectionGoal::None;
13057                }
13058                if is_first {
13059                    is_first = false;
13060                } else if !prev_selection_was_entire_line {
13061                    text += "\n";
13062                }
13063                prev_selection_was_entire_line = is_entire_line;
13064                let mut len = 0;
13065                for chunk in buffer.text_for_range(selection.start..selection.end) {
13066                    text.push_str(chunk);
13067                    len += chunk.len();
13068                }
13069
13070                clipboard_selections.push(ClipboardSelection::for_buffer(
13071                    len,
13072                    is_entire_line,
13073                    selection.range(),
13074                    &buffer,
13075                    self.project.as_ref(),
13076                    cx,
13077                ));
13078            }
13079        }
13080
13081        self.transact(window, cx, |this, window, cx| {
13082            this.change_selections(Default::default(), window, cx, |s| {
13083                s.select(selections);
13084            });
13085            this.insert("", window, cx);
13086        });
13087        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
13088    }
13089
13090    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
13091        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13092        let item = self.cut_common(true, window, cx);
13093        cx.write_to_clipboard(item);
13094    }
13095
13096    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
13097        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13098        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13099            s.move_with(|snapshot, sel| {
13100                if sel.is_empty() {
13101                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
13102                }
13103                if sel.is_empty() {
13104                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13105                }
13106            });
13107        });
13108        let item = self.cut_common(false, window, cx);
13109        cx.set_global(KillRing(item))
13110    }
13111
13112    pub fn kill_ring_yank(
13113        &mut self,
13114        _: &KillRingYank,
13115        window: &mut Window,
13116        cx: &mut Context<Self>,
13117    ) {
13118        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13119        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
13120            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
13121                (kill_ring.text().to_string(), kill_ring.metadata_json())
13122            } else {
13123                return;
13124            }
13125        } else {
13126            return;
13127        };
13128        self.do_paste(&text, metadata, false, window, cx);
13129    }
13130
13131    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
13132        self.do_copy(true, cx);
13133    }
13134
13135    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
13136        self.do_copy(false, cx);
13137    }
13138
13139    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
13140        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13141        let buffer = self.buffer.read(cx).read(cx);
13142        let mut text = String::new();
13143
13144        let mut clipboard_selections = Vec::with_capacity(selections.len());
13145        {
13146            let max_point = buffer.max_point();
13147            let mut is_first = true;
13148            let mut prev_selection_was_entire_line = false;
13149            for selection in &selections {
13150                let mut start = selection.start;
13151                let mut end = selection.end;
13152                let is_entire_line = selection.is_empty() || self.selections.line_mode();
13153                let mut add_trailing_newline = false;
13154                if is_entire_line {
13155                    start = Point::new(start.row, 0);
13156                    let next_line_start = Point::new(end.row + 1, 0);
13157                    if next_line_start <= max_point {
13158                        end = next_line_start;
13159                    } else {
13160                        // We're on the last line without a trailing newline.
13161                        // Copy to the end of the line and add a newline afterwards.
13162                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
13163                        add_trailing_newline = true;
13164                    }
13165                }
13166
13167                let mut trimmed_selections = Vec::new();
13168                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
13169                    let row = MultiBufferRow(start.row);
13170                    let first_indent = buffer.indent_size_for_line(row);
13171                    if first_indent.len == 0 || start.column > first_indent.len {
13172                        trimmed_selections.push(start..end);
13173                    } else {
13174                        trimmed_selections.push(
13175                            Point::new(row.0, first_indent.len)
13176                                ..Point::new(row.0, buffer.line_len(row)),
13177                        );
13178                        for row in start.row + 1..=end.row {
13179                            let mut line_len = buffer.line_len(MultiBufferRow(row));
13180                            if row == end.row {
13181                                line_len = end.column;
13182                            }
13183                            if line_len == 0 {
13184                                trimmed_selections
13185                                    .push(Point::new(row, 0)..Point::new(row, line_len));
13186                                continue;
13187                            }
13188                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
13189                            if row_indent_size.len >= first_indent.len {
13190                                trimmed_selections.push(
13191                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
13192                                );
13193                            } else {
13194                                trimmed_selections.clear();
13195                                trimmed_selections.push(start..end);
13196                                break;
13197                            }
13198                        }
13199                    }
13200                } else {
13201                    trimmed_selections.push(start..end);
13202                }
13203
13204                for trimmed_range in trimmed_selections {
13205                    if is_first {
13206                        is_first = false;
13207                    } else if !prev_selection_was_entire_line {
13208                        text += "\n";
13209                    }
13210                    prev_selection_was_entire_line = is_entire_line;
13211                    let mut len = 0;
13212                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
13213                        text.push_str(chunk);
13214                        len += chunk.len();
13215                    }
13216                    if add_trailing_newline {
13217                        text.push('\n');
13218                        len += 1;
13219                    }
13220                    clipboard_selections.push(ClipboardSelection::for_buffer(
13221                        len,
13222                        is_entire_line,
13223                        trimmed_range,
13224                        &buffer,
13225                        self.project.as_ref(),
13226                        cx,
13227                    ));
13228                }
13229            }
13230        }
13231
13232        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
13233            text,
13234            clipboard_selections,
13235        ));
13236    }
13237
13238    pub fn do_paste(
13239        &mut self,
13240        text: &String,
13241        clipboard_selections: Option<Vec<ClipboardSelection>>,
13242        handle_entire_lines: bool,
13243        window: &mut Window,
13244        cx: &mut Context<Self>,
13245    ) {
13246        if self.read_only(cx) {
13247            return;
13248        }
13249
13250        let clipboard_text = Cow::Borrowed(text.as_str());
13251
13252        self.transact(window, cx, |this, window, cx| {
13253            let had_active_edit_prediction = this.has_active_edit_prediction();
13254            let display_map = this.display_snapshot(cx);
13255            let old_selections = this.selections.all::<MultiBufferOffset>(&display_map);
13256            let cursor_offset = this
13257                .selections
13258                .last::<MultiBufferOffset>(&display_map)
13259                .head();
13260
13261            if let Some(mut clipboard_selections) = clipboard_selections {
13262                let all_selections_were_entire_line =
13263                    clipboard_selections.iter().all(|s| s.is_entire_line);
13264                let first_selection_indent_column =
13265                    clipboard_selections.first().map(|s| s.first_line_indent);
13266                if clipboard_selections.len() != old_selections.len() {
13267                    clipboard_selections.drain(..);
13268                }
13269                let mut auto_indent_on_paste = true;
13270
13271                this.buffer.update(cx, |buffer, cx| {
13272                    let snapshot = buffer.read(cx);
13273                    auto_indent_on_paste = snapshot
13274                        .language_settings_at(cursor_offset, cx)
13275                        .auto_indent_on_paste;
13276
13277                    let mut start_offset = 0;
13278                    let mut edits = Vec::new();
13279                    let mut original_indent_columns = Vec::new();
13280                    for (ix, selection) in old_selections.iter().enumerate() {
13281                        let to_insert;
13282                        let entire_line;
13283                        let original_indent_column;
13284                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
13285                            let end_offset = start_offset + clipboard_selection.len;
13286                            to_insert = &clipboard_text[start_offset..end_offset];
13287                            entire_line = clipboard_selection.is_entire_line;
13288                            start_offset = if entire_line {
13289                                end_offset
13290                            } else {
13291                                end_offset + 1
13292                            };
13293                            original_indent_column = Some(clipboard_selection.first_line_indent);
13294                        } else {
13295                            to_insert = &*clipboard_text;
13296                            entire_line = all_selections_were_entire_line;
13297                            original_indent_column = first_selection_indent_column
13298                        }
13299
13300                        let (range, to_insert) =
13301                            if selection.is_empty() && handle_entire_lines && entire_line {
13302                                // If the corresponding selection was empty when this slice of the
13303                                // clipboard text was written, then the entire line containing the
13304                                // selection was copied. If this selection is also currently empty,
13305                                // then paste the line before the current line of the buffer.
13306                                let column = selection.start.to_point(&snapshot).column as usize;
13307                                let line_start = selection.start - column;
13308                                (line_start..line_start, Cow::Borrowed(to_insert))
13309                            } else {
13310                                let language = snapshot.language_at(selection.head());
13311                                let range = selection.range();
13312                                if let Some(language) = language
13313                                    && language.name() == "Markdown".into()
13314                                {
13315                                    edit_for_markdown_paste(
13316                                        &snapshot,
13317                                        range,
13318                                        to_insert,
13319                                        url::Url::parse(to_insert).ok(),
13320                                    )
13321                                } else {
13322                                    (range, Cow::Borrowed(to_insert))
13323                                }
13324                            };
13325
13326                        edits.push((range, to_insert));
13327                        original_indent_columns.push(original_indent_column);
13328                    }
13329                    drop(snapshot);
13330
13331                    buffer.edit(
13332                        edits,
13333                        if auto_indent_on_paste {
13334                            Some(AutoindentMode::Block {
13335                                original_indent_columns,
13336                            })
13337                        } else {
13338                            None
13339                        },
13340                        cx,
13341                    );
13342                });
13343
13344                let selections = this
13345                    .selections
13346                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
13347                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
13348            } else {
13349                let url = url::Url::parse(&clipboard_text).ok();
13350
13351                let auto_indent_mode = if !clipboard_text.is_empty() {
13352                    Some(AutoindentMode::Block {
13353                        original_indent_columns: Vec::new(),
13354                    })
13355                } else {
13356                    None
13357                };
13358
13359                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
13360                    let snapshot = buffer.snapshot(cx);
13361
13362                    let anchors = old_selections
13363                        .iter()
13364                        .map(|s| {
13365                            let anchor = snapshot.anchor_after(s.head());
13366                            s.map(|_| anchor)
13367                        })
13368                        .collect::<Vec<_>>();
13369
13370                    let mut edits = Vec::new();
13371
13372                    for selection in old_selections.iter() {
13373                        let language = snapshot.language_at(selection.head());
13374                        let range = selection.range();
13375
13376                        let (edit_range, edit_text) = if let Some(language) = language
13377                            && language.name() == "Markdown".into()
13378                        {
13379                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
13380                        } else {
13381                            (range, clipboard_text.clone())
13382                        };
13383
13384                        edits.push((edit_range, edit_text));
13385                    }
13386
13387                    drop(snapshot);
13388                    buffer.edit(edits, auto_indent_mode, cx);
13389
13390                    anchors
13391                });
13392
13393                this.change_selections(Default::default(), window, cx, |s| {
13394                    s.select_anchors(selection_anchors);
13395                });
13396            }
13397
13398            //   🤔                 |    ..     | show_in_menu |
13399            // | ..                  |   true        true
13400            // | had_edit_prediction |   false       true
13401
13402            let trigger_in_words =
13403                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
13404
13405            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
13406        });
13407    }
13408
13409    pub fn diff_clipboard_with_selection(
13410        &mut self,
13411        _: &DiffClipboardWithSelection,
13412        window: &mut Window,
13413        cx: &mut Context<Self>,
13414    ) {
13415        let selections = self
13416            .selections
13417            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
13418
13419        if selections.is_empty() {
13420            log::warn!("There should always be at least one selection in Zed. This is a bug.");
13421            return;
13422        };
13423
13424        let clipboard_text = match cx.read_from_clipboard() {
13425            Some(item) => match item.entries().first() {
13426                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
13427                _ => None,
13428            },
13429            None => None,
13430        };
13431
13432        let Some(clipboard_text) = clipboard_text else {
13433            log::warn!("Clipboard doesn't contain text.");
13434            return;
13435        };
13436
13437        window.dispatch_action(
13438            Box::new(DiffClipboardWithSelectionData {
13439                clipboard_text,
13440                editor: cx.entity(),
13441            }),
13442            cx,
13443        );
13444    }
13445
13446    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
13447        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13448        if let Some(item) = cx.read_from_clipboard() {
13449            let entries = item.entries();
13450
13451            match entries.first() {
13452                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
13453                // of all the pasted entries.
13454                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
13455                    .do_paste(
13456                        clipboard_string.text(),
13457                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
13458                        true,
13459                        window,
13460                        cx,
13461                    ),
13462                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
13463            }
13464        }
13465    }
13466
13467    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
13468        if self.read_only(cx) {
13469            return;
13470        }
13471
13472        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13473
13474        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
13475            if let Some((selections, _)) =
13476                self.selection_history.transaction(transaction_id).cloned()
13477            {
13478                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13479                    s.select_anchors(selections.to_vec());
13480                });
13481            } else {
13482                log::error!(
13483                    "No entry in selection_history found for undo. \
13484                     This may correspond to a bug where undo does not update the selection. \
13485                     If this is occurring, please add details to \
13486                     https://github.com/zed-industries/zed/issues/22692"
13487                );
13488            }
13489            self.request_autoscroll(Autoscroll::fit(), cx);
13490            self.unmark_text(window, cx);
13491            self.refresh_edit_prediction(true, false, window, cx);
13492            cx.emit(EditorEvent::Edited { transaction_id });
13493            cx.emit(EditorEvent::TransactionUndone { transaction_id });
13494        }
13495    }
13496
13497    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
13498        if self.read_only(cx) {
13499            return;
13500        }
13501
13502        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13503
13504        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
13505            if let Some((_, Some(selections))) =
13506                self.selection_history.transaction(transaction_id).cloned()
13507            {
13508                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13509                    s.select_anchors(selections.to_vec());
13510                });
13511            } else {
13512                log::error!(
13513                    "No entry in selection_history found for redo. \
13514                     This may correspond to a bug where undo does not update the selection. \
13515                     If this is occurring, please add details to \
13516                     https://github.com/zed-industries/zed/issues/22692"
13517                );
13518            }
13519            self.request_autoscroll(Autoscroll::fit(), cx);
13520            self.unmark_text(window, cx);
13521            self.refresh_edit_prediction(true, false, window, cx);
13522            cx.emit(EditorEvent::Edited { transaction_id });
13523        }
13524    }
13525
13526    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
13527        self.buffer
13528            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
13529    }
13530
13531    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
13532        self.buffer
13533            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
13534    }
13535
13536    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
13537        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13538        self.change_selections(Default::default(), window, cx, |s| {
13539            s.move_with(|map, selection| {
13540                let cursor = if selection.is_empty() {
13541                    movement::left(map, selection.start)
13542                } else {
13543                    selection.start
13544                };
13545                selection.collapse_to(cursor, SelectionGoal::None);
13546            });
13547        })
13548    }
13549
13550    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
13551        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13552        self.change_selections(Default::default(), window, cx, |s| {
13553            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
13554        })
13555    }
13556
13557    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
13558        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13559        self.change_selections(Default::default(), window, cx, |s| {
13560            s.move_with(|map, selection| {
13561                let cursor = if selection.is_empty() {
13562                    movement::right(map, selection.end)
13563                } else {
13564                    selection.end
13565                };
13566                selection.collapse_to(cursor, SelectionGoal::None)
13567            });
13568        })
13569    }
13570
13571    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
13572        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13573        self.change_selections(Default::default(), window, cx, |s| {
13574            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13575        });
13576    }
13577
13578    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13579        if self.take_rename(true, window, cx).is_some() {
13580            return;
13581        }
13582
13583        if self.mode.is_single_line() {
13584            cx.propagate();
13585            return;
13586        }
13587
13588        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13589
13590        let text_layout_details = &self.text_layout_details(window);
13591        let selection_count = self.selections.count();
13592        let first_selection = self.selections.first_anchor();
13593
13594        self.change_selections(Default::default(), window, cx, |s| {
13595            s.move_with(|map, selection| {
13596                if !selection.is_empty() {
13597                    selection.goal = SelectionGoal::None;
13598                }
13599                let (cursor, goal) = movement::up(
13600                    map,
13601                    selection.start,
13602                    selection.goal,
13603                    false,
13604                    text_layout_details,
13605                );
13606                selection.collapse_to(cursor, goal);
13607            });
13608        });
13609
13610        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13611        {
13612            cx.propagate();
13613        }
13614    }
13615
13616    pub fn move_up_by_lines(
13617        &mut self,
13618        action: &MoveUpByLines,
13619        window: &mut Window,
13620        cx: &mut Context<Self>,
13621    ) {
13622        if self.take_rename(true, window, cx).is_some() {
13623            return;
13624        }
13625
13626        if self.mode.is_single_line() {
13627            cx.propagate();
13628            return;
13629        }
13630
13631        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13632
13633        let text_layout_details = &self.text_layout_details(window);
13634
13635        self.change_selections(Default::default(), window, cx, |s| {
13636            s.move_with(|map, selection| {
13637                if !selection.is_empty() {
13638                    selection.goal = SelectionGoal::None;
13639                }
13640                let (cursor, goal) = movement::up_by_rows(
13641                    map,
13642                    selection.start,
13643                    action.lines,
13644                    selection.goal,
13645                    false,
13646                    text_layout_details,
13647                );
13648                selection.collapse_to(cursor, goal);
13649            });
13650        })
13651    }
13652
13653    pub fn move_down_by_lines(
13654        &mut self,
13655        action: &MoveDownByLines,
13656        window: &mut Window,
13657        cx: &mut Context<Self>,
13658    ) {
13659        if self.take_rename(true, window, cx).is_some() {
13660            return;
13661        }
13662
13663        if self.mode.is_single_line() {
13664            cx.propagate();
13665            return;
13666        }
13667
13668        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13669
13670        let text_layout_details = &self.text_layout_details(window);
13671
13672        self.change_selections(Default::default(), window, cx, |s| {
13673            s.move_with(|map, selection| {
13674                if !selection.is_empty() {
13675                    selection.goal = SelectionGoal::None;
13676                }
13677                let (cursor, goal) = movement::down_by_rows(
13678                    map,
13679                    selection.start,
13680                    action.lines,
13681                    selection.goal,
13682                    false,
13683                    text_layout_details,
13684                );
13685                selection.collapse_to(cursor, goal);
13686            });
13687        })
13688    }
13689
13690    pub fn select_down_by_lines(
13691        &mut self,
13692        action: &SelectDownByLines,
13693        window: &mut Window,
13694        cx: &mut Context<Self>,
13695    ) {
13696        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13697        let text_layout_details = &self.text_layout_details(window);
13698        self.change_selections(Default::default(), window, cx, |s| {
13699            s.move_heads_with(|map, head, goal| {
13700                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13701            })
13702        })
13703    }
13704
13705    pub fn select_up_by_lines(
13706        &mut self,
13707        action: &SelectUpByLines,
13708        window: &mut Window,
13709        cx: &mut Context<Self>,
13710    ) {
13711        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13712        let text_layout_details = &self.text_layout_details(window);
13713        self.change_selections(Default::default(), window, cx, |s| {
13714            s.move_heads_with(|map, head, goal| {
13715                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13716            })
13717        })
13718    }
13719
13720    pub fn select_page_up(
13721        &mut self,
13722        _: &SelectPageUp,
13723        window: &mut Window,
13724        cx: &mut Context<Self>,
13725    ) {
13726        let Some(row_count) = self.visible_row_count() else {
13727            return;
13728        };
13729
13730        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13731
13732        let text_layout_details = &self.text_layout_details(window);
13733
13734        self.change_selections(Default::default(), window, cx, |s| {
13735            s.move_heads_with(|map, head, goal| {
13736                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13737            })
13738        })
13739    }
13740
13741    pub fn move_page_up(
13742        &mut self,
13743        action: &MovePageUp,
13744        window: &mut Window,
13745        cx: &mut Context<Self>,
13746    ) {
13747        if self.take_rename(true, window, cx).is_some() {
13748            return;
13749        }
13750
13751        if self
13752            .context_menu
13753            .borrow_mut()
13754            .as_mut()
13755            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13756            .unwrap_or(false)
13757        {
13758            return;
13759        }
13760
13761        if matches!(self.mode, EditorMode::SingleLine) {
13762            cx.propagate();
13763            return;
13764        }
13765
13766        let Some(row_count) = self.visible_row_count() else {
13767            return;
13768        };
13769
13770        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13771
13772        let effects = if action.center_cursor {
13773            SelectionEffects::scroll(Autoscroll::center())
13774        } else {
13775            SelectionEffects::default()
13776        };
13777
13778        let text_layout_details = &self.text_layout_details(window);
13779
13780        self.change_selections(effects, window, cx, |s| {
13781            s.move_with(|map, selection| {
13782                if !selection.is_empty() {
13783                    selection.goal = SelectionGoal::None;
13784                }
13785                let (cursor, goal) = movement::up_by_rows(
13786                    map,
13787                    selection.end,
13788                    row_count,
13789                    selection.goal,
13790                    false,
13791                    text_layout_details,
13792                );
13793                selection.collapse_to(cursor, goal);
13794            });
13795        });
13796    }
13797
13798    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13799        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13800        let text_layout_details = &self.text_layout_details(window);
13801        self.change_selections(Default::default(), window, cx, |s| {
13802            s.move_heads_with(|map, head, goal| {
13803                movement::up(map, head, goal, false, text_layout_details)
13804            })
13805        })
13806    }
13807
13808    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13809        self.take_rename(true, window, cx);
13810
13811        if self.mode.is_single_line() {
13812            cx.propagate();
13813            return;
13814        }
13815
13816        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13817
13818        let text_layout_details = &self.text_layout_details(window);
13819        let selection_count = self.selections.count();
13820        let first_selection = self.selections.first_anchor();
13821
13822        self.change_selections(Default::default(), window, cx, |s| {
13823            s.move_with(|map, selection| {
13824                if !selection.is_empty() {
13825                    selection.goal = SelectionGoal::None;
13826                }
13827                let (cursor, goal) = movement::down(
13828                    map,
13829                    selection.end,
13830                    selection.goal,
13831                    false,
13832                    text_layout_details,
13833                );
13834                selection.collapse_to(cursor, goal);
13835            });
13836        });
13837
13838        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13839        {
13840            cx.propagate();
13841        }
13842    }
13843
13844    pub fn select_page_down(
13845        &mut self,
13846        _: &SelectPageDown,
13847        window: &mut Window,
13848        cx: &mut Context<Self>,
13849    ) {
13850        let Some(row_count) = self.visible_row_count() else {
13851            return;
13852        };
13853
13854        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13855
13856        let text_layout_details = &self.text_layout_details(window);
13857
13858        self.change_selections(Default::default(), window, cx, |s| {
13859            s.move_heads_with(|map, head, goal| {
13860                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13861            })
13862        })
13863    }
13864
13865    pub fn move_page_down(
13866        &mut self,
13867        action: &MovePageDown,
13868        window: &mut Window,
13869        cx: &mut Context<Self>,
13870    ) {
13871        if self.take_rename(true, window, cx).is_some() {
13872            return;
13873        }
13874
13875        if self
13876            .context_menu
13877            .borrow_mut()
13878            .as_mut()
13879            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13880            .unwrap_or(false)
13881        {
13882            return;
13883        }
13884
13885        if matches!(self.mode, EditorMode::SingleLine) {
13886            cx.propagate();
13887            return;
13888        }
13889
13890        let Some(row_count) = self.visible_row_count() else {
13891            return;
13892        };
13893
13894        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13895
13896        let effects = if action.center_cursor {
13897            SelectionEffects::scroll(Autoscroll::center())
13898        } else {
13899            SelectionEffects::default()
13900        };
13901
13902        let text_layout_details = &self.text_layout_details(window);
13903        self.change_selections(effects, window, cx, |s| {
13904            s.move_with(|map, selection| {
13905                if !selection.is_empty() {
13906                    selection.goal = SelectionGoal::None;
13907                }
13908                let (cursor, goal) = movement::down_by_rows(
13909                    map,
13910                    selection.end,
13911                    row_count,
13912                    selection.goal,
13913                    false,
13914                    text_layout_details,
13915                );
13916                selection.collapse_to(cursor, goal);
13917            });
13918        });
13919    }
13920
13921    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13922        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13923        let text_layout_details = &self.text_layout_details(window);
13924        self.change_selections(Default::default(), window, cx, |s| {
13925            s.move_heads_with(|map, head, goal| {
13926                movement::down(map, head, goal, false, text_layout_details)
13927            })
13928        });
13929    }
13930
13931    pub fn context_menu_first(
13932        &mut self,
13933        _: &ContextMenuFirst,
13934        window: &mut Window,
13935        cx: &mut Context<Self>,
13936    ) {
13937        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13938            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13939        }
13940    }
13941
13942    pub fn context_menu_prev(
13943        &mut self,
13944        _: &ContextMenuPrevious,
13945        window: &mut Window,
13946        cx: &mut Context<Self>,
13947    ) {
13948        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13949            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13950        }
13951    }
13952
13953    pub fn context_menu_next(
13954        &mut self,
13955        _: &ContextMenuNext,
13956        window: &mut Window,
13957        cx: &mut Context<Self>,
13958    ) {
13959        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13960            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
13961        }
13962    }
13963
13964    pub fn context_menu_last(
13965        &mut self,
13966        _: &ContextMenuLast,
13967        window: &mut Window,
13968        cx: &mut Context<Self>,
13969    ) {
13970        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13971            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
13972        }
13973    }
13974
13975    pub fn signature_help_prev(
13976        &mut self,
13977        _: &SignatureHelpPrevious,
13978        _: &mut Window,
13979        cx: &mut Context<Self>,
13980    ) {
13981        if let Some(popover) = self.signature_help_state.popover_mut() {
13982            if popover.current_signature == 0 {
13983                popover.current_signature = popover.signatures.len() - 1;
13984            } else {
13985                popover.current_signature -= 1;
13986            }
13987            cx.notify();
13988        }
13989    }
13990
13991    pub fn signature_help_next(
13992        &mut self,
13993        _: &SignatureHelpNext,
13994        _: &mut Window,
13995        cx: &mut Context<Self>,
13996    ) {
13997        if let Some(popover) = self.signature_help_state.popover_mut() {
13998            if popover.current_signature + 1 == popover.signatures.len() {
13999                popover.current_signature = 0;
14000            } else {
14001                popover.current_signature += 1;
14002            }
14003            cx.notify();
14004        }
14005    }
14006
14007    pub fn move_to_previous_word_start(
14008        &mut self,
14009        _: &MoveToPreviousWordStart,
14010        window: &mut Window,
14011        cx: &mut Context<Self>,
14012    ) {
14013        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14014        self.change_selections(Default::default(), window, cx, |s| {
14015            s.move_cursors_with(|map, head, _| {
14016                (
14017                    movement::previous_word_start(map, head),
14018                    SelectionGoal::None,
14019                )
14020            });
14021        })
14022    }
14023
14024    pub fn move_to_previous_subword_start(
14025        &mut self,
14026        _: &MoveToPreviousSubwordStart,
14027        window: &mut Window,
14028        cx: &mut Context<Self>,
14029    ) {
14030        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14031        self.change_selections(Default::default(), window, cx, |s| {
14032            s.move_cursors_with(|map, head, _| {
14033                (
14034                    movement::previous_subword_start(map, head),
14035                    SelectionGoal::None,
14036                )
14037            });
14038        })
14039    }
14040
14041    pub fn select_to_previous_word_start(
14042        &mut self,
14043        _: &SelectToPreviousWordStart,
14044        window: &mut Window,
14045        cx: &mut Context<Self>,
14046    ) {
14047        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14048        self.change_selections(Default::default(), window, cx, |s| {
14049            s.move_heads_with(|map, head, _| {
14050                (
14051                    movement::previous_word_start(map, head),
14052                    SelectionGoal::None,
14053                )
14054            });
14055        })
14056    }
14057
14058    pub fn select_to_previous_subword_start(
14059        &mut self,
14060        _: &SelectToPreviousSubwordStart,
14061        window: &mut Window,
14062        cx: &mut Context<Self>,
14063    ) {
14064        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14065        self.change_selections(Default::default(), window, cx, |s| {
14066            s.move_heads_with(|map, head, _| {
14067                (
14068                    movement::previous_subword_start(map, head),
14069                    SelectionGoal::None,
14070                )
14071            });
14072        })
14073    }
14074
14075    pub fn delete_to_previous_word_start(
14076        &mut self,
14077        action: &DeleteToPreviousWordStart,
14078        window: &mut Window,
14079        cx: &mut Context<Self>,
14080    ) {
14081        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14082        self.transact(window, cx, |this, window, cx| {
14083            this.select_autoclose_pair(window, cx);
14084            this.change_selections(Default::default(), window, cx, |s| {
14085                s.move_with(|map, selection| {
14086                    if selection.is_empty() {
14087                        let mut cursor = if action.ignore_newlines {
14088                            movement::previous_word_start(map, selection.head())
14089                        } else {
14090                            movement::previous_word_start_or_newline(map, selection.head())
14091                        };
14092                        cursor = movement::adjust_greedy_deletion(
14093                            map,
14094                            selection.head(),
14095                            cursor,
14096                            action.ignore_brackets,
14097                        );
14098                        selection.set_head(cursor, SelectionGoal::None);
14099                    }
14100                });
14101            });
14102            this.insert("", window, cx);
14103        });
14104    }
14105
14106    pub fn delete_to_previous_subword_start(
14107        &mut self,
14108        _: &DeleteToPreviousSubwordStart,
14109        window: &mut Window,
14110        cx: &mut Context<Self>,
14111    ) {
14112        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14113        self.transact(window, cx, |this, window, cx| {
14114            this.select_autoclose_pair(window, cx);
14115            this.change_selections(Default::default(), window, cx, |s| {
14116                s.move_with(|map, selection| {
14117                    if selection.is_empty() {
14118                        let mut cursor = movement::previous_subword_start(map, selection.head());
14119                        cursor =
14120                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
14121                        selection.set_head(cursor, SelectionGoal::None);
14122                    }
14123                });
14124            });
14125            this.insert("", window, cx);
14126        });
14127    }
14128
14129    pub fn move_to_next_word_end(
14130        &mut self,
14131        _: &MoveToNextWordEnd,
14132        window: &mut Window,
14133        cx: &mut Context<Self>,
14134    ) {
14135        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14136        self.change_selections(Default::default(), window, cx, |s| {
14137            s.move_cursors_with(|map, head, _| {
14138                (movement::next_word_end(map, head), SelectionGoal::None)
14139            });
14140        })
14141    }
14142
14143    pub fn move_to_next_subword_end(
14144        &mut self,
14145        _: &MoveToNextSubwordEnd,
14146        window: &mut Window,
14147        cx: &mut Context<Self>,
14148    ) {
14149        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14150        self.change_selections(Default::default(), window, cx, |s| {
14151            s.move_cursors_with(|map, head, _| {
14152                (movement::next_subword_end(map, head), SelectionGoal::None)
14153            });
14154        })
14155    }
14156
14157    pub fn select_to_next_word_end(
14158        &mut self,
14159        _: &SelectToNextWordEnd,
14160        window: &mut Window,
14161        cx: &mut Context<Self>,
14162    ) {
14163        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14164        self.change_selections(Default::default(), window, cx, |s| {
14165            s.move_heads_with(|map, head, _| {
14166                (movement::next_word_end(map, head), SelectionGoal::None)
14167            });
14168        })
14169    }
14170
14171    pub fn select_to_next_subword_end(
14172        &mut self,
14173        _: &SelectToNextSubwordEnd,
14174        window: &mut Window,
14175        cx: &mut Context<Self>,
14176    ) {
14177        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14178        self.change_selections(Default::default(), window, cx, |s| {
14179            s.move_heads_with(|map, head, _| {
14180                (movement::next_subword_end(map, head), SelectionGoal::None)
14181            });
14182        })
14183    }
14184
14185    pub fn delete_to_next_word_end(
14186        &mut self,
14187        action: &DeleteToNextWordEnd,
14188        window: &mut Window,
14189        cx: &mut Context<Self>,
14190    ) {
14191        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14192        self.transact(window, cx, |this, window, cx| {
14193            this.change_selections(Default::default(), window, cx, |s| {
14194                s.move_with(|map, selection| {
14195                    if selection.is_empty() {
14196                        let mut cursor = if action.ignore_newlines {
14197                            movement::next_word_end(map, selection.head())
14198                        } else {
14199                            movement::next_word_end_or_newline(map, selection.head())
14200                        };
14201                        cursor = movement::adjust_greedy_deletion(
14202                            map,
14203                            selection.head(),
14204                            cursor,
14205                            action.ignore_brackets,
14206                        );
14207                        selection.set_head(cursor, SelectionGoal::None);
14208                    }
14209                });
14210            });
14211            this.insert("", window, cx);
14212        });
14213    }
14214
14215    pub fn delete_to_next_subword_end(
14216        &mut self,
14217        _: &DeleteToNextSubwordEnd,
14218        window: &mut Window,
14219        cx: &mut Context<Self>,
14220    ) {
14221        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14222        self.transact(window, cx, |this, window, cx| {
14223            this.change_selections(Default::default(), window, cx, |s| {
14224                s.move_with(|map, selection| {
14225                    if selection.is_empty() {
14226                        let mut cursor = movement::next_subword_end(map, selection.head());
14227                        cursor =
14228                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
14229                        selection.set_head(cursor, SelectionGoal::None);
14230                    }
14231                });
14232            });
14233            this.insert("", window, cx);
14234        });
14235    }
14236
14237    pub fn move_to_beginning_of_line(
14238        &mut self,
14239        action: &MoveToBeginningOfLine,
14240        window: &mut Window,
14241        cx: &mut Context<Self>,
14242    ) {
14243        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14244        self.change_selections(Default::default(), window, cx, |s| {
14245            s.move_cursors_with(|map, head, _| {
14246                (
14247                    movement::indented_line_beginning(
14248                        map,
14249                        head,
14250                        action.stop_at_soft_wraps,
14251                        action.stop_at_indent,
14252                    ),
14253                    SelectionGoal::None,
14254                )
14255            });
14256        })
14257    }
14258
14259    pub fn select_to_beginning_of_line(
14260        &mut self,
14261        action: &SelectToBeginningOfLine,
14262        window: &mut Window,
14263        cx: &mut Context<Self>,
14264    ) {
14265        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14266        self.change_selections(Default::default(), window, cx, |s| {
14267            s.move_heads_with(|map, head, _| {
14268                (
14269                    movement::indented_line_beginning(
14270                        map,
14271                        head,
14272                        action.stop_at_soft_wraps,
14273                        action.stop_at_indent,
14274                    ),
14275                    SelectionGoal::None,
14276                )
14277            });
14278        });
14279    }
14280
14281    pub fn delete_to_beginning_of_line(
14282        &mut self,
14283        action: &DeleteToBeginningOfLine,
14284        window: &mut Window,
14285        cx: &mut Context<Self>,
14286    ) {
14287        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14288        self.transact(window, cx, |this, window, cx| {
14289            this.change_selections(Default::default(), window, cx, |s| {
14290                s.move_with(|_, selection| {
14291                    selection.reversed = true;
14292                });
14293            });
14294
14295            this.select_to_beginning_of_line(
14296                &SelectToBeginningOfLine {
14297                    stop_at_soft_wraps: false,
14298                    stop_at_indent: action.stop_at_indent,
14299                },
14300                window,
14301                cx,
14302            );
14303            this.backspace(&Backspace, window, cx);
14304        });
14305    }
14306
14307    pub fn move_to_end_of_line(
14308        &mut self,
14309        action: &MoveToEndOfLine,
14310        window: &mut Window,
14311        cx: &mut Context<Self>,
14312    ) {
14313        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14314        self.change_selections(Default::default(), window, cx, |s| {
14315            s.move_cursors_with(|map, head, _| {
14316                (
14317                    movement::line_end(map, head, action.stop_at_soft_wraps),
14318                    SelectionGoal::None,
14319                )
14320            });
14321        })
14322    }
14323
14324    pub fn select_to_end_of_line(
14325        &mut self,
14326        action: &SelectToEndOfLine,
14327        window: &mut Window,
14328        cx: &mut Context<Self>,
14329    ) {
14330        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14331        self.change_selections(Default::default(), window, cx, |s| {
14332            s.move_heads_with(|map, head, _| {
14333                (
14334                    movement::line_end(map, head, action.stop_at_soft_wraps),
14335                    SelectionGoal::None,
14336                )
14337            });
14338        })
14339    }
14340
14341    pub fn delete_to_end_of_line(
14342        &mut self,
14343        _: &DeleteToEndOfLine,
14344        window: &mut Window,
14345        cx: &mut Context<Self>,
14346    ) {
14347        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14348        self.transact(window, cx, |this, window, cx| {
14349            this.select_to_end_of_line(
14350                &SelectToEndOfLine {
14351                    stop_at_soft_wraps: false,
14352                },
14353                window,
14354                cx,
14355            );
14356            this.delete(&Delete, window, cx);
14357        });
14358    }
14359
14360    pub fn cut_to_end_of_line(
14361        &mut self,
14362        action: &CutToEndOfLine,
14363        window: &mut Window,
14364        cx: &mut Context<Self>,
14365    ) {
14366        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14367        self.transact(window, cx, |this, window, cx| {
14368            this.select_to_end_of_line(
14369                &SelectToEndOfLine {
14370                    stop_at_soft_wraps: false,
14371                },
14372                window,
14373                cx,
14374            );
14375            if !action.stop_at_newlines {
14376                this.change_selections(Default::default(), window, cx, |s| {
14377                    s.move_with(|_, sel| {
14378                        if sel.is_empty() {
14379                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
14380                        }
14381                    });
14382                });
14383            }
14384            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14385            let item = this.cut_common(false, window, cx);
14386            cx.write_to_clipboard(item);
14387        });
14388    }
14389
14390    pub fn move_to_start_of_paragraph(
14391        &mut self,
14392        _: &MoveToStartOfParagraph,
14393        window: &mut Window,
14394        cx: &mut Context<Self>,
14395    ) {
14396        if matches!(self.mode, EditorMode::SingleLine) {
14397            cx.propagate();
14398            return;
14399        }
14400        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14401        self.change_selections(Default::default(), window, cx, |s| {
14402            s.move_with(|map, selection| {
14403                selection.collapse_to(
14404                    movement::start_of_paragraph(map, selection.head(), 1),
14405                    SelectionGoal::None,
14406                )
14407            });
14408        })
14409    }
14410
14411    pub fn move_to_end_of_paragraph(
14412        &mut self,
14413        _: &MoveToEndOfParagraph,
14414        window: &mut Window,
14415        cx: &mut Context<Self>,
14416    ) {
14417        if matches!(self.mode, EditorMode::SingleLine) {
14418            cx.propagate();
14419            return;
14420        }
14421        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14422        self.change_selections(Default::default(), window, cx, |s| {
14423            s.move_with(|map, selection| {
14424                selection.collapse_to(
14425                    movement::end_of_paragraph(map, selection.head(), 1),
14426                    SelectionGoal::None,
14427                )
14428            });
14429        })
14430    }
14431
14432    pub fn select_to_start_of_paragraph(
14433        &mut self,
14434        _: &SelectToStartOfParagraph,
14435        window: &mut Window,
14436        cx: &mut Context<Self>,
14437    ) {
14438        if matches!(self.mode, EditorMode::SingleLine) {
14439            cx.propagate();
14440            return;
14441        }
14442        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14443        self.change_selections(Default::default(), window, cx, |s| {
14444            s.move_heads_with(|map, head, _| {
14445                (
14446                    movement::start_of_paragraph(map, head, 1),
14447                    SelectionGoal::None,
14448                )
14449            });
14450        })
14451    }
14452
14453    pub fn select_to_end_of_paragraph(
14454        &mut self,
14455        _: &SelectToEndOfParagraph,
14456        window: &mut Window,
14457        cx: &mut Context<Self>,
14458    ) {
14459        if matches!(self.mode, EditorMode::SingleLine) {
14460            cx.propagate();
14461            return;
14462        }
14463        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14464        self.change_selections(Default::default(), window, cx, |s| {
14465            s.move_heads_with(|map, head, _| {
14466                (
14467                    movement::end_of_paragraph(map, head, 1),
14468                    SelectionGoal::None,
14469                )
14470            });
14471        })
14472    }
14473
14474    pub fn move_to_start_of_excerpt(
14475        &mut self,
14476        _: &MoveToStartOfExcerpt,
14477        window: &mut Window,
14478        cx: &mut Context<Self>,
14479    ) {
14480        if matches!(self.mode, EditorMode::SingleLine) {
14481            cx.propagate();
14482            return;
14483        }
14484        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14485        self.change_selections(Default::default(), window, cx, |s| {
14486            s.move_with(|map, selection| {
14487                selection.collapse_to(
14488                    movement::start_of_excerpt(
14489                        map,
14490                        selection.head(),
14491                        workspace::searchable::Direction::Prev,
14492                    ),
14493                    SelectionGoal::None,
14494                )
14495            });
14496        })
14497    }
14498
14499    pub fn move_to_start_of_next_excerpt(
14500        &mut self,
14501        _: &MoveToStartOfNextExcerpt,
14502        window: &mut Window,
14503        cx: &mut Context<Self>,
14504    ) {
14505        if matches!(self.mode, EditorMode::SingleLine) {
14506            cx.propagate();
14507            return;
14508        }
14509
14510        self.change_selections(Default::default(), window, cx, |s| {
14511            s.move_with(|map, selection| {
14512                selection.collapse_to(
14513                    movement::start_of_excerpt(
14514                        map,
14515                        selection.head(),
14516                        workspace::searchable::Direction::Next,
14517                    ),
14518                    SelectionGoal::None,
14519                )
14520            });
14521        })
14522    }
14523
14524    pub fn move_to_end_of_excerpt(
14525        &mut self,
14526        _: &MoveToEndOfExcerpt,
14527        window: &mut Window,
14528        cx: &mut Context<Self>,
14529    ) {
14530        if matches!(self.mode, EditorMode::SingleLine) {
14531            cx.propagate();
14532            return;
14533        }
14534        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14535        self.change_selections(Default::default(), window, cx, |s| {
14536            s.move_with(|map, selection| {
14537                selection.collapse_to(
14538                    movement::end_of_excerpt(
14539                        map,
14540                        selection.head(),
14541                        workspace::searchable::Direction::Next,
14542                    ),
14543                    SelectionGoal::None,
14544                )
14545            });
14546        })
14547    }
14548
14549    pub fn move_to_end_of_previous_excerpt(
14550        &mut self,
14551        _: &MoveToEndOfPreviousExcerpt,
14552        window: &mut Window,
14553        cx: &mut Context<Self>,
14554    ) {
14555        if matches!(self.mode, EditorMode::SingleLine) {
14556            cx.propagate();
14557            return;
14558        }
14559        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14560        self.change_selections(Default::default(), window, cx, |s| {
14561            s.move_with(|map, selection| {
14562                selection.collapse_to(
14563                    movement::end_of_excerpt(
14564                        map,
14565                        selection.head(),
14566                        workspace::searchable::Direction::Prev,
14567                    ),
14568                    SelectionGoal::None,
14569                )
14570            });
14571        })
14572    }
14573
14574    pub fn select_to_start_of_excerpt(
14575        &mut self,
14576        _: &SelectToStartOfExcerpt,
14577        window: &mut Window,
14578        cx: &mut Context<Self>,
14579    ) {
14580        if matches!(self.mode, EditorMode::SingleLine) {
14581            cx.propagate();
14582            return;
14583        }
14584        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14585        self.change_selections(Default::default(), window, cx, |s| {
14586            s.move_heads_with(|map, head, _| {
14587                (
14588                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14589                    SelectionGoal::None,
14590                )
14591            });
14592        })
14593    }
14594
14595    pub fn select_to_start_of_next_excerpt(
14596        &mut self,
14597        _: &SelectToStartOfNextExcerpt,
14598        window: &mut Window,
14599        cx: &mut Context<Self>,
14600    ) {
14601        if matches!(self.mode, EditorMode::SingleLine) {
14602            cx.propagate();
14603            return;
14604        }
14605        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14606        self.change_selections(Default::default(), window, cx, |s| {
14607            s.move_heads_with(|map, head, _| {
14608                (
14609                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14610                    SelectionGoal::None,
14611                )
14612            });
14613        })
14614    }
14615
14616    pub fn select_to_end_of_excerpt(
14617        &mut self,
14618        _: &SelectToEndOfExcerpt,
14619        window: &mut Window,
14620        cx: &mut Context<Self>,
14621    ) {
14622        if matches!(self.mode, EditorMode::SingleLine) {
14623            cx.propagate();
14624            return;
14625        }
14626        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14627        self.change_selections(Default::default(), window, cx, |s| {
14628            s.move_heads_with(|map, head, _| {
14629                (
14630                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14631                    SelectionGoal::None,
14632                )
14633            });
14634        })
14635    }
14636
14637    pub fn select_to_end_of_previous_excerpt(
14638        &mut self,
14639        _: &SelectToEndOfPreviousExcerpt,
14640        window: &mut Window,
14641        cx: &mut Context<Self>,
14642    ) {
14643        if matches!(self.mode, EditorMode::SingleLine) {
14644            cx.propagate();
14645            return;
14646        }
14647        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14648        self.change_selections(Default::default(), window, cx, |s| {
14649            s.move_heads_with(|map, head, _| {
14650                (
14651                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14652                    SelectionGoal::None,
14653                )
14654            });
14655        })
14656    }
14657
14658    pub fn move_to_beginning(
14659        &mut self,
14660        _: &MoveToBeginning,
14661        window: &mut Window,
14662        cx: &mut Context<Self>,
14663    ) {
14664        if matches!(self.mode, EditorMode::SingleLine) {
14665            cx.propagate();
14666            return;
14667        }
14668        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14669        self.change_selections(Default::default(), window, cx, |s| {
14670            s.select_ranges(vec![Anchor::min()..Anchor::min()]);
14671        });
14672    }
14673
14674    pub fn select_to_beginning(
14675        &mut self,
14676        _: &SelectToBeginning,
14677        window: &mut Window,
14678        cx: &mut Context<Self>,
14679    ) {
14680        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14681        selection.set_head(Point::zero(), SelectionGoal::None);
14682        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14683        self.change_selections(Default::default(), window, cx, |s| {
14684            s.select(vec![selection]);
14685        });
14686    }
14687
14688    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14689        if matches!(self.mode, EditorMode::SingleLine) {
14690            cx.propagate();
14691            return;
14692        }
14693        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14694        let cursor = self.buffer.read(cx).read(cx).len();
14695        self.change_selections(Default::default(), window, cx, |s| {
14696            s.select_ranges(vec![cursor..cursor])
14697        });
14698    }
14699
14700    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14701        self.nav_history = nav_history;
14702    }
14703
14704    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14705        self.nav_history.as_ref()
14706    }
14707
14708    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14709        self.push_to_nav_history(
14710            self.selections.newest_anchor().head(),
14711            None,
14712            false,
14713            true,
14714            cx,
14715        );
14716    }
14717
14718    fn push_to_nav_history(
14719        &mut self,
14720        cursor_anchor: Anchor,
14721        new_position: Option<Point>,
14722        is_deactivate: bool,
14723        always: bool,
14724        cx: &mut Context<Self>,
14725    ) {
14726        if let Some(nav_history) = self.nav_history.as_mut() {
14727            let buffer = self.buffer.read(cx).read(cx);
14728            let cursor_position = cursor_anchor.to_point(&buffer);
14729            let scroll_state = self.scroll_manager.anchor();
14730            let scroll_top_row = scroll_state.top_row(&buffer);
14731            drop(buffer);
14732
14733            if let Some(new_position) = new_position {
14734                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14735                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14736                    return;
14737                }
14738            }
14739
14740            nav_history.push(
14741                Some(NavigationData {
14742                    cursor_anchor,
14743                    cursor_position,
14744                    scroll_anchor: scroll_state,
14745                    scroll_top_row,
14746                }),
14747                cx,
14748            );
14749            cx.emit(EditorEvent::PushedToNavHistory {
14750                anchor: cursor_anchor,
14751                is_deactivate,
14752            })
14753        }
14754    }
14755
14756    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14757        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14758        let buffer = self.buffer.read(cx).snapshot(cx);
14759        let mut selection = self
14760            .selections
14761            .first::<MultiBufferOffset>(&self.display_snapshot(cx));
14762        selection.set_head(buffer.len(), SelectionGoal::None);
14763        self.change_selections(Default::default(), window, cx, |s| {
14764            s.select(vec![selection]);
14765        });
14766    }
14767
14768    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14769        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14770        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14771            s.select_ranges(vec![Anchor::min()..Anchor::max()]);
14772        });
14773    }
14774
14775    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14776        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14777        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14778        let mut selections = self.selections.all::<Point>(&display_map);
14779        let max_point = display_map.buffer_snapshot().max_point();
14780        for selection in &mut selections {
14781            let rows = selection.spanned_rows(true, &display_map);
14782            selection.start = Point::new(rows.start.0, 0);
14783            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14784            selection.reversed = false;
14785        }
14786        self.change_selections(Default::default(), window, cx, |s| {
14787            s.select(selections);
14788        });
14789    }
14790
14791    pub fn split_selection_into_lines(
14792        &mut self,
14793        action: &SplitSelectionIntoLines,
14794        window: &mut Window,
14795        cx: &mut Context<Self>,
14796    ) {
14797        let selections = self
14798            .selections
14799            .all::<Point>(&self.display_snapshot(cx))
14800            .into_iter()
14801            .map(|selection| selection.start..selection.end)
14802            .collect::<Vec<_>>();
14803        self.unfold_ranges(&selections, true, true, cx);
14804
14805        let mut new_selection_ranges = Vec::new();
14806        {
14807            let buffer = self.buffer.read(cx).read(cx);
14808            for selection in selections {
14809                for row in selection.start.row..selection.end.row {
14810                    let line_start = Point::new(row, 0);
14811                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14812
14813                    if action.keep_selections {
14814                        // Keep the selection range for each line
14815                        let selection_start = if row == selection.start.row {
14816                            selection.start
14817                        } else {
14818                            line_start
14819                        };
14820                        new_selection_ranges.push(selection_start..line_end);
14821                    } else {
14822                        // Collapse to cursor at end of line
14823                        new_selection_ranges.push(line_end..line_end);
14824                    }
14825                }
14826
14827                let is_multiline_selection = selection.start.row != selection.end.row;
14828                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14829                // so this action feels more ergonomic when paired with other selection operations
14830                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14831                if !should_skip_last {
14832                    if action.keep_selections {
14833                        if is_multiline_selection {
14834                            let line_start = Point::new(selection.end.row, 0);
14835                            new_selection_ranges.push(line_start..selection.end);
14836                        } else {
14837                            new_selection_ranges.push(selection.start..selection.end);
14838                        }
14839                    } else {
14840                        new_selection_ranges.push(selection.end..selection.end);
14841                    }
14842                }
14843            }
14844        }
14845        self.change_selections(Default::default(), window, cx, |s| {
14846            s.select_ranges(new_selection_ranges);
14847        });
14848    }
14849
14850    pub fn add_selection_above(
14851        &mut self,
14852        action: &AddSelectionAbove,
14853        window: &mut Window,
14854        cx: &mut Context<Self>,
14855    ) {
14856        self.add_selection(true, action.skip_soft_wrap, window, cx);
14857    }
14858
14859    pub fn add_selection_below(
14860        &mut self,
14861        action: &AddSelectionBelow,
14862        window: &mut Window,
14863        cx: &mut Context<Self>,
14864    ) {
14865        self.add_selection(false, action.skip_soft_wrap, window, cx);
14866    }
14867
14868    fn add_selection(
14869        &mut self,
14870        above: bool,
14871        skip_soft_wrap: bool,
14872        window: &mut Window,
14873        cx: &mut Context<Self>,
14874    ) {
14875        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14876
14877        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14878        let all_selections = self.selections.all::<Point>(&display_map);
14879        let text_layout_details = self.text_layout_details(window);
14880
14881        let (mut columnar_selections, new_selections_to_columnarize) = {
14882            if let Some(state) = self.add_selections_state.as_ref() {
14883                let columnar_selection_ids: HashSet<_> = state
14884                    .groups
14885                    .iter()
14886                    .flat_map(|group| group.stack.iter())
14887                    .copied()
14888                    .collect();
14889
14890                all_selections
14891                    .into_iter()
14892                    .partition(|s| columnar_selection_ids.contains(&s.id))
14893            } else {
14894                (Vec::new(), all_selections)
14895            }
14896        };
14897
14898        let mut state = self
14899            .add_selections_state
14900            .take()
14901            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14902
14903        for selection in new_selections_to_columnarize {
14904            let range = selection.display_range(&display_map).sorted();
14905            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14906            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14907            let positions = start_x.min(end_x)..start_x.max(end_x);
14908            let mut stack = Vec::new();
14909            for row in range.start.row().0..=range.end.row().0 {
14910                if let Some(selection) = self.selections.build_columnar_selection(
14911                    &display_map,
14912                    DisplayRow(row),
14913                    &positions,
14914                    selection.reversed,
14915                    &text_layout_details,
14916                ) {
14917                    stack.push(selection.id);
14918                    columnar_selections.push(selection);
14919                }
14920            }
14921            if !stack.is_empty() {
14922                if above {
14923                    stack.reverse();
14924                }
14925                state.groups.push(AddSelectionsGroup { above, stack });
14926            }
14927        }
14928
14929        let mut final_selections = Vec::new();
14930        let end_row = if above {
14931            DisplayRow(0)
14932        } else {
14933            display_map.max_point().row()
14934        };
14935
14936        let mut last_added_item_per_group = HashMap::default();
14937        for group in state.groups.iter_mut() {
14938            if let Some(last_id) = group.stack.last() {
14939                last_added_item_per_group.insert(*last_id, group);
14940            }
14941        }
14942
14943        for selection in columnar_selections {
14944            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14945                if above == group.above {
14946                    let range = selection.display_range(&display_map).sorted();
14947                    debug_assert_eq!(range.start.row(), range.end.row());
14948                    let mut row = range.start.row();
14949                    let positions =
14950                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14951                            Pixels::from(start)..Pixels::from(end)
14952                        } else {
14953                            let start_x =
14954                                display_map.x_for_display_point(range.start, &text_layout_details);
14955                            let end_x =
14956                                display_map.x_for_display_point(range.end, &text_layout_details);
14957                            start_x.min(end_x)..start_x.max(end_x)
14958                        };
14959
14960                    let mut maybe_new_selection = None;
14961                    let direction = if above { -1 } else { 1 };
14962
14963                    while row != end_row {
14964                        if skip_soft_wrap {
14965                            row = display_map
14966                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
14967                                .row();
14968                        } else if above {
14969                            row.0 -= 1;
14970                        } else {
14971                            row.0 += 1;
14972                        }
14973
14974                        if let Some(new_selection) = self.selections.build_columnar_selection(
14975                            &display_map,
14976                            row,
14977                            &positions,
14978                            selection.reversed,
14979                            &text_layout_details,
14980                        ) {
14981                            maybe_new_selection = Some(new_selection);
14982                            break;
14983                        }
14984                    }
14985
14986                    if let Some(new_selection) = maybe_new_selection {
14987                        group.stack.push(new_selection.id);
14988                        if above {
14989                            final_selections.push(new_selection);
14990                            final_selections.push(selection);
14991                        } else {
14992                            final_selections.push(selection);
14993                            final_selections.push(new_selection);
14994                        }
14995                    } else {
14996                        final_selections.push(selection);
14997                    }
14998                } else {
14999                    group.stack.pop();
15000                }
15001            } else {
15002                final_selections.push(selection);
15003            }
15004        }
15005
15006        self.change_selections(Default::default(), window, cx, |s| {
15007            s.select(final_selections);
15008        });
15009
15010        let final_selection_ids: HashSet<_> = self
15011            .selections
15012            .all::<Point>(&display_map)
15013            .iter()
15014            .map(|s| s.id)
15015            .collect();
15016        state.groups.retain_mut(|group| {
15017            // selections might get merged above so we remove invalid items from stacks
15018            group.stack.retain(|id| final_selection_ids.contains(id));
15019
15020            // single selection in stack can be treated as initial state
15021            group.stack.len() > 1
15022        });
15023
15024        if !state.groups.is_empty() {
15025            self.add_selections_state = Some(state);
15026        }
15027    }
15028
15029    pub fn insert_snippet_at_selections(
15030        &mut self,
15031        action: &InsertSnippet,
15032        window: &mut Window,
15033        cx: &mut Context<Self>,
15034    ) {
15035        self.try_insert_snippet_at_selections(action, window, cx)
15036            .log_err();
15037    }
15038
15039    fn try_insert_snippet_at_selections(
15040        &mut self,
15041        action: &InsertSnippet,
15042        window: &mut Window,
15043        cx: &mut Context<Self>,
15044    ) -> Result<()> {
15045        let insertion_ranges = self
15046            .selections
15047            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15048            .into_iter()
15049            .map(|selection| selection.range())
15050            .collect_vec();
15051
15052        let snippet = if let Some(snippet_body) = &action.snippet {
15053            if action.language.is_none() && action.name.is_none() {
15054                Snippet::parse(snippet_body)?
15055            } else {
15056                bail!("`snippet` is mutually exclusive with `language` and `name`")
15057            }
15058        } else if let Some(name) = &action.name {
15059            let project = self.project().context("no project")?;
15060            let snippet_store = project.read(cx).snippets().read(cx);
15061            let snippet = snippet_store
15062                .snippets_for(action.language.clone(), cx)
15063                .into_iter()
15064                .find(|snippet| snippet.name == *name)
15065                .context("snippet not found")?;
15066            Snippet::parse(&snippet.body)?
15067        } else {
15068            // todo(andrew): open modal to select snippet
15069            bail!("`name` or `snippet` is required")
15070        };
15071
15072        self.insert_snippet(&insertion_ranges, snippet, window, cx)
15073    }
15074
15075    fn select_match_ranges(
15076        &mut self,
15077        range: Range<MultiBufferOffset>,
15078        reversed: bool,
15079        replace_newest: bool,
15080        auto_scroll: Option<Autoscroll>,
15081        window: &mut Window,
15082        cx: &mut Context<Editor>,
15083    ) {
15084        self.unfold_ranges(
15085            std::slice::from_ref(&range),
15086            false,
15087            auto_scroll.is_some(),
15088            cx,
15089        );
15090        let effects = if let Some(scroll) = auto_scroll {
15091            SelectionEffects::scroll(scroll)
15092        } else {
15093            SelectionEffects::no_scroll()
15094        };
15095        self.change_selections(effects, window, cx, |s| {
15096            if replace_newest {
15097                s.delete(s.newest_anchor().id);
15098            }
15099            if reversed {
15100                s.insert_range(range.end..range.start);
15101            } else {
15102                s.insert_range(range);
15103            }
15104        });
15105    }
15106
15107    pub fn select_next_match_internal(
15108        &mut self,
15109        display_map: &DisplaySnapshot,
15110        replace_newest: bool,
15111        autoscroll: Option<Autoscroll>,
15112        window: &mut Window,
15113        cx: &mut Context<Self>,
15114    ) -> Result<()> {
15115        let buffer = display_map.buffer_snapshot();
15116        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15117        if let Some(mut select_next_state) = self.select_next_state.take() {
15118            let query = &select_next_state.query;
15119            if !select_next_state.done {
15120                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15121                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15122                let mut next_selected_range = None;
15123
15124                let bytes_after_last_selection =
15125                    buffer.bytes_in_range(last_selection.end..buffer.len());
15126                let bytes_before_first_selection =
15127                    buffer.bytes_in_range(MultiBufferOffset(0)..first_selection.start);
15128                let query_matches = query
15129                    .stream_find_iter(bytes_after_last_selection)
15130                    .map(|result| (last_selection.end, result))
15131                    .chain(
15132                        query
15133                            .stream_find_iter(bytes_before_first_selection)
15134                            .map(|result| (MultiBufferOffset(0), result)),
15135                    );
15136
15137                for (start_offset, query_match) in query_matches {
15138                    let query_match = query_match.unwrap(); // can only fail due to I/O
15139                    let offset_range =
15140                        start_offset + query_match.start()..start_offset + query_match.end();
15141
15142                    if !select_next_state.wordwise
15143                        || (!buffer.is_inside_word(offset_range.start, None)
15144                            && !buffer.is_inside_word(offset_range.end, None))
15145                    {
15146                        let idx = selections
15147                            .partition_point(|selection| selection.end <= offset_range.start);
15148                        let overlaps = selections
15149                            .get(idx)
15150                            .map_or(false, |selection| selection.start < offset_range.end);
15151
15152                        if !overlaps {
15153                            next_selected_range = Some(offset_range);
15154                            break;
15155                        }
15156                    }
15157                }
15158
15159                if let Some(next_selected_range) = next_selected_range {
15160                    self.select_match_ranges(
15161                        next_selected_range,
15162                        last_selection.reversed,
15163                        replace_newest,
15164                        autoscroll,
15165                        window,
15166                        cx,
15167                    );
15168                } else {
15169                    select_next_state.done = true;
15170                }
15171            }
15172
15173            self.select_next_state = Some(select_next_state);
15174        } else {
15175            let mut only_carets = true;
15176            let mut same_text_selected = true;
15177            let mut selected_text = None;
15178
15179            let mut selections_iter = selections.iter().peekable();
15180            while let Some(selection) = selections_iter.next() {
15181                if selection.start != selection.end {
15182                    only_carets = false;
15183                }
15184
15185                if same_text_selected {
15186                    if selected_text.is_none() {
15187                        selected_text =
15188                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15189                    }
15190
15191                    if let Some(next_selection) = selections_iter.peek() {
15192                        if next_selection.len() == selection.len() {
15193                            let next_selected_text = buffer
15194                                .text_for_range(next_selection.range())
15195                                .collect::<String>();
15196                            if Some(next_selected_text) != selected_text {
15197                                same_text_selected = false;
15198                                selected_text = None;
15199                            }
15200                        } else {
15201                            same_text_selected = false;
15202                            selected_text = None;
15203                        }
15204                    }
15205                }
15206            }
15207
15208            if only_carets {
15209                for selection in &mut selections {
15210                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15211                    selection.start = word_range.start;
15212                    selection.end = word_range.end;
15213                    selection.goal = SelectionGoal::None;
15214                    selection.reversed = false;
15215                    self.select_match_ranges(
15216                        selection.start..selection.end,
15217                        selection.reversed,
15218                        replace_newest,
15219                        autoscroll,
15220                        window,
15221                        cx,
15222                    );
15223                }
15224
15225                if selections.len() == 1 {
15226                    let selection = selections
15227                        .last()
15228                        .expect("ensured that there's only one selection");
15229                    let query = buffer
15230                        .text_for_range(selection.start..selection.end)
15231                        .collect::<String>();
15232                    let is_empty = query.is_empty();
15233                    let select_state = SelectNextState {
15234                        query: self.build_query(&[query], cx)?,
15235                        wordwise: true,
15236                        done: is_empty,
15237                    };
15238                    self.select_next_state = Some(select_state);
15239                } else {
15240                    self.select_next_state = None;
15241                }
15242            } else if let Some(selected_text) = selected_text {
15243                self.select_next_state = Some(SelectNextState {
15244                    query: self.build_query(&[selected_text], cx)?,
15245                    wordwise: false,
15246                    done: false,
15247                });
15248                self.select_next_match_internal(
15249                    display_map,
15250                    replace_newest,
15251                    autoscroll,
15252                    window,
15253                    cx,
15254                )?;
15255            }
15256        }
15257        Ok(())
15258    }
15259
15260    pub fn select_all_matches(
15261        &mut self,
15262        _action: &SelectAllMatches,
15263        window: &mut Window,
15264        cx: &mut Context<Self>,
15265    ) -> Result<()> {
15266        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15267
15268        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15269
15270        self.select_next_match_internal(&display_map, false, None, window, cx)?;
15271        let Some(select_next_state) = self.select_next_state.as_mut() else {
15272            return Ok(());
15273        };
15274        if select_next_state.done {
15275            return Ok(());
15276        }
15277
15278        let mut new_selections = Vec::new();
15279
15280        let reversed = self
15281            .selections
15282            .oldest::<MultiBufferOffset>(&display_map)
15283            .reversed;
15284        let buffer = display_map.buffer_snapshot();
15285        let query_matches = select_next_state
15286            .query
15287            .stream_find_iter(buffer.bytes_in_range(MultiBufferOffset(0)..buffer.len()));
15288
15289        for query_match in query_matches.into_iter() {
15290            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
15291            let offset_range = if reversed {
15292                MultiBufferOffset(query_match.end())..MultiBufferOffset(query_match.start())
15293            } else {
15294                MultiBufferOffset(query_match.start())..MultiBufferOffset(query_match.end())
15295            };
15296
15297            if !select_next_state.wordwise
15298                || (!buffer.is_inside_word(offset_range.start, None)
15299                    && !buffer.is_inside_word(offset_range.end, None))
15300            {
15301                new_selections.push(offset_range.start..offset_range.end);
15302            }
15303        }
15304
15305        select_next_state.done = true;
15306
15307        if new_selections.is_empty() {
15308            log::error!("bug: new_selections is empty in select_all_matches");
15309            return Ok(());
15310        }
15311
15312        self.unfold_ranges(&new_selections.clone(), false, false, cx);
15313        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
15314            selections.select_ranges(new_selections)
15315        });
15316
15317        Ok(())
15318    }
15319
15320    pub fn select_next(
15321        &mut self,
15322        action: &SelectNext,
15323        window: &mut Window,
15324        cx: &mut Context<Self>,
15325    ) -> Result<()> {
15326        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15327        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15328        self.select_next_match_internal(
15329            &display_map,
15330            action.replace_newest,
15331            Some(Autoscroll::newest()),
15332            window,
15333            cx,
15334        )?;
15335        Ok(())
15336    }
15337
15338    pub fn select_previous(
15339        &mut self,
15340        action: &SelectPrevious,
15341        window: &mut Window,
15342        cx: &mut Context<Self>,
15343    ) -> Result<()> {
15344        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15345        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15346        let buffer = display_map.buffer_snapshot();
15347        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15348        if let Some(mut select_prev_state) = self.select_prev_state.take() {
15349            let query = &select_prev_state.query;
15350            if !select_prev_state.done {
15351                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15352                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15353                let mut next_selected_range = None;
15354                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
15355                let bytes_before_last_selection =
15356                    buffer.reversed_bytes_in_range(MultiBufferOffset(0)..last_selection.start);
15357                let bytes_after_first_selection =
15358                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
15359                let query_matches = query
15360                    .stream_find_iter(bytes_before_last_selection)
15361                    .map(|result| (last_selection.start, result))
15362                    .chain(
15363                        query
15364                            .stream_find_iter(bytes_after_first_selection)
15365                            .map(|result| (buffer.len(), result)),
15366                    );
15367                for (end_offset, query_match) in query_matches {
15368                    let query_match = query_match.unwrap(); // can only fail due to I/O
15369                    let offset_range =
15370                        end_offset - query_match.end()..end_offset - query_match.start();
15371
15372                    if !select_prev_state.wordwise
15373                        || (!buffer.is_inside_word(offset_range.start, None)
15374                            && !buffer.is_inside_word(offset_range.end, None))
15375                    {
15376                        next_selected_range = Some(offset_range);
15377                        break;
15378                    }
15379                }
15380
15381                if let Some(next_selected_range) = next_selected_range {
15382                    self.select_match_ranges(
15383                        next_selected_range,
15384                        last_selection.reversed,
15385                        action.replace_newest,
15386                        Some(Autoscroll::newest()),
15387                        window,
15388                        cx,
15389                    );
15390                } else {
15391                    select_prev_state.done = true;
15392                }
15393            }
15394
15395            self.select_prev_state = Some(select_prev_state);
15396        } else {
15397            let mut only_carets = true;
15398            let mut same_text_selected = true;
15399            let mut selected_text = None;
15400
15401            let mut selections_iter = selections.iter().peekable();
15402            while let Some(selection) = selections_iter.next() {
15403                if selection.start != selection.end {
15404                    only_carets = false;
15405                }
15406
15407                if same_text_selected {
15408                    if selected_text.is_none() {
15409                        selected_text =
15410                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15411                    }
15412
15413                    if let Some(next_selection) = selections_iter.peek() {
15414                        if next_selection.len() == selection.len() {
15415                            let next_selected_text = buffer
15416                                .text_for_range(next_selection.range())
15417                                .collect::<String>();
15418                            if Some(next_selected_text) != selected_text {
15419                                same_text_selected = false;
15420                                selected_text = None;
15421                            }
15422                        } else {
15423                            same_text_selected = false;
15424                            selected_text = None;
15425                        }
15426                    }
15427                }
15428            }
15429
15430            if only_carets {
15431                for selection in &mut selections {
15432                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15433                    selection.start = word_range.start;
15434                    selection.end = word_range.end;
15435                    selection.goal = SelectionGoal::None;
15436                    selection.reversed = false;
15437                    self.select_match_ranges(
15438                        selection.start..selection.end,
15439                        selection.reversed,
15440                        action.replace_newest,
15441                        Some(Autoscroll::newest()),
15442                        window,
15443                        cx,
15444                    );
15445                }
15446                if selections.len() == 1 {
15447                    let selection = selections
15448                        .last()
15449                        .expect("ensured that there's only one selection");
15450                    let query = buffer
15451                        .text_for_range(selection.start..selection.end)
15452                        .collect::<String>();
15453                    let is_empty = query.is_empty();
15454                    let select_state = SelectNextState {
15455                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
15456                        wordwise: true,
15457                        done: is_empty,
15458                    };
15459                    self.select_prev_state = Some(select_state);
15460                } else {
15461                    self.select_prev_state = None;
15462                }
15463            } else if let Some(selected_text) = selected_text {
15464                self.select_prev_state = Some(SelectNextState {
15465                    query: self
15466                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
15467                    wordwise: false,
15468                    done: false,
15469                });
15470                self.select_previous(action, window, cx)?;
15471            }
15472        }
15473        Ok(())
15474    }
15475
15476    /// Builds an `AhoCorasick` automaton from the provided patterns, while
15477    /// setting the case sensitivity based on the global
15478    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
15479    /// editor's settings.
15480    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
15481    where
15482        I: IntoIterator<Item = P>,
15483        P: AsRef<[u8]>,
15484    {
15485        let case_sensitive = self.select_next_is_case_sensitive.map_or_else(
15486            || EditorSettings::get_global(cx).search.case_sensitive,
15487            |value| value,
15488        );
15489
15490        let mut builder = AhoCorasickBuilder::new();
15491        builder.ascii_case_insensitive(!case_sensitive);
15492        builder.build(patterns)
15493    }
15494
15495    pub fn find_next_match(
15496        &mut self,
15497        _: &FindNextMatch,
15498        window: &mut Window,
15499        cx: &mut Context<Self>,
15500    ) -> Result<()> {
15501        let selections = self.selections.disjoint_anchors_arc();
15502        match selections.first() {
15503            Some(first) if selections.len() >= 2 => {
15504                self.change_selections(Default::default(), window, cx, |s| {
15505                    s.select_ranges([first.range()]);
15506                });
15507            }
15508            _ => self.select_next(
15509                &SelectNext {
15510                    replace_newest: true,
15511                },
15512                window,
15513                cx,
15514            )?,
15515        }
15516        Ok(())
15517    }
15518
15519    pub fn find_previous_match(
15520        &mut self,
15521        _: &FindPreviousMatch,
15522        window: &mut Window,
15523        cx: &mut Context<Self>,
15524    ) -> Result<()> {
15525        let selections = self.selections.disjoint_anchors_arc();
15526        match selections.last() {
15527            Some(last) if selections.len() >= 2 => {
15528                self.change_selections(Default::default(), window, cx, |s| {
15529                    s.select_ranges([last.range()]);
15530                });
15531            }
15532            _ => self.select_previous(
15533                &SelectPrevious {
15534                    replace_newest: true,
15535                },
15536                window,
15537                cx,
15538            )?,
15539        }
15540        Ok(())
15541    }
15542
15543    pub fn toggle_comments(
15544        &mut self,
15545        action: &ToggleComments,
15546        window: &mut Window,
15547        cx: &mut Context<Self>,
15548    ) {
15549        if self.read_only(cx) {
15550            return;
15551        }
15552        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15553        let text_layout_details = &self.text_layout_details(window);
15554        self.transact(window, cx, |this, window, cx| {
15555            let mut selections = this
15556                .selections
15557                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
15558            let mut edits = Vec::new();
15559            let mut selection_edit_ranges = Vec::new();
15560            let mut last_toggled_row = None;
15561            let snapshot = this.buffer.read(cx).read(cx);
15562            let empty_str: Arc<str> = Arc::default();
15563            let mut suffixes_inserted = Vec::new();
15564            let ignore_indent = action.ignore_indent;
15565
15566            fn comment_prefix_range(
15567                snapshot: &MultiBufferSnapshot,
15568                row: MultiBufferRow,
15569                comment_prefix: &str,
15570                comment_prefix_whitespace: &str,
15571                ignore_indent: bool,
15572            ) -> Range<Point> {
15573                let indent_size = if ignore_indent {
15574                    0
15575                } else {
15576                    snapshot.indent_size_for_line(row).len
15577                };
15578
15579                let start = Point::new(row.0, indent_size);
15580
15581                let mut line_bytes = snapshot
15582                    .bytes_in_range(start..snapshot.max_point())
15583                    .flatten()
15584                    .copied();
15585
15586                // If this line currently begins with the line comment prefix, then record
15587                // the range containing the prefix.
15588                if line_bytes
15589                    .by_ref()
15590                    .take(comment_prefix.len())
15591                    .eq(comment_prefix.bytes())
15592                {
15593                    // Include any whitespace that matches the comment prefix.
15594                    let matching_whitespace_len = line_bytes
15595                        .zip(comment_prefix_whitespace.bytes())
15596                        .take_while(|(a, b)| a == b)
15597                        .count() as u32;
15598                    let end = Point::new(
15599                        start.row,
15600                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
15601                    );
15602                    start..end
15603                } else {
15604                    start..start
15605                }
15606            }
15607
15608            fn comment_suffix_range(
15609                snapshot: &MultiBufferSnapshot,
15610                row: MultiBufferRow,
15611                comment_suffix: &str,
15612                comment_suffix_has_leading_space: bool,
15613            ) -> Range<Point> {
15614                let end = Point::new(row.0, snapshot.line_len(row));
15615                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
15616
15617                let mut line_end_bytes = snapshot
15618                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
15619                    .flatten()
15620                    .copied();
15621
15622                let leading_space_len = if suffix_start_column > 0
15623                    && line_end_bytes.next() == Some(b' ')
15624                    && comment_suffix_has_leading_space
15625                {
15626                    1
15627                } else {
15628                    0
15629                };
15630
15631                // If this line currently begins with the line comment prefix, then record
15632                // the range containing the prefix.
15633                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
15634                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
15635                    start..end
15636                } else {
15637                    end..end
15638                }
15639            }
15640
15641            // TODO: Handle selections that cross excerpts
15642            for selection in &mut selections {
15643                let start_column = snapshot
15644                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15645                    .len;
15646                let language = if let Some(language) =
15647                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15648                {
15649                    language
15650                } else {
15651                    continue;
15652                };
15653
15654                selection_edit_ranges.clear();
15655
15656                // If multiple selections contain a given row, avoid processing that
15657                // row more than once.
15658                let mut start_row = MultiBufferRow(selection.start.row);
15659                if last_toggled_row == Some(start_row) {
15660                    start_row = start_row.next_row();
15661                }
15662                let end_row =
15663                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15664                        MultiBufferRow(selection.end.row - 1)
15665                    } else {
15666                        MultiBufferRow(selection.end.row)
15667                    };
15668                last_toggled_row = Some(end_row);
15669
15670                if start_row > end_row {
15671                    continue;
15672                }
15673
15674                // If the language has line comments, toggle those.
15675                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15676
15677                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15678                if ignore_indent {
15679                    full_comment_prefixes = full_comment_prefixes
15680                        .into_iter()
15681                        .map(|s| Arc::from(s.trim_end()))
15682                        .collect();
15683                }
15684
15685                if !full_comment_prefixes.is_empty() {
15686                    let first_prefix = full_comment_prefixes
15687                        .first()
15688                        .expect("prefixes is non-empty");
15689                    let prefix_trimmed_lengths = full_comment_prefixes
15690                        .iter()
15691                        .map(|p| p.trim_end_matches(' ').len())
15692                        .collect::<SmallVec<[usize; 4]>>();
15693
15694                    let mut all_selection_lines_are_comments = true;
15695
15696                    for row in start_row.0..=end_row.0 {
15697                        let row = MultiBufferRow(row);
15698                        if start_row < end_row && snapshot.is_line_blank(row) {
15699                            continue;
15700                        }
15701
15702                        let prefix_range = full_comment_prefixes
15703                            .iter()
15704                            .zip(prefix_trimmed_lengths.iter().copied())
15705                            .map(|(prefix, trimmed_prefix_len)| {
15706                                comment_prefix_range(
15707                                    snapshot.deref(),
15708                                    row,
15709                                    &prefix[..trimmed_prefix_len],
15710                                    &prefix[trimmed_prefix_len..],
15711                                    ignore_indent,
15712                                )
15713                            })
15714                            .max_by_key(|range| range.end.column - range.start.column)
15715                            .expect("prefixes is non-empty");
15716
15717                        if prefix_range.is_empty() {
15718                            all_selection_lines_are_comments = false;
15719                        }
15720
15721                        selection_edit_ranges.push(prefix_range);
15722                    }
15723
15724                    if all_selection_lines_are_comments {
15725                        edits.extend(
15726                            selection_edit_ranges
15727                                .iter()
15728                                .cloned()
15729                                .map(|range| (range, empty_str.clone())),
15730                        );
15731                    } else {
15732                        let min_column = selection_edit_ranges
15733                            .iter()
15734                            .map(|range| range.start.column)
15735                            .min()
15736                            .unwrap_or(0);
15737                        edits.extend(selection_edit_ranges.iter().map(|range| {
15738                            let position = Point::new(range.start.row, min_column);
15739                            (position..position, first_prefix.clone())
15740                        }));
15741                    }
15742                } else if let Some(BlockCommentConfig {
15743                    start: full_comment_prefix,
15744                    end: comment_suffix,
15745                    ..
15746                }) = language.block_comment()
15747                {
15748                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15749                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15750                    let prefix_range = comment_prefix_range(
15751                        snapshot.deref(),
15752                        start_row,
15753                        comment_prefix,
15754                        comment_prefix_whitespace,
15755                        ignore_indent,
15756                    );
15757                    let suffix_range = comment_suffix_range(
15758                        snapshot.deref(),
15759                        end_row,
15760                        comment_suffix.trim_start_matches(' '),
15761                        comment_suffix.starts_with(' '),
15762                    );
15763
15764                    if prefix_range.is_empty() || suffix_range.is_empty() {
15765                        edits.push((
15766                            prefix_range.start..prefix_range.start,
15767                            full_comment_prefix.clone(),
15768                        ));
15769                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15770                        suffixes_inserted.push((end_row, comment_suffix.len()));
15771                    } else {
15772                        edits.push((prefix_range, empty_str.clone()));
15773                        edits.push((suffix_range, empty_str.clone()));
15774                    }
15775                } else {
15776                    continue;
15777                }
15778            }
15779
15780            drop(snapshot);
15781            this.buffer.update(cx, |buffer, cx| {
15782                buffer.edit(edits, None, cx);
15783            });
15784
15785            // Adjust selections so that they end before any comment suffixes that
15786            // were inserted.
15787            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15788            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15789            let snapshot = this.buffer.read(cx).read(cx);
15790            for selection in &mut selections {
15791                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15792                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15793                        Ordering::Less => {
15794                            suffixes_inserted.next();
15795                            continue;
15796                        }
15797                        Ordering::Greater => break,
15798                        Ordering::Equal => {
15799                            if selection.end.column == snapshot.line_len(row) {
15800                                if selection.is_empty() {
15801                                    selection.start.column -= suffix_len as u32;
15802                                }
15803                                selection.end.column -= suffix_len as u32;
15804                            }
15805                            break;
15806                        }
15807                    }
15808                }
15809            }
15810
15811            drop(snapshot);
15812            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15813
15814            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15815            let selections_on_single_row = selections.windows(2).all(|selections| {
15816                selections[0].start.row == selections[1].start.row
15817                    && selections[0].end.row == selections[1].end.row
15818                    && selections[0].start.row == selections[0].end.row
15819            });
15820            let selections_selecting = selections
15821                .iter()
15822                .any(|selection| selection.start != selection.end);
15823            let advance_downwards = action.advance_downwards
15824                && selections_on_single_row
15825                && !selections_selecting
15826                && !matches!(this.mode, EditorMode::SingleLine);
15827
15828            if advance_downwards {
15829                let snapshot = this.buffer.read(cx).snapshot(cx);
15830
15831                this.change_selections(Default::default(), window, cx, |s| {
15832                    s.move_cursors_with(|display_snapshot, display_point, _| {
15833                        let mut point = display_point.to_point(display_snapshot);
15834                        point.row += 1;
15835                        point = snapshot.clip_point(point, Bias::Left);
15836                        let display_point = point.to_display_point(display_snapshot);
15837                        let goal = SelectionGoal::HorizontalPosition(
15838                            display_snapshot
15839                                .x_for_display_point(display_point, text_layout_details)
15840                                .into(),
15841                        );
15842                        (display_point, goal)
15843                    })
15844                });
15845            }
15846        });
15847    }
15848
15849    pub fn select_enclosing_symbol(
15850        &mut self,
15851        _: &SelectEnclosingSymbol,
15852        window: &mut Window,
15853        cx: &mut Context<Self>,
15854    ) {
15855        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15856
15857        let buffer = self.buffer.read(cx).snapshot(cx);
15858        let old_selections = self
15859            .selections
15860            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15861            .into_boxed_slice();
15862
15863        fn update_selection(
15864            selection: &Selection<MultiBufferOffset>,
15865            buffer_snap: &MultiBufferSnapshot,
15866        ) -> Option<Selection<MultiBufferOffset>> {
15867            let cursor = selection.head();
15868            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15869            for symbol in symbols.iter().rev() {
15870                let start = symbol.range.start.to_offset(buffer_snap);
15871                let end = symbol.range.end.to_offset(buffer_snap);
15872                let new_range = start..end;
15873                if start < selection.start || end > selection.end {
15874                    return Some(Selection {
15875                        id: selection.id,
15876                        start: new_range.start,
15877                        end: new_range.end,
15878                        goal: SelectionGoal::None,
15879                        reversed: selection.reversed,
15880                    });
15881                }
15882            }
15883            None
15884        }
15885
15886        let mut selected_larger_symbol = false;
15887        let new_selections = old_selections
15888            .iter()
15889            .map(|selection| match update_selection(selection, &buffer) {
15890                Some(new_selection) => {
15891                    if new_selection.range() != selection.range() {
15892                        selected_larger_symbol = true;
15893                    }
15894                    new_selection
15895                }
15896                None => selection.clone(),
15897            })
15898            .collect::<Vec<_>>();
15899
15900        if selected_larger_symbol {
15901            self.change_selections(Default::default(), window, cx, |s| {
15902                s.select(new_selections);
15903            });
15904        }
15905    }
15906
15907    pub fn select_larger_syntax_node(
15908        &mut self,
15909        _: &SelectLargerSyntaxNode,
15910        window: &mut Window,
15911        cx: &mut Context<Self>,
15912    ) {
15913        let Some(visible_row_count) = self.visible_row_count() else {
15914            return;
15915        };
15916        let old_selections: Box<[_]> = self
15917            .selections
15918            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15919            .into();
15920        if old_selections.is_empty() {
15921            return;
15922        }
15923
15924        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15925
15926        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15927        let buffer = self.buffer.read(cx).snapshot(cx);
15928
15929        let mut selected_larger_node = false;
15930        let mut new_selections = old_selections
15931            .iter()
15932            .map(|selection| {
15933                let old_range = selection.start..selection.end;
15934
15935                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15936                    // manually select word at selection
15937                    if ["string_content", "inline"].contains(&node.kind()) {
15938                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15939                        // ignore if word is already selected
15940                        if !word_range.is_empty() && old_range != word_range {
15941                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15942                            // only select word if start and end point belongs to same word
15943                            if word_range == last_word_range {
15944                                selected_larger_node = true;
15945                                return Selection {
15946                                    id: selection.id,
15947                                    start: word_range.start,
15948                                    end: word_range.end,
15949                                    goal: SelectionGoal::None,
15950                                    reversed: selection.reversed,
15951                                };
15952                            }
15953                        }
15954                    }
15955                }
15956
15957                let mut new_range = old_range.clone();
15958                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15959                    new_range = range;
15960                    if !node.is_named() {
15961                        continue;
15962                    }
15963                    if !display_map.intersects_fold(new_range.start)
15964                        && !display_map.intersects_fold(new_range.end)
15965                    {
15966                        break;
15967                    }
15968                }
15969
15970                selected_larger_node |= new_range != old_range;
15971                Selection {
15972                    id: selection.id,
15973                    start: new_range.start,
15974                    end: new_range.end,
15975                    goal: SelectionGoal::None,
15976                    reversed: selection.reversed,
15977                }
15978            })
15979            .collect::<Vec<_>>();
15980
15981        if !selected_larger_node {
15982            return; // don't put this call in the history
15983        }
15984
15985        // scroll based on transformation done to the last selection created by the user
15986        let (last_old, last_new) = old_selections
15987            .last()
15988            .zip(new_selections.last().cloned())
15989            .expect("old_selections isn't empty");
15990
15991        // revert selection
15992        let is_selection_reversed = {
15993            let should_newest_selection_be_reversed = last_old.start != last_new.start;
15994            new_selections.last_mut().expect("checked above").reversed =
15995                should_newest_selection_be_reversed;
15996            should_newest_selection_be_reversed
15997        };
15998
15999        if selected_larger_node {
16000            self.select_syntax_node_history.disable_clearing = true;
16001            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16002                s.select(new_selections.clone());
16003            });
16004            self.select_syntax_node_history.disable_clearing = false;
16005        }
16006
16007        let start_row = last_new.start.to_display_point(&display_map).row().0;
16008        let end_row = last_new.end.to_display_point(&display_map).row().0;
16009        let selection_height = end_row - start_row + 1;
16010        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
16011
16012        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
16013        let scroll_behavior = if fits_on_the_screen {
16014            self.request_autoscroll(Autoscroll::fit(), cx);
16015            SelectSyntaxNodeScrollBehavior::FitSelection
16016        } else if is_selection_reversed {
16017            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16018            SelectSyntaxNodeScrollBehavior::CursorTop
16019        } else {
16020            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16021            SelectSyntaxNodeScrollBehavior::CursorBottom
16022        };
16023
16024        self.select_syntax_node_history.push((
16025            old_selections,
16026            scroll_behavior,
16027            is_selection_reversed,
16028        ));
16029    }
16030
16031    pub fn select_smaller_syntax_node(
16032        &mut self,
16033        _: &SelectSmallerSyntaxNode,
16034        window: &mut Window,
16035        cx: &mut Context<Self>,
16036    ) {
16037        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16038
16039        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
16040            self.select_syntax_node_history.pop()
16041        {
16042            if let Some(selection) = selections.last_mut() {
16043                selection.reversed = is_selection_reversed;
16044            }
16045
16046            self.select_syntax_node_history.disable_clearing = true;
16047            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16048                s.select(selections.to_vec());
16049            });
16050            self.select_syntax_node_history.disable_clearing = false;
16051
16052            match scroll_behavior {
16053                SelectSyntaxNodeScrollBehavior::CursorTop => {
16054                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16055                }
16056                SelectSyntaxNodeScrollBehavior::FitSelection => {
16057                    self.request_autoscroll(Autoscroll::fit(), cx);
16058                }
16059                SelectSyntaxNodeScrollBehavior::CursorBottom => {
16060                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16061                }
16062            }
16063        }
16064    }
16065
16066    pub fn unwrap_syntax_node(
16067        &mut self,
16068        _: &UnwrapSyntaxNode,
16069        window: &mut Window,
16070        cx: &mut Context<Self>,
16071    ) {
16072        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16073
16074        let buffer = self.buffer.read(cx).snapshot(cx);
16075        let selections = self
16076            .selections
16077            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16078            .into_iter()
16079            // subtracting the offset requires sorting
16080            .sorted_by_key(|i| i.start);
16081
16082        let full_edits = selections
16083            .into_iter()
16084            .filter_map(|selection| {
16085                let child = if selection.is_empty()
16086                    && let Some((_, ancestor_range)) =
16087                        buffer.syntax_ancestor(selection.start..selection.end)
16088                {
16089                    ancestor_range
16090                } else {
16091                    selection.range()
16092                };
16093
16094                let mut parent = child.clone();
16095                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
16096                    parent = ancestor_range;
16097                    if parent.start < child.start || parent.end > child.end {
16098                        break;
16099                    }
16100                }
16101
16102                if parent == child {
16103                    return None;
16104                }
16105                let text = buffer.text_for_range(child).collect::<String>();
16106                Some((selection.id, parent, text))
16107            })
16108            .collect::<Vec<_>>();
16109        if full_edits.is_empty() {
16110            return;
16111        }
16112
16113        self.transact(window, cx, |this, window, cx| {
16114            this.buffer.update(cx, |buffer, cx| {
16115                buffer.edit(
16116                    full_edits
16117                        .iter()
16118                        .map(|(_, p, t)| (p.clone(), t.clone()))
16119                        .collect::<Vec<_>>(),
16120                    None,
16121                    cx,
16122                );
16123            });
16124            this.change_selections(Default::default(), window, cx, |s| {
16125                let mut offset = 0;
16126                let mut selections = vec![];
16127                for (id, parent, text) in full_edits {
16128                    let start = parent.start - offset;
16129                    offset += (parent.end - parent.start) - text.len();
16130                    selections.push(Selection {
16131                        id,
16132                        start,
16133                        end: start + text.len(),
16134                        reversed: false,
16135                        goal: Default::default(),
16136                    });
16137                }
16138                s.select(selections);
16139            });
16140        });
16141    }
16142
16143    pub fn select_next_syntax_node(
16144        &mut self,
16145        _: &SelectNextSyntaxNode,
16146        window: &mut Window,
16147        cx: &mut Context<Self>,
16148    ) {
16149        let old_selections: Box<[_]> = self
16150            .selections
16151            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16152            .into();
16153        if old_selections.is_empty() {
16154            return;
16155        }
16156
16157        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16158
16159        let buffer = self.buffer.read(cx).snapshot(cx);
16160        let mut selected_sibling = false;
16161
16162        let new_selections = old_selections
16163            .iter()
16164            .map(|selection| {
16165                let old_range = selection.start..selection.end;
16166
16167                let old_range =
16168                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16169                let excerpt = buffer.excerpt_containing(old_range.clone());
16170
16171                if let Some(mut excerpt) = excerpt
16172                    && let Some(node) = excerpt
16173                        .buffer()
16174                        .syntax_next_sibling(excerpt.map_range_to_buffer(old_range))
16175                {
16176                    let new_range = excerpt.map_range_from_buffer(
16177                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16178                    );
16179                    selected_sibling = true;
16180                    Selection {
16181                        id: selection.id,
16182                        start: new_range.start,
16183                        end: new_range.end,
16184                        goal: SelectionGoal::None,
16185                        reversed: selection.reversed,
16186                    }
16187                } else {
16188                    selection.clone()
16189                }
16190            })
16191            .collect::<Vec<_>>();
16192
16193        if selected_sibling {
16194            self.change_selections(
16195                SelectionEffects::scroll(Autoscroll::fit()),
16196                window,
16197                cx,
16198                |s| {
16199                    s.select(new_selections);
16200                },
16201            );
16202        }
16203    }
16204
16205    pub fn select_prev_syntax_node(
16206        &mut self,
16207        _: &SelectPreviousSyntaxNode,
16208        window: &mut Window,
16209        cx: &mut Context<Self>,
16210    ) {
16211        let old_selections: Box<[_]> = self
16212            .selections
16213            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16214            .into();
16215        if old_selections.is_empty() {
16216            return;
16217        }
16218
16219        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16220
16221        let buffer = self.buffer.read(cx).snapshot(cx);
16222        let mut selected_sibling = false;
16223
16224        let new_selections = old_selections
16225            .iter()
16226            .map(|selection| {
16227                let old_range = selection.start..selection.end;
16228                let old_range =
16229                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16230                let excerpt = buffer.excerpt_containing(old_range.clone());
16231
16232                if let Some(mut excerpt) = excerpt
16233                    && let Some(node) = excerpt
16234                        .buffer()
16235                        .syntax_prev_sibling(excerpt.map_range_to_buffer(old_range))
16236                {
16237                    let new_range = excerpt.map_range_from_buffer(
16238                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16239                    );
16240                    selected_sibling = true;
16241                    Selection {
16242                        id: selection.id,
16243                        start: new_range.start,
16244                        end: new_range.end,
16245                        goal: SelectionGoal::None,
16246                        reversed: selection.reversed,
16247                    }
16248                } else {
16249                    selection.clone()
16250                }
16251            })
16252            .collect::<Vec<_>>();
16253
16254        if selected_sibling {
16255            self.change_selections(
16256                SelectionEffects::scroll(Autoscroll::fit()),
16257                window,
16258                cx,
16259                |s| {
16260                    s.select(new_selections);
16261                },
16262            );
16263        }
16264    }
16265
16266    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
16267        if !EditorSettings::get_global(cx).gutter.runnables {
16268            self.clear_tasks();
16269            return Task::ready(());
16270        }
16271        let project = self.project().map(Entity::downgrade);
16272        let task_sources = self.lsp_task_sources(cx);
16273        let multi_buffer = self.buffer.downgrade();
16274        cx.spawn_in(window, async move |editor, cx| {
16275            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
16276            let Some(project) = project.and_then(|p| p.upgrade()) else {
16277                return;
16278            };
16279            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
16280                this.display_map.update(cx, |map, cx| map.snapshot(cx))
16281            }) else {
16282                return;
16283            };
16284
16285            let hide_runnables = project
16286                .update(cx, |project, _| project.is_via_collab())
16287                .unwrap_or(true);
16288            if hide_runnables {
16289                return;
16290            }
16291            let new_rows =
16292                cx.background_spawn({
16293                    let snapshot = display_snapshot.clone();
16294                    async move {
16295                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
16296                    }
16297                })
16298                    .await;
16299            let Ok(lsp_tasks) =
16300                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
16301            else {
16302                return;
16303            };
16304            let lsp_tasks = lsp_tasks.await;
16305
16306            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
16307                lsp_tasks
16308                    .into_iter()
16309                    .flat_map(|(kind, tasks)| {
16310                        tasks.into_iter().filter_map(move |(location, task)| {
16311                            Some((kind.clone(), location?, task))
16312                        })
16313                    })
16314                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
16315                        let buffer = location.target.buffer;
16316                        let buffer_snapshot = buffer.read(cx).snapshot();
16317                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
16318                            |(excerpt_id, snapshot, _)| {
16319                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
16320                                    display_snapshot
16321                                        .buffer_snapshot()
16322                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
16323                                } else {
16324                                    None
16325                                }
16326                            },
16327                        );
16328                        if let Some(offset) = offset {
16329                            let task_buffer_range =
16330                                location.target.range.to_point(&buffer_snapshot);
16331                            let context_buffer_range =
16332                                task_buffer_range.to_offset(&buffer_snapshot);
16333                            let context_range = BufferOffset(context_buffer_range.start)
16334                                ..BufferOffset(context_buffer_range.end);
16335
16336                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
16337                                .or_insert_with(|| RunnableTasks {
16338                                    templates: Vec::new(),
16339                                    offset,
16340                                    column: task_buffer_range.start.column,
16341                                    extra_variables: HashMap::default(),
16342                                    context_range,
16343                                })
16344                                .templates
16345                                .push((kind, task.original_task().clone()));
16346                        }
16347
16348                        acc
16349                    })
16350            }) else {
16351                return;
16352            };
16353
16354            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
16355                buffer.language_settings(cx).tasks.prefer_lsp
16356            }) else {
16357                return;
16358            };
16359
16360            let rows = Self::runnable_rows(
16361                project,
16362                display_snapshot,
16363                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
16364                new_rows,
16365                cx.clone(),
16366            )
16367            .await;
16368            editor
16369                .update(cx, |editor, _| {
16370                    editor.clear_tasks();
16371                    for (key, mut value) in rows {
16372                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
16373                            value.templates.extend(lsp_tasks.templates);
16374                        }
16375
16376                        editor.insert_tasks(key, value);
16377                    }
16378                    for (key, value) in lsp_tasks_by_rows {
16379                        editor.insert_tasks(key, value);
16380                    }
16381                })
16382                .ok();
16383        })
16384    }
16385    fn fetch_runnable_ranges(
16386        snapshot: &DisplaySnapshot,
16387        range: Range<Anchor>,
16388    ) -> Vec<(Range<MultiBufferOffset>, language::RunnableRange)> {
16389        snapshot.buffer_snapshot().runnable_ranges(range).collect()
16390    }
16391
16392    fn runnable_rows(
16393        project: Entity<Project>,
16394        snapshot: DisplaySnapshot,
16395        prefer_lsp: bool,
16396        runnable_ranges: Vec<(Range<MultiBufferOffset>, language::RunnableRange)>,
16397        cx: AsyncWindowContext,
16398    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
16399        cx.spawn(async move |cx| {
16400            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
16401            for (run_range, mut runnable) in runnable_ranges {
16402                let Some(tasks) = cx
16403                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
16404                    .ok()
16405                else {
16406                    continue;
16407                };
16408                let mut tasks = tasks.await;
16409
16410                if prefer_lsp {
16411                    tasks.retain(|(task_kind, _)| {
16412                        !matches!(task_kind, TaskSourceKind::Language { .. })
16413                    });
16414                }
16415                if tasks.is_empty() {
16416                    continue;
16417                }
16418
16419                let point = run_range.start.to_point(&snapshot.buffer_snapshot());
16420                let Some(row) = snapshot
16421                    .buffer_snapshot()
16422                    .buffer_line_for_row(MultiBufferRow(point.row))
16423                    .map(|(_, range)| range.start.row)
16424                else {
16425                    continue;
16426                };
16427
16428                let context_range =
16429                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
16430                runnable_rows.push((
16431                    (runnable.buffer_id, row),
16432                    RunnableTasks {
16433                        templates: tasks,
16434                        offset: snapshot.buffer_snapshot().anchor_before(run_range.start),
16435                        context_range,
16436                        column: point.column,
16437                        extra_variables: runnable.extra_captures,
16438                    },
16439                ));
16440            }
16441            runnable_rows
16442        })
16443    }
16444
16445    fn templates_with_tags(
16446        project: &Entity<Project>,
16447        runnable: &mut Runnable,
16448        cx: &mut App,
16449    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
16450        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
16451            let (worktree_id, file) = project
16452                .buffer_for_id(runnable.buffer, cx)
16453                .and_then(|buffer| buffer.read(cx).file())
16454                .map(|file| (file.worktree_id(cx), file.clone()))
16455                .unzip();
16456
16457            (
16458                project.task_store().read(cx).task_inventory().cloned(),
16459                worktree_id,
16460                file,
16461            )
16462        });
16463
16464        let tags = mem::take(&mut runnable.tags);
16465        let language = runnable.language.clone();
16466        cx.spawn(async move |cx| {
16467            let mut templates_with_tags = Vec::new();
16468            if let Some(inventory) = inventory {
16469                for RunnableTag(tag) in tags {
16470                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
16471                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
16472                    }) else {
16473                        return templates_with_tags;
16474                    };
16475                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
16476                        move |(_, template)| {
16477                            template.tags.iter().any(|source_tag| source_tag == &tag)
16478                        },
16479                    ));
16480                }
16481            }
16482            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
16483
16484            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
16485                // Strongest source wins; if we have worktree tag binding, prefer that to
16486                // global and language bindings;
16487                // if we have a global binding, prefer that to language binding.
16488                let first_mismatch = templates_with_tags
16489                    .iter()
16490                    .position(|(tag_source, _)| tag_source != leading_tag_source);
16491                if let Some(index) = first_mismatch {
16492                    templates_with_tags.truncate(index);
16493                }
16494            }
16495
16496            templates_with_tags
16497        })
16498    }
16499
16500    pub fn move_to_enclosing_bracket(
16501        &mut self,
16502        _: &MoveToEnclosingBracket,
16503        window: &mut Window,
16504        cx: &mut Context<Self>,
16505    ) {
16506        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16507        self.change_selections(Default::default(), window, cx, |s| {
16508            s.move_offsets_with(|snapshot, selection| {
16509                let Some(enclosing_bracket_ranges) =
16510                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
16511                else {
16512                    return;
16513                };
16514
16515                let mut best_length = usize::MAX;
16516                let mut best_inside = false;
16517                let mut best_in_bracket_range = false;
16518                let mut best_destination = None;
16519                for (open, close) in enclosing_bracket_ranges {
16520                    let close = close.to_inclusive();
16521                    let length = *close.end() - open.start;
16522                    let inside = selection.start >= open.end && selection.end <= *close.start();
16523                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
16524                        || close.contains(&selection.head());
16525
16526                    // If best is next to a bracket and current isn't, skip
16527                    if !in_bracket_range && best_in_bracket_range {
16528                        continue;
16529                    }
16530
16531                    // Prefer smaller lengths unless best is inside and current isn't
16532                    if length > best_length && (best_inside || !inside) {
16533                        continue;
16534                    }
16535
16536                    best_length = length;
16537                    best_inside = inside;
16538                    best_in_bracket_range = in_bracket_range;
16539                    best_destination = Some(
16540                        if close.contains(&selection.start) && close.contains(&selection.end) {
16541                            if inside { open.end } else { open.start }
16542                        } else if inside {
16543                            *close.start()
16544                        } else {
16545                            *close.end()
16546                        },
16547                    );
16548                }
16549
16550                if let Some(destination) = best_destination {
16551                    selection.collapse_to(destination, SelectionGoal::None);
16552                }
16553            })
16554        });
16555    }
16556
16557    pub fn undo_selection(
16558        &mut self,
16559        _: &UndoSelection,
16560        window: &mut Window,
16561        cx: &mut Context<Self>,
16562    ) {
16563        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16564        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
16565            self.selection_history.mode = SelectionHistoryMode::Undoing;
16566            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16567                this.end_selection(window, cx);
16568                this.change_selections(
16569                    SelectionEffects::scroll(Autoscroll::newest()),
16570                    window,
16571                    cx,
16572                    |s| s.select_anchors(entry.selections.to_vec()),
16573                );
16574            });
16575            self.selection_history.mode = SelectionHistoryMode::Normal;
16576
16577            self.select_next_state = entry.select_next_state;
16578            self.select_prev_state = entry.select_prev_state;
16579            self.add_selections_state = entry.add_selections_state;
16580        }
16581    }
16582
16583    pub fn redo_selection(
16584        &mut self,
16585        _: &RedoSelection,
16586        window: &mut Window,
16587        cx: &mut Context<Self>,
16588    ) {
16589        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16590        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
16591            self.selection_history.mode = SelectionHistoryMode::Redoing;
16592            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16593                this.end_selection(window, cx);
16594                this.change_selections(
16595                    SelectionEffects::scroll(Autoscroll::newest()),
16596                    window,
16597                    cx,
16598                    |s| s.select_anchors(entry.selections.to_vec()),
16599                );
16600            });
16601            self.selection_history.mode = SelectionHistoryMode::Normal;
16602
16603            self.select_next_state = entry.select_next_state;
16604            self.select_prev_state = entry.select_prev_state;
16605            self.add_selections_state = entry.add_selections_state;
16606        }
16607    }
16608
16609    pub fn expand_excerpts(
16610        &mut self,
16611        action: &ExpandExcerpts,
16612        _: &mut Window,
16613        cx: &mut Context<Self>,
16614    ) {
16615        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
16616    }
16617
16618    pub fn expand_excerpts_down(
16619        &mut self,
16620        action: &ExpandExcerptsDown,
16621        _: &mut Window,
16622        cx: &mut Context<Self>,
16623    ) {
16624        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
16625    }
16626
16627    pub fn expand_excerpts_up(
16628        &mut self,
16629        action: &ExpandExcerptsUp,
16630        _: &mut Window,
16631        cx: &mut Context<Self>,
16632    ) {
16633        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
16634    }
16635
16636    pub fn expand_excerpts_for_direction(
16637        &mut self,
16638        lines: u32,
16639        direction: ExpandExcerptDirection,
16640
16641        cx: &mut Context<Self>,
16642    ) {
16643        let selections = self.selections.disjoint_anchors_arc();
16644
16645        let lines = if lines == 0 {
16646            EditorSettings::get_global(cx).expand_excerpt_lines
16647        } else {
16648            lines
16649        };
16650
16651        self.buffer.update(cx, |buffer, cx| {
16652            let snapshot = buffer.snapshot(cx);
16653            let mut excerpt_ids = selections
16654                .iter()
16655                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
16656                .collect::<Vec<_>>();
16657            excerpt_ids.sort();
16658            excerpt_ids.dedup();
16659            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
16660        })
16661    }
16662
16663    pub fn expand_excerpt(
16664        &mut self,
16665        excerpt: ExcerptId,
16666        direction: ExpandExcerptDirection,
16667        window: &mut Window,
16668        cx: &mut Context<Self>,
16669    ) {
16670        let current_scroll_position = self.scroll_position(cx);
16671        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
16672        let mut scroll = None;
16673
16674        if direction == ExpandExcerptDirection::Down {
16675            let multi_buffer = self.buffer.read(cx);
16676            let snapshot = multi_buffer.snapshot(cx);
16677            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16678                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16679                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16680            {
16681                let buffer_snapshot = buffer.read(cx).snapshot();
16682                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16683                let last_row = buffer_snapshot.max_point().row;
16684                let lines_below = last_row.saturating_sub(excerpt_end_row);
16685                if lines_below >= lines_to_expand {
16686                    scroll = Some(
16687                        current_scroll_position
16688                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
16689                    );
16690                }
16691            }
16692        }
16693        if direction == ExpandExcerptDirection::Up
16694            && self
16695                .buffer
16696                .read(cx)
16697                .snapshot(cx)
16698                .excerpt_before(excerpt)
16699                .is_none()
16700        {
16701            scroll = Some(current_scroll_position);
16702        }
16703
16704        self.buffer.update(cx, |buffer, cx| {
16705            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16706        });
16707
16708        if let Some(new_scroll_position) = scroll {
16709            self.set_scroll_position(new_scroll_position, window, cx);
16710        }
16711    }
16712
16713    pub fn go_to_singleton_buffer_point(
16714        &mut self,
16715        point: Point,
16716        window: &mut Window,
16717        cx: &mut Context<Self>,
16718    ) {
16719        self.go_to_singleton_buffer_range(point..point, window, cx);
16720    }
16721
16722    pub fn go_to_singleton_buffer_range(
16723        &mut self,
16724        range: Range<Point>,
16725        window: &mut Window,
16726        cx: &mut Context<Self>,
16727    ) {
16728        let multibuffer = self.buffer().read(cx);
16729        let Some(buffer) = multibuffer.as_singleton() else {
16730            return;
16731        };
16732        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16733            return;
16734        };
16735        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16736            return;
16737        };
16738        self.change_selections(
16739            SelectionEffects::default().nav_history(true),
16740            window,
16741            cx,
16742            |s| s.select_anchor_ranges([start..end]),
16743        );
16744    }
16745
16746    pub fn go_to_diagnostic(
16747        &mut self,
16748        action: &GoToDiagnostic,
16749        window: &mut Window,
16750        cx: &mut Context<Self>,
16751    ) {
16752        if !self.diagnostics_enabled() {
16753            return;
16754        }
16755        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16756        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16757    }
16758
16759    pub fn go_to_prev_diagnostic(
16760        &mut self,
16761        action: &GoToPreviousDiagnostic,
16762        window: &mut Window,
16763        cx: &mut Context<Self>,
16764    ) {
16765        if !self.diagnostics_enabled() {
16766            return;
16767        }
16768        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16769        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16770    }
16771
16772    pub fn go_to_diagnostic_impl(
16773        &mut self,
16774        direction: Direction,
16775        severity: GoToDiagnosticSeverityFilter,
16776        window: &mut Window,
16777        cx: &mut Context<Self>,
16778    ) {
16779        let buffer = self.buffer.read(cx).snapshot(cx);
16780        let selection = self
16781            .selections
16782            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
16783
16784        let mut active_group_id = None;
16785        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16786            && active_group.active_range.start.to_offset(&buffer) == selection.start
16787        {
16788            active_group_id = Some(active_group.group_id);
16789        }
16790
16791        fn filtered<'a>(
16792            severity: GoToDiagnosticSeverityFilter,
16793            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>>,
16794        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>> {
16795            diagnostics
16796                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16797                .filter(|entry| entry.range.start != entry.range.end)
16798                .filter(|entry| !entry.diagnostic.is_unnecessary)
16799        }
16800
16801        let before = filtered(
16802            severity,
16803            buffer
16804                .diagnostics_in_range(MultiBufferOffset(0)..selection.start)
16805                .filter(|entry| entry.range.start <= selection.start),
16806        );
16807        let after = filtered(
16808            severity,
16809            buffer
16810                .diagnostics_in_range(selection.start..buffer.len())
16811                .filter(|entry| entry.range.start >= selection.start),
16812        );
16813
16814        let mut found: Option<DiagnosticEntryRef<MultiBufferOffset>> = None;
16815        if direction == Direction::Prev {
16816            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16817            {
16818                for diagnostic in prev_diagnostics.into_iter().rev() {
16819                    if diagnostic.range.start != selection.start
16820                        || active_group_id
16821                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16822                    {
16823                        found = Some(diagnostic);
16824                        break 'outer;
16825                    }
16826                }
16827            }
16828        } else {
16829            for diagnostic in after.chain(before) {
16830                if diagnostic.range.start != selection.start
16831                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16832                {
16833                    found = Some(diagnostic);
16834                    break;
16835                }
16836            }
16837        }
16838        let Some(next_diagnostic) = found else {
16839            return;
16840        };
16841
16842        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16843        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16844            return;
16845        };
16846        let snapshot = self.snapshot(window, cx);
16847        if snapshot.intersects_fold(next_diagnostic.range.start) {
16848            self.unfold_ranges(
16849                std::slice::from_ref(&next_diagnostic.range),
16850                true,
16851                false,
16852                cx,
16853            );
16854        }
16855        self.change_selections(Default::default(), window, cx, |s| {
16856            s.select_ranges(vec![
16857                next_diagnostic.range.start..next_diagnostic.range.start,
16858            ])
16859        });
16860        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16861        self.refresh_edit_prediction(false, true, window, cx);
16862    }
16863
16864    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16865        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16866        let snapshot = self.snapshot(window, cx);
16867        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16868        self.go_to_hunk_before_or_after_position(
16869            &snapshot,
16870            selection.head(),
16871            Direction::Next,
16872            window,
16873            cx,
16874        );
16875    }
16876
16877    pub fn go_to_hunk_before_or_after_position(
16878        &mut self,
16879        snapshot: &EditorSnapshot,
16880        position: Point,
16881        direction: Direction,
16882        window: &mut Window,
16883        cx: &mut Context<Editor>,
16884    ) {
16885        let row = if direction == Direction::Next {
16886            self.hunk_after_position(snapshot, position)
16887                .map(|hunk| hunk.row_range.start)
16888        } else {
16889            self.hunk_before_position(snapshot, position)
16890        };
16891
16892        if let Some(row) = row {
16893            let destination = Point::new(row.0, 0);
16894            let autoscroll = Autoscroll::center();
16895
16896            self.unfold_ranges(&[destination..destination], false, false, cx);
16897            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16898                s.select_ranges([destination..destination]);
16899            });
16900        }
16901    }
16902
16903    fn hunk_after_position(
16904        &mut self,
16905        snapshot: &EditorSnapshot,
16906        position: Point,
16907    ) -> Option<MultiBufferDiffHunk> {
16908        snapshot
16909            .buffer_snapshot()
16910            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16911            .find(|hunk| hunk.row_range.start.0 > position.row)
16912            .or_else(|| {
16913                snapshot
16914                    .buffer_snapshot()
16915                    .diff_hunks_in_range(Point::zero()..position)
16916                    .find(|hunk| hunk.row_range.end.0 < position.row)
16917            })
16918    }
16919
16920    fn go_to_prev_hunk(
16921        &mut self,
16922        _: &GoToPreviousHunk,
16923        window: &mut Window,
16924        cx: &mut Context<Self>,
16925    ) {
16926        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16927        let snapshot = self.snapshot(window, cx);
16928        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16929        self.go_to_hunk_before_or_after_position(
16930            &snapshot,
16931            selection.head(),
16932            Direction::Prev,
16933            window,
16934            cx,
16935        );
16936    }
16937
16938    fn hunk_before_position(
16939        &mut self,
16940        snapshot: &EditorSnapshot,
16941        position: Point,
16942    ) -> Option<MultiBufferRow> {
16943        snapshot
16944            .buffer_snapshot()
16945            .diff_hunk_before(position)
16946            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16947    }
16948
16949    fn go_to_next_change(
16950        &mut self,
16951        _: &GoToNextChange,
16952        window: &mut Window,
16953        cx: &mut Context<Self>,
16954    ) {
16955        if let Some(selections) = self
16956            .change_list
16957            .next_change(1, Direction::Next)
16958            .map(|s| s.to_vec())
16959        {
16960            self.change_selections(Default::default(), window, cx, |s| {
16961                let map = s.display_snapshot();
16962                s.select_display_ranges(selections.iter().map(|a| {
16963                    let point = a.to_display_point(&map);
16964                    point..point
16965                }))
16966            })
16967        }
16968    }
16969
16970    fn go_to_previous_change(
16971        &mut self,
16972        _: &GoToPreviousChange,
16973        window: &mut Window,
16974        cx: &mut Context<Self>,
16975    ) {
16976        if let Some(selections) = self
16977            .change_list
16978            .next_change(1, Direction::Prev)
16979            .map(|s| s.to_vec())
16980        {
16981            self.change_selections(Default::default(), window, cx, |s| {
16982                let map = s.display_snapshot();
16983                s.select_display_ranges(selections.iter().map(|a| {
16984                    let point = a.to_display_point(&map);
16985                    point..point
16986                }))
16987            })
16988        }
16989    }
16990
16991    pub fn go_to_next_document_highlight(
16992        &mut self,
16993        _: &GoToNextDocumentHighlight,
16994        window: &mut Window,
16995        cx: &mut Context<Self>,
16996    ) {
16997        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
16998    }
16999
17000    pub fn go_to_prev_document_highlight(
17001        &mut self,
17002        _: &GoToPreviousDocumentHighlight,
17003        window: &mut Window,
17004        cx: &mut Context<Self>,
17005    ) {
17006        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
17007    }
17008
17009    pub fn go_to_document_highlight_before_or_after_position(
17010        &mut self,
17011        direction: Direction,
17012        window: &mut Window,
17013        cx: &mut Context<Editor>,
17014    ) {
17015        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17016        let snapshot = self.snapshot(window, cx);
17017        let buffer = &snapshot.buffer_snapshot();
17018        let position = self
17019            .selections
17020            .newest::<Point>(&snapshot.display_snapshot)
17021            .head();
17022        let anchor_position = buffer.anchor_after(position);
17023
17024        // Get all document highlights (both read and write)
17025        let mut all_highlights = Vec::new();
17026
17027        if let Some((_, read_highlights)) = self
17028            .background_highlights
17029            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
17030        {
17031            all_highlights.extend(read_highlights.iter());
17032        }
17033
17034        if let Some((_, write_highlights)) = self
17035            .background_highlights
17036            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
17037        {
17038            all_highlights.extend(write_highlights.iter());
17039        }
17040
17041        if all_highlights.is_empty() {
17042            return;
17043        }
17044
17045        // Sort highlights by position
17046        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
17047
17048        let target_highlight = match direction {
17049            Direction::Next => {
17050                // Find the first highlight after the current position
17051                all_highlights
17052                    .iter()
17053                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
17054            }
17055            Direction::Prev => {
17056                // Find the last highlight before the current position
17057                all_highlights
17058                    .iter()
17059                    .rev()
17060                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
17061            }
17062        };
17063
17064        if let Some(highlight) = target_highlight {
17065            let destination = highlight.start.to_point(buffer);
17066            let autoscroll = Autoscroll::center();
17067
17068            self.unfold_ranges(&[destination..destination], false, false, cx);
17069            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17070                s.select_ranges([destination..destination]);
17071            });
17072        }
17073    }
17074
17075    fn go_to_line<T: 'static>(
17076        &mut self,
17077        position: Anchor,
17078        highlight_color: Option<Hsla>,
17079        window: &mut Window,
17080        cx: &mut Context<Self>,
17081    ) {
17082        let snapshot = self.snapshot(window, cx).display_snapshot;
17083        let position = position.to_point(&snapshot.buffer_snapshot());
17084        let start = snapshot
17085            .buffer_snapshot()
17086            .clip_point(Point::new(position.row, 0), Bias::Left);
17087        let end = start + Point::new(1, 0);
17088        let start = snapshot.buffer_snapshot().anchor_before(start);
17089        let end = snapshot.buffer_snapshot().anchor_before(end);
17090
17091        self.highlight_rows::<T>(
17092            start..end,
17093            highlight_color
17094                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
17095            Default::default(),
17096            cx,
17097        );
17098
17099        if self.buffer.read(cx).is_singleton() {
17100            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
17101        }
17102    }
17103
17104    pub fn go_to_definition(
17105        &mut self,
17106        _: &GoToDefinition,
17107        window: &mut Window,
17108        cx: &mut Context<Self>,
17109    ) -> Task<Result<Navigated>> {
17110        let definition =
17111            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
17112        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
17113        cx.spawn_in(window, async move |editor, cx| {
17114            if definition.await? == Navigated::Yes {
17115                return Ok(Navigated::Yes);
17116            }
17117            match fallback_strategy {
17118                GoToDefinitionFallback::None => Ok(Navigated::No),
17119                GoToDefinitionFallback::FindAllReferences => {
17120                    match editor.update_in(cx, |editor, window, cx| {
17121                        editor.find_all_references(&FindAllReferences::default(), window, cx)
17122                    })? {
17123                        Some(references) => references.await,
17124                        None => Ok(Navigated::No),
17125                    }
17126                }
17127            }
17128        })
17129    }
17130
17131    pub fn go_to_declaration(
17132        &mut self,
17133        _: &GoToDeclaration,
17134        window: &mut Window,
17135        cx: &mut Context<Self>,
17136    ) -> Task<Result<Navigated>> {
17137        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
17138    }
17139
17140    pub fn go_to_declaration_split(
17141        &mut self,
17142        _: &GoToDeclaration,
17143        window: &mut Window,
17144        cx: &mut Context<Self>,
17145    ) -> Task<Result<Navigated>> {
17146        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
17147    }
17148
17149    pub fn go_to_implementation(
17150        &mut self,
17151        _: &GoToImplementation,
17152        window: &mut Window,
17153        cx: &mut Context<Self>,
17154    ) -> Task<Result<Navigated>> {
17155        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
17156    }
17157
17158    pub fn go_to_implementation_split(
17159        &mut self,
17160        _: &GoToImplementationSplit,
17161        window: &mut Window,
17162        cx: &mut Context<Self>,
17163    ) -> Task<Result<Navigated>> {
17164        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
17165    }
17166
17167    pub fn go_to_type_definition(
17168        &mut self,
17169        _: &GoToTypeDefinition,
17170        window: &mut Window,
17171        cx: &mut Context<Self>,
17172    ) -> Task<Result<Navigated>> {
17173        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
17174    }
17175
17176    pub fn go_to_definition_split(
17177        &mut self,
17178        _: &GoToDefinitionSplit,
17179        window: &mut Window,
17180        cx: &mut Context<Self>,
17181    ) -> Task<Result<Navigated>> {
17182        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
17183    }
17184
17185    pub fn go_to_type_definition_split(
17186        &mut self,
17187        _: &GoToTypeDefinitionSplit,
17188        window: &mut Window,
17189        cx: &mut Context<Self>,
17190    ) -> Task<Result<Navigated>> {
17191        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
17192    }
17193
17194    fn go_to_definition_of_kind(
17195        &mut self,
17196        kind: GotoDefinitionKind,
17197        split: bool,
17198        window: &mut Window,
17199        cx: &mut Context<Self>,
17200    ) -> Task<Result<Navigated>> {
17201        let Some(provider) = self.semantics_provider.clone() else {
17202            return Task::ready(Ok(Navigated::No));
17203        };
17204        let head = self
17205            .selections
17206            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
17207            .head();
17208        let buffer = self.buffer.read(cx);
17209        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
17210            return Task::ready(Ok(Navigated::No));
17211        };
17212        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
17213            return Task::ready(Ok(Navigated::No));
17214        };
17215
17216        cx.spawn_in(window, async move |editor, cx| {
17217            let Some(definitions) = definitions.await? else {
17218                return Ok(Navigated::No);
17219            };
17220            let navigated = editor
17221                .update_in(cx, |editor, window, cx| {
17222                    editor.navigate_to_hover_links(
17223                        Some(kind),
17224                        definitions
17225                            .into_iter()
17226                            .filter(|location| {
17227                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
17228                            })
17229                            .map(HoverLink::Text)
17230                            .collect::<Vec<_>>(),
17231                        split,
17232                        window,
17233                        cx,
17234                    )
17235                })?
17236                .await?;
17237            anyhow::Ok(navigated)
17238        })
17239    }
17240
17241    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
17242        let selection = self.selections.newest_anchor();
17243        let head = selection.head();
17244        let tail = selection.tail();
17245
17246        let Some((buffer, start_position)) =
17247            self.buffer.read(cx).text_anchor_for_position(head, cx)
17248        else {
17249            return;
17250        };
17251
17252        let end_position = if head != tail {
17253            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
17254                return;
17255            };
17256            Some(pos)
17257        } else {
17258            None
17259        };
17260
17261        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
17262            let url = if let Some(end_pos) = end_position {
17263                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
17264            } else {
17265                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
17266            };
17267
17268            if let Some(url) = url {
17269                cx.update(|window, cx| {
17270                    if parse_zed_link(&url, cx).is_some() {
17271                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
17272                    } else {
17273                        cx.open_url(&url);
17274                    }
17275                })?;
17276            }
17277
17278            anyhow::Ok(())
17279        });
17280
17281        url_finder.detach();
17282    }
17283
17284    pub fn open_selected_filename(
17285        &mut self,
17286        _: &OpenSelectedFilename,
17287        window: &mut Window,
17288        cx: &mut Context<Self>,
17289    ) {
17290        let Some(workspace) = self.workspace() else {
17291            return;
17292        };
17293
17294        let position = self.selections.newest_anchor().head();
17295
17296        let Some((buffer, buffer_position)) =
17297            self.buffer.read(cx).text_anchor_for_position(position, cx)
17298        else {
17299            return;
17300        };
17301
17302        let project = self.project.clone();
17303
17304        cx.spawn_in(window, async move |_, cx| {
17305            let result = find_file(&buffer, project, buffer_position, cx).await;
17306
17307            if let Some((_, path)) = result {
17308                workspace
17309                    .update_in(cx, |workspace, window, cx| {
17310                        workspace.open_resolved_path(path, window, cx)
17311                    })?
17312                    .await?;
17313            }
17314            anyhow::Ok(())
17315        })
17316        .detach();
17317    }
17318
17319    pub(crate) fn navigate_to_hover_links(
17320        &mut self,
17321        kind: Option<GotoDefinitionKind>,
17322        definitions: Vec<HoverLink>,
17323        split: bool,
17324        window: &mut Window,
17325        cx: &mut Context<Editor>,
17326    ) -> Task<Result<Navigated>> {
17327        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
17328        let mut first_url_or_file = None;
17329        let definitions: Vec<_> = definitions
17330            .into_iter()
17331            .filter_map(|def| match def {
17332                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
17333                HoverLink::InlayHint(lsp_location, server_id) => {
17334                    let computation =
17335                        self.compute_target_location(lsp_location, server_id, window, cx);
17336                    Some(cx.background_spawn(computation))
17337                }
17338                HoverLink::Url(url) => {
17339                    first_url_or_file = Some(Either::Left(url));
17340                    None
17341                }
17342                HoverLink::File(path) => {
17343                    first_url_or_file = Some(Either::Right(path));
17344                    None
17345                }
17346            })
17347            .collect();
17348
17349        let workspace = self.workspace();
17350
17351        cx.spawn_in(window, async move |editor, cx| {
17352            let locations: Vec<Location> = future::join_all(definitions)
17353                .await
17354                .into_iter()
17355                .filter_map(|location| location.transpose())
17356                .collect::<Result<_>>()
17357                .context("location tasks")?;
17358            let mut locations = cx.update(|_, cx| {
17359                locations
17360                    .into_iter()
17361                    .map(|location| {
17362                        let buffer = location.buffer.read(cx);
17363                        (location.buffer, location.range.to_point(buffer))
17364                    })
17365                    .into_group_map()
17366            })?;
17367            let mut num_locations = 0;
17368            for ranges in locations.values_mut() {
17369                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17370                ranges.dedup();
17371                num_locations += ranges.len();
17372            }
17373
17374            if num_locations > 1 {
17375                let tab_kind = match kind {
17376                    Some(GotoDefinitionKind::Implementation) => "Implementations",
17377                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
17378                    Some(GotoDefinitionKind::Declaration) => "Declarations",
17379                    Some(GotoDefinitionKind::Type) => "Types",
17380                };
17381                let title = editor
17382                    .update_in(cx, |_, _, cx| {
17383                        let target = locations
17384                            .iter()
17385                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17386                            .map(|(buffer, location)| {
17387                                buffer
17388                                    .read(cx)
17389                                    .text_for_range(location.clone())
17390                                    .collect::<String>()
17391                            })
17392                            .filter(|text| !text.contains('\n'))
17393                            .unique()
17394                            .take(3)
17395                            .join(", ");
17396                        if target.is_empty() {
17397                            tab_kind.to_owned()
17398                        } else {
17399                            format!("{tab_kind} for {target}")
17400                        }
17401                    })
17402                    .context("buffer title")?;
17403
17404                let Some(workspace) = workspace else {
17405                    return Ok(Navigated::No);
17406                };
17407
17408                let opened = workspace
17409                    .update_in(cx, |workspace, window, cx| {
17410                        let allow_preview = PreviewTabsSettings::get_global(cx)
17411                            .enable_preview_multibuffer_from_code_navigation;
17412                        Self::open_locations_in_multibuffer(
17413                            workspace,
17414                            locations,
17415                            title,
17416                            split,
17417                            allow_preview,
17418                            MultibufferSelectionMode::First,
17419                            window,
17420                            cx,
17421                        )
17422                    })
17423                    .is_ok();
17424
17425                anyhow::Ok(Navigated::from_bool(opened))
17426            } else if num_locations == 0 {
17427                // If there is one url or file, open it directly
17428                match first_url_or_file {
17429                    Some(Either::Left(url)) => {
17430                        cx.update(|_, cx| cx.open_url(&url))?;
17431                        Ok(Navigated::Yes)
17432                    }
17433                    Some(Either::Right(path)) => {
17434                        // TODO(andrew): respect preview tab settings
17435                        //               `enable_keep_preview_on_code_navigation` and
17436                        //               `enable_preview_file_from_code_navigation`
17437                        let Some(workspace) = workspace else {
17438                            return Ok(Navigated::No);
17439                        };
17440                        workspace
17441                            .update_in(cx, |workspace, window, cx| {
17442                                workspace.open_resolved_path(path, window, cx)
17443                            })?
17444                            .await?;
17445                        Ok(Navigated::Yes)
17446                    }
17447                    None => Ok(Navigated::No),
17448                }
17449            } else {
17450                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17451                let target_range = target_ranges.first().unwrap().clone();
17452
17453                editor.update_in(cx, |editor, window, cx| {
17454                    let range = target_range.to_point(target_buffer.read(cx));
17455                    let range = editor.range_for_match(&range);
17456                    let range = collapse_multiline_range(range);
17457
17458                    if !split
17459                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
17460                    {
17461                        editor.go_to_singleton_buffer_range(range, window, cx);
17462                    } else {
17463                        let Some(workspace) = workspace else {
17464                            return Navigated::No;
17465                        };
17466                        let pane = workspace.read(cx).active_pane().clone();
17467                        window.defer(cx, move |window, cx| {
17468                            let target_editor: Entity<Self> =
17469                                workspace.update(cx, |workspace, cx| {
17470                                    let pane = if split {
17471                                        workspace.adjacent_pane(window, cx)
17472                                    } else {
17473                                        workspace.active_pane().clone()
17474                                    };
17475
17476                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
17477                                    let keep_old_preview = preview_tabs_settings
17478                                        .enable_keep_preview_on_code_navigation;
17479                                    let allow_new_preview = preview_tabs_settings
17480                                        .enable_preview_file_from_code_navigation;
17481
17482                                    workspace.open_project_item(
17483                                        pane,
17484                                        target_buffer.clone(),
17485                                        true,
17486                                        true,
17487                                        keep_old_preview,
17488                                        allow_new_preview,
17489                                        window,
17490                                        cx,
17491                                    )
17492                                });
17493                            target_editor.update(cx, |target_editor, cx| {
17494                                // When selecting a definition in a different buffer, disable the nav history
17495                                // to avoid creating a history entry at the previous cursor location.
17496                                pane.update(cx, |pane, _| pane.disable_history());
17497                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17498                                pane.update(cx, |pane, _| pane.enable_history());
17499                            });
17500                        });
17501                    }
17502                    Navigated::Yes
17503                })
17504            }
17505        })
17506    }
17507
17508    fn compute_target_location(
17509        &self,
17510        lsp_location: lsp::Location,
17511        server_id: LanguageServerId,
17512        window: &mut Window,
17513        cx: &mut Context<Self>,
17514    ) -> Task<anyhow::Result<Option<Location>>> {
17515        let Some(project) = self.project.clone() else {
17516            return Task::ready(Ok(None));
17517        };
17518
17519        cx.spawn_in(window, async move |editor, cx| {
17520            let location_task = editor.update(cx, |_, cx| {
17521                project.update(cx, |project, cx| {
17522                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
17523                })
17524            })?;
17525            let location = Some({
17526                let target_buffer_handle = location_task.await.context("open local buffer")?;
17527                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
17528                    let target_start = target_buffer
17529                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
17530                    let target_end = target_buffer
17531                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
17532                    target_buffer.anchor_after(target_start)
17533                        ..target_buffer.anchor_before(target_end)
17534                })?;
17535                Location {
17536                    buffer: target_buffer_handle,
17537                    range,
17538                }
17539            });
17540            Ok(location)
17541        })
17542    }
17543
17544    fn go_to_next_reference(
17545        &mut self,
17546        _: &GoToNextReference,
17547        window: &mut Window,
17548        cx: &mut Context<Self>,
17549    ) {
17550        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
17551        if let Some(task) = task {
17552            task.detach();
17553        };
17554    }
17555
17556    fn go_to_prev_reference(
17557        &mut self,
17558        _: &GoToPreviousReference,
17559        window: &mut Window,
17560        cx: &mut Context<Self>,
17561    ) {
17562        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
17563        if let Some(task) = task {
17564            task.detach();
17565        };
17566    }
17567
17568    pub fn go_to_reference_before_or_after_position(
17569        &mut self,
17570        direction: Direction,
17571        count: usize,
17572        window: &mut Window,
17573        cx: &mut Context<Self>,
17574    ) -> Option<Task<Result<()>>> {
17575        let selection = self.selections.newest_anchor();
17576        let head = selection.head();
17577
17578        let multi_buffer = self.buffer.read(cx);
17579
17580        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
17581        let workspace = self.workspace()?;
17582        let project = workspace.read(cx).project().clone();
17583        let references =
17584            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
17585        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
17586            let Some(locations) = references.await? else {
17587                return Ok(());
17588            };
17589
17590            if locations.is_empty() {
17591                // totally normal - the cursor may be on something which is not
17592                // a symbol (e.g. a keyword)
17593                log::info!("no references found under cursor");
17594                return Ok(());
17595            }
17596
17597            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
17598
17599            let (locations, current_location_index) =
17600                multi_buffer.update(cx, |multi_buffer, cx| {
17601                    let mut locations = locations
17602                        .into_iter()
17603                        .filter_map(|loc| {
17604                            let start = multi_buffer.buffer_anchor_to_anchor(
17605                                &loc.buffer,
17606                                loc.range.start,
17607                                cx,
17608                            )?;
17609                            let end = multi_buffer.buffer_anchor_to_anchor(
17610                                &loc.buffer,
17611                                loc.range.end,
17612                                cx,
17613                            )?;
17614                            Some(start..end)
17615                        })
17616                        .collect::<Vec<_>>();
17617
17618                    let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17619                    // There is an O(n) implementation, but given this list will be
17620                    // small (usually <100 items), the extra O(log(n)) factor isn't
17621                    // worth the (surprisingly large amount of) extra complexity.
17622                    locations
17623                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
17624
17625                    let head_offset = head.to_offset(&multi_buffer_snapshot);
17626
17627                    let current_location_index = locations.iter().position(|loc| {
17628                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
17629                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
17630                    });
17631
17632                    (locations, current_location_index)
17633                })?;
17634
17635            let Some(current_location_index) = current_location_index else {
17636                // This indicates something has gone wrong, because we already
17637                // handle the "no references" case above
17638                log::error!(
17639                    "failed to find current reference under cursor. Total references: {}",
17640                    locations.len()
17641                );
17642                return Ok(());
17643            };
17644
17645            let destination_location_index = match direction {
17646                Direction::Next => (current_location_index + count) % locations.len(),
17647                Direction::Prev => {
17648                    (current_location_index + locations.len() - count % locations.len())
17649                        % locations.len()
17650                }
17651            };
17652
17653            // TODO(cameron): is this needed?
17654            // the thinking is to avoid "jumping to the current location" (avoid
17655            // polluting "jumplist" in vim terms)
17656            if current_location_index == destination_location_index {
17657                return Ok(());
17658            }
17659
17660            let Range { start, end } = locations[destination_location_index];
17661
17662            editor.update_in(cx, |editor, window, cx| {
17663                let effects = SelectionEffects::default();
17664
17665                editor.unfold_ranges(&[start..end], false, false, cx);
17666                editor.change_selections(effects, window, cx, |s| {
17667                    s.select_ranges([start..start]);
17668                });
17669            })?;
17670
17671            Ok(())
17672        }))
17673    }
17674
17675    pub fn find_all_references(
17676        &mut self,
17677        action: &FindAllReferences,
17678        window: &mut Window,
17679        cx: &mut Context<Self>,
17680    ) -> Option<Task<Result<Navigated>>> {
17681        let always_open_multibuffer = action.always_open_multibuffer;
17682        let selection = self.selections.newest_anchor();
17683        let multi_buffer = self.buffer.read(cx);
17684        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17685        let selection_offset = selection.map(|anchor| anchor.to_offset(&multi_buffer_snapshot));
17686        let selection_point = selection.map(|anchor| anchor.to_point(&multi_buffer_snapshot));
17687        let head = selection_offset.head();
17688
17689        let head_anchor = multi_buffer_snapshot.anchor_at(
17690            head,
17691            if head < selection_offset.tail() {
17692                Bias::Right
17693            } else {
17694                Bias::Left
17695            },
17696        );
17697
17698        match self
17699            .find_all_references_task_sources
17700            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17701        {
17702            Ok(_) => {
17703                log::info!(
17704                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
17705                );
17706                return None;
17707            }
17708            Err(i) => {
17709                self.find_all_references_task_sources.insert(i, head_anchor);
17710            }
17711        }
17712
17713        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
17714        let workspace = self.workspace()?;
17715        let project = workspace.read(cx).project().clone();
17716        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
17717        Some(cx.spawn_in(window, async move |editor, cx| {
17718            let _cleanup = cx.on_drop(&editor, move |editor, _| {
17719                if let Ok(i) = editor
17720                    .find_all_references_task_sources
17721                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17722                {
17723                    editor.find_all_references_task_sources.remove(i);
17724                }
17725            });
17726
17727            let Some(locations) = references.await? else {
17728                return anyhow::Ok(Navigated::No);
17729            };
17730            let mut locations = cx.update(|_, cx| {
17731                locations
17732                    .into_iter()
17733                    .map(|location| {
17734                        let buffer = location.buffer.read(cx);
17735                        (location.buffer, location.range.to_point(buffer))
17736                    })
17737                    // if special-casing the single-match case, remove ranges
17738                    // that intersect current selection
17739                    .filter(|(location_buffer, location)| {
17740                        if always_open_multibuffer || &buffer != location_buffer {
17741                            return true;
17742                        }
17743
17744                        !location.contains_inclusive(&selection_point.range())
17745                    })
17746                    .into_group_map()
17747            })?;
17748            if locations.is_empty() {
17749                return anyhow::Ok(Navigated::No);
17750            }
17751            for ranges in locations.values_mut() {
17752                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17753                ranges.dedup();
17754            }
17755            let mut num_locations = 0;
17756            for ranges in locations.values_mut() {
17757                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17758                ranges.dedup();
17759                num_locations += ranges.len();
17760            }
17761
17762            if num_locations == 1 && !always_open_multibuffer {
17763                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17764                let target_range = target_ranges.first().unwrap().clone();
17765
17766                return editor.update_in(cx, |editor, window, cx| {
17767                    let range = target_range.to_point(target_buffer.read(cx));
17768                    let range = editor.range_for_match(&range);
17769                    let range = range.start..range.start;
17770
17771                    if Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref() {
17772                        editor.go_to_singleton_buffer_range(range, window, cx);
17773                    } else {
17774                        let pane = workspace.read(cx).active_pane().clone();
17775                        window.defer(cx, move |window, cx| {
17776                            let target_editor: Entity<Self> =
17777                                workspace.update(cx, |workspace, cx| {
17778                                    let pane = workspace.active_pane().clone();
17779
17780                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
17781                                    let keep_old_preview = preview_tabs_settings
17782                                        .enable_keep_preview_on_code_navigation;
17783                                    let allow_new_preview = preview_tabs_settings
17784                                        .enable_preview_file_from_code_navigation;
17785
17786                                    workspace.open_project_item(
17787                                        pane,
17788                                        target_buffer.clone(),
17789                                        true,
17790                                        true,
17791                                        keep_old_preview,
17792                                        allow_new_preview,
17793                                        window,
17794                                        cx,
17795                                    )
17796                                });
17797                            target_editor.update(cx, |target_editor, cx| {
17798                                // When selecting a definition in a different buffer, disable the nav history
17799                                // to avoid creating a history entry at the previous cursor location.
17800                                pane.update(cx, |pane, _| pane.disable_history());
17801                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17802                                pane.update(cx, |pane, _| pane.enable_history());
17803                            });
17804                        });
17805                    }
17806                    Navigated::No
17807                });
17808            }
17809
17810            workspace.update_in(cx, |workspace, window, cx| {
17811                let target = locations
17812                    .iter()
17813                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17814                    .map(|(buffer, location)| {
17815                        buffer
17816                            .read(cx)
17817                            .text_for_range(location.clone())
17818                            .collect::<String>()
17819                    })
17820                    .filter(|text| !text.contains('\n'))
17821                    .unique()
17822                    .take(3)
17823                    .join(", ");
17824                let title = if target.is_empty() {
17825                    "References".to_owned()
17826                } else {
17827                    format!("References to {target}")
17828                };
17829                let allow_preview = PreviewTabsSettings::get_global(cx)
17830                    .enable_preview_multibuffer_from_code_navigation;
17831                Self::open_locations_in_multibuffer(
17832                    workspace,
17833                    locations,
17834                    title,
17835                    false,
17836                    allow_preview,
17837                    MultibufferSelectionMode::First,
17838                    window,
17839                    cx,
17840                );
17841                Navigated::Yes
17842            })
17843        }))
17844    }
17845
17846    /// Opens a multibuffer with the given project locations in it.
17847    pub fn open_locations_in_multibuffer(
17848        workspace: &mut Workspace,
17849        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
17850        title: String,
17851        split: bool,
17852        allow_preview: bool,
17853        multibuffer_selection_mode: MultibufferSelectionMode,
17854        window: &mut Window,
17855        cx: &mut Context<Workspace>,
17856    ) {
17857        if locations.is_empty() {
17858            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
17859            return;
17860        }
17861
17862        let capability = workspace.project().read(cx).capability();
17863        let mut ranges = <Vec<Range<Anchor>>>::new();
17864
17865        // a key to find existing multibuffer editors with the same set of locations
17866        // to prevent us from opening more and more multibuffer tabs for searches and the like
17867        let mut key = (title.clone(), vec![]);
17868        let excerpt_buffer = cx.new(|cx| {
17869            let key = &mut key.1;
17870            let mut multibuffer = MultiBuffer::new(capability);
17871            for (buffer, mut ranges_for_buffer) in locations {
17872                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17873                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17874                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17875                    PathKey::for_buffer(&buffer, cx),
17876                    buffer.clone(),
17877                    ranges_for_buffer,
17878                    multibuffer_context_lines(cx),
17879                    cx,
17880                );
17881                ranges.extend(new_ranges)
17882            }
17883
17884            multibuffer.with_title(title)
17885        });
17886        let existing = workspace.active_pane().update(cx, |pane, cx| {
17887            pane.items()
17888                .filter_map(|item| item.downcast::<Editor>())
17889                .find(|editor| {
17890                    editor
17891                        .read(cx)
17892                        .lookup_key
17893                        .as_ref()
17894                        .and_then(|it| {
17895                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17896                        })
17897                        .is_some_and(|it| *it == key)
17898                })
17899        });
17900        let was_existing = existing.is_some();
17901        let editor = existing.unwrap_or_else(|| {
17902            cx.new(|cx| {
17903                let mut editor = Editor::for_multibuffer(
17904                    excerpt_buffer,
17905                    Some(workspace.project().clone()),
17906                    window,
17907                    cx,
17908                );
17909                editor.lookup_key = Some(Box::new(key));
17910                editor
17911            })
17912        });
17913        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17914            MultibufferSelectionMode::First => {
17915                if let Some(first_range) = ranges.first() {
17916                    editor.change_selections(
17917                        SelectionEffects::no_scroll(),
17918                        window,
17919                        cx,
17920                        |selections| {
17921                            selections.clear_disjoint();
17922                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17923                        },
17924                    );
17925                }
17926                editor.highlight_background::<Self>(
17927                    &ranges,
17928                    |_, theme| theme.colors().editor_highlighted_line_background,
17929                    cx,
17930                );
17931            }
17932            MultibufferSelectionMode::All => {
17933                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17934                    selections.clear_disjoint();
17935                    selections.select_anchor_ranges(ranges);
17936                });
17937            }
17938        });
17939
17940        let item = Box::new(editor);
17941
17942        let pane = if split {
17943            workspace.adjacent_pane(window, cx)
17944        } else {
17945            workspace.active_pane().clone()
17946        };
17947        let activate_pane = split;
17948
17949        let mut destination_index = None;
17950        pane.update(cx, |pane, cx| {
17951            if allow_preview && !was_existing {
17952                destination_index = pane.replace_preview_item_id(item.item_id(), window, cx);
17953            }
17954            if was_existing && !allow_preview {
17955                pane.unpreview_item_if_preview(item.item_id());
17956            }
17957            pane.add_item(item, activate_pane, true, destination_index, window, cx);
17958        });
17959    }
17960
17961    pub fn rename(
17962        &mut self,
17963        _: &Rename,
17964        window: &mut Window,
17965        cx: &mut Context<Self>,
17966    ) -> Option<Task<Result<()>>> {
17967        use language::ToOffset as _;
17968
17969        let provider = self.semantics_provider.clone()?;
17970        let selection = self.selections.newest_anchor().clone();
17971        let (cursor_buffer, cursor_buffer_position) = self
17972            .buffer
17973            .read(cx)
17974            .text_anchor_for_position(selection.head(), cx)?;
17975        let (tail_buffer, cursor_buffer_position_end) = self
17976            .buffer
17977            .read(cx)
17978            .text_anchor_for_position(selection.tail(), cx)?;
17979        if tail_buffer != cursor_buffer {
17980            return None;
17981        }
17982
17983        let snapshot = cursor_buffer.read(cx).snapshot();
17984        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
17985        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
17986        let prepare_rename = provider
17987            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
17988            .unwrap_or_else(|| Task::ready(Ok(None)));
17989        drop(snapshot);
17990
17991        Some(cx.spawn_in(window, async move |this, cx| {
17992            let rename_range = if let Some(range) = prepare_rename.await? {
17993                Some(range)
17994            } else {
17995                this.update(cx, |this, cx| {
17996                    let buffer = this.buffer.read(cx).snapshot(cx);
17997                    let mut buffer_highlights = this
17998                        .document_highlights_for_position(selection.head(), &buffer)
17999                        .filter(|highlight| {
18000                            highlight.start.excerpt_id == selection.head().excerpt_id
18001                                && highlight.end.excerpt_id == selection.head().excerpt_id
18002                        });
18003                    buffer_highlights
18004                        .next()
18005                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
18006                })?
18007            };
18008            if let Some(rename_range) = rename_range {
18009                this.update_in(cx, |this, window, cx| {
18010                    let snapshot = cursor_buffer.read(cx).snapshot();
18011                    let rename_buffer_range = rename_range.to_offset(&snapshot);
18012                    let cursor_offset_in_rename_range =
18013                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
18014                    let cursor_offset_in_rename_range_end =
18015                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
18016
18017                    this.take_rename(false, window, cx);
18018                    let buffer = this.buffer.read(cx).read(cx);
18019                    let cursor_offset = selection.head().to_offset(&buffer);
18020                    let rename_start =
18021                        cursor_offset.saturating_sub_usize(cursor_offset_in_rename_range);
18022                    let rename_end = rename_start + rename_buffer_range.len();
18023                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
18024                    let mut old_highlight_id = None;
18025                    let old_name: Arc<str> = buffer
18026                        .chunks(rename_start..rename_end, true)
18027                        .map(|chunk| {
18028                            if old_highlight_id.is_none() {
18029                                old_highlight_id = chunk.syntax_highlight_id;
18030                            }
18031                            chunk.text
18032                        })
18033                        .collect::<String>()
18034                        .into();
18035
18036                    drop(buffer);
18037
18038                    // Position the selection in the rename editor so that it matches the current selection.
18039                    this.show_local_selections = false;
18040                    let rename_editor = cx.new(|cx| {
18041                        let mut editor = Editor::single_line(window, cx);
18042                        editor.buffer.update(cx, |buffer, cx| {
18043                            buffer.edit(
18044                                [(MultiBufferOffset(0)..MultiBufferOffset(0), old_name.clone())],
18045                                None,
18046                                cx,
18047                            )
18048                        });
18049                        let cursor_offset_in_rename_range =
18050                            MultiBufferOffset(cursor_offset_in_rename_range);
18051                        let cursor_offset_in_rename_range_end =
18052                            MultiBufferOffset(cursor_offset_in_rename_range_end);
18053                        let rename_selection_range = match cursor_offset_in_rename_range
18054                            .cmp(&cursor_offset_in_rename_range_end)
18055                        {
18056                            Ordering::Equal => {
18057                                editor.select_all(&SelectAll, window, cx);
18058                                return editor;
18059                            }
18060                            Ordering::Less => {
18061                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
18062                            }
18063                            Ordering::Greater => {
18064                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
18065                            }
18066                        };
18067                        if rename_selection_range.end.0 > old_name.len() {
18068                            editor.select_all(&SelectAll, window, cx);
18069                        } else {
18070                            editor.change_selections(Default::default(), window, cx, |s| {
18071                                s.select_ranges([rename_selection_range]);
18072                            });
18073                        }
18074                        editor
18075                    });
18076                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
18077                        if e == &EditorEvent::Focused {
18078                            cx.emit(EditorEvent::FocusedIn)
18079                        }
18080                    })
18081                    .detach();
18082
18083                    let write_highlights =
18084                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
18085                    let read_highlights =
18086                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
18087                    let ranges = write_highlights
18088                        .iter()
18089                        .flat_map(|(_, ranges)| ranges.iter())
18090                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
18091                        .cloned()
18092                        .collect();
18093
18094                    this.highlight_text::<Rename>(
18095                        ranges,
18096                        HighlightStyle {
18097                            fade_out: Some(0.6),
18098                            ..Default::default()
18099                        },
18100                        cx,
18101                    );
18102                    let rename_focus_handle = rename_editor.focus_handle(cx);
18103                    window.focus(&rename_focus_handle);
18104                    let block_id = this.insert_blocks(
18105                        [BlockProperties {
18106                            style: BlockStyle::Flex,
18107                            placement: BlockPlacement::Below(range.start),
18108                            height: Some(1),
18109                            render: Arc::new({
18110                                let rename_editor = rename_editor.clone();
18111                                move |cx: &mut BlockContext| {
18112                                    let mut text_style = cx.editor_style.text.clone();
18113                                    if let Some(highlight_style) = old_highlight_id
18114                                        .and_then(|h| h.style(&cx.editor_style.syntax))
18115                                    {
18116                                        text_style = text_style.highlight(highlight_style);
18117                                    }
18118                                    div()
18119                                        .block_mouse_except_scroll()
18120                                        .pl(cx.anchor_x)
18121                                        .child(EditorElement::new(
18122                                            &rename_editor,
18123                                            EditorStyle {
18124                                                background: cx.theme().system().transparent,
18125                                                local_player: cx.editor_style.local_player,
18126                                                text: text_style,
18127                                                scrollbar_width: cx.editor_style.scrollbar_width,
18128                                                syntax: cx.editor_style.syntax.clone(),
18129                                                status: cx.editor_style.status.clone(),
18130                                                inlay_hints_style: HighlightStyle {
18131                                                    font_weight: Some(FontWeight::BOLD),
18132                                                    ..make_inlay_hints_style(cx.app)
18133                                                },
18134                                                edit_prediction_styles: make_suggestion_styles(
18135                                                    cx.app,
18136                                                ),
18137                                                ..EditorStyle::default()
18138                                            },
18139                                        ))
18140                                        .into_any_element()
18141                                }
18142                            }),
18143                            priority: 0,
18144                        }],
18145                        Some(Autoscroll::fit()),
18146                        cx,
18147                    )[0];
18148                    this.pending_rename = Some(RenameState {
18149                        range,
18150                        old_name,
18151                        editor: rename_editor,
18152                        block_id,
18153                    });
18154                })?;
18155            }
18156
18157            Ok(())
18158        }))
18159    }
18160
18161    pub fn confirm_rename(
18162        &mut self,
18163        _: &ConfirmRename,
18164        window: &mut Window,
18165        cx: &mut Context<Self>,
18166    ) -> Option<Task<Result<()>>> {
18167        let rename = self.take_rename(false, window, cx)?;
18168        let workspace = self.workspace()?.downgrade();
18169        let (buffer, start) = self
18170            .buffer
18171            .read(cx)
18172            .text_anchor_for_position(rename.range.start, cx)?;
18173        let (end_buffer, _) = self
18174            .buffer
18175            .read(cx)
18176            .text_anchor_for_position(rename.range.end, cx)?;
18177        if buffer != end_buffer {
18178            return None;
18179        }
18180
18181        let old_name = rename.old_name;
18182        let new_name = rename.editor.read(cx).text(cx);
18183
18184        let rename = self.semantics_provider.as_ref()?.perform_rename(
18185            &buffer,
18186            start,
18187            new_name.clone(),
18188            cx,
18189        )?;
18190
18191        Some(cx.spawn_in(window, async move |editor, cx| {
18192            let project_transaction = rename.await?;
18193            Self::open_project_transaction(
18194                &editor,
18195                workspace,
18196                project_transaction,
18197                format!("Rename: {}{}", old_name, new_name),
18198                cx,
18199            )
18200            .await?;
18201
18202            editor.update(cx, |editor, cx| {
18203                editor.refresh_document_highlights(cx);
18204            })?;
18205            Ok(())
18206        }))
18207    }
18208
18209    fn take_rename(
18210        &mut self,
18211        moving_cursor: bool,
18212        window: &mut Window,
18213        cx: &mut Context<Self>,
18214    ) -> Option<RenameState> {
18215        let rename = self.pending_rename.take()?;
18216        if rename.editor.focus_handle(cx).is_focused(window) {
18217            window.focus(&self.focus_handle);
18218        }
18219
18220        self.remove_blocks(
18221            [rename.block_id].into_iter().collect(),
18222            Some(Autoscroll::fit()),
18223            cx,
18224        );
18225        self.clear_highlights::<Rename>(cx);
18226        self.show_local_selections = true;
18227
18228        if moving_cursor {
18229            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
18230                editor
18231                    .selections
18232                    .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
18233                    .head()
18234            });
18235
18236            // Update the selection to match the position of the selection inside
18237            // the rename editor.
18238            let snapshot = self.buffer.read(cx).read(cx);
18239            let rename_range = rename.range.to_offset(&snapshot);
18240            let cursor_in_editor = snapshot
18241                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
18242                .min(rename_range.end);
18243            drop(snapshot);
18244
18245            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18246                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
18247            });
18248        } else {
18249            self.refresh_document_highlights(cx);
18250        }
18251
18252        Some(rename)
18253    }
18254
18255    pub fn pending_rename(&self) -> Option<&RenameState> {
18256        self.pending_rename.as_ref()
18257    }
18258
18259    fn format(
18260        &mut self,
18261        _: &Format,
18262        window: &mut Window,
18263        cx: &mut Context<Self>,
18264    ) -> Option<Task<Result<()>>> {
18265        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18266
18267        let project = match &self.project {
18268            Some(project) => project.clone(),
18269            None => return None,
18270        };
18271
18272        Some(self.perform_format(
18273            project,
18274            FormatTrigger::Manual,
18275            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
18276            window,
18277            cx,
18278        ))
18279    }
18280
18281    fn format_selections(
18282        &mut self,
18283        _: &FormatSelections,
18284        window: &mut Window,
18285        cx: &mut Context<Self>,
18286    ) -> Option<Task<Result<()>>> {
18287        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18288
18289        let project = match &self.project {
18290            Some(project) => project.clone(),
18291            None => return None,
18292        };
18293
18294        let ranges = self
18295            .selections
18296            .all_adjusted(&self.display_snapshot(cx))
18297            .into_iter()
18298            .map(|selection| selection.range())
18299            .collect_vec();
18300
18301        Some(self.perform_format(
18302            project,
18303            FormatTrigger::Manual,
18304            FormatTarget::Ranges(ranges),
18305            window,
18306            cx,
18307        ))
18308    }
18309
18310    fn perform_format(
18311        &mut self,
18312        project: Entity<Project>,
18313        trigger: FormatTrigger,
18314        target: FormatTarget,
18315        window: &mut Window,
18316        cx: &mut Context<Self>,
18317    ) -> Task<Result<()>> {
18318        let buffer = self.buffer.clone();
18319        let (buffers, target) = match target {
18320            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
18321            FormatTarget::Ranges(selection_ranges) => {
18322                let multi_buffer = buffer.read(cx);
18323                let snapshot = multi_buffer.read(cx);
18324                let mut buffers = HashSet::default();
18325                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
18326                    BTreeMap::new();
18327                for selection_range in selection_ranges {
18328                    for (buffer, buffer_range, _) in
18329                        snapshot.range_to_buffer_ranges(selection_range)
18330                    {
18331                        let buffer_id = buffer.remote_id();
18332                        let start = buffer.anchor_before(buffer_range.start);
18333                        let end = buffer.anchor_after(buffer_range.end);
18334                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
18335                        buffer_id_to_ranges
18336                            .entry(buffer_id)
18337                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
18338                            .or_insert_with(|| vec![start..end]);
18339                    }
18340                }
18341                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
18342            }
18343        };
18344
18345        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
18346        let selections_prev = transaction_id_prev
18347            .and_then(|transaction_id_prev| {
18348                // default to selections as they were after the last edit, if we have them,
18349                // instead of how they are now.
18350                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
18351                // will take you back to where you made the last edit, instead of staying where you scrolled
18352                self.selection_history
18353                    .transaction(transaction_id_prev)
18354                    .map(|t| t.0.clone())
18355            })
18356            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
18357
18358        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
18359        let format = project.update(cx, |project, cx| {
18360            project.format(buffers, target, true, trigger, cx)
18361        });
18362
18363        cx.spawn_in(window, async move |editor, cx| {
18364            let transaction = futures::select_biased! {
18365                transaction = format.log_err().fuse() => transaction,
18366                () = timeout => {
18367                    log::warn!("timed out waiting for formatting");
18368                    None
18369                }
18370            };
18371
18372            buffer
18373                .update(cx, |buffer, cx| {
18374                    if let Some(transaction) = transaction
18375                        && !buffer.is_singleton()
18376                    {
18377                        buffer.push_transaction(&transaction.0, cx);
18378                    }
18379                    cx.notify();
18380                })
18381                .ok();
18382
18383            if let Some(transaction_id_now) =
18384                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
18385            {
18386                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
18387                if has_new_transaction {
18388                    _ = editor.update(cx, |editor, _| {
18389                        editor
18390                            .selection_history
18391                            .insert_transaction(transaction_id_now, selections_prev);
18392                    });
18393                }
18394            }
18395
18396            Ok(())
18397        })
18398    }
18399
18400    fn organize_imports(
18401        &mut self,
18402        _: &OrganizeImports,
18403        window: &mut Window,
18404        cx: &mut Context<Self>,
18405    ) -> Option<Task<Result<()>>> {
18406        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18407        let project = match &self.project {
18408            Some(project) => project.clone(),
18409            None => return None,
18410        };
18411        Some(self.perform_code_action_kind(
18412            project,
18413            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
18414            window,
18415            cx,
18416        ))
18417    }
18418
18419    fn perform_code_action_kind(
18420        &mut self,
18421        project: Entity<Project>,
18422        kind: CodeActionKind,
18423        window: &mut Window,
18424        cx: &mut Context<Self>,
18425    ) -> Task<Result<()>> {
18426        let buffer = self.buffer.clone();
18427        let buffers = buffer.read(cx).all_buffers();
18428        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
18429        let apply_action = project.update(cx, |project, cx| {
18430            project.apply_code_action_kind(buffers, kind, true, cx)
18431        });
18432        cx.spawn_in(window, async move |_, cx| {
18433            let transaction = futures::select_biased! {
18434                () = timeout => {
18435                    log::warn!("timed out waiting for executing code action");
18436                    None
18437                }
18438                transaction = apply_action.log_err().fuse() => transaction,
18439            };
18440            buffer
18441                .update(cx, |buffer, cx| {
18442                    // check if we need this
18443                    if let Some(transaction) = transaction
18444                        && !buffer.is_singleton()
18445                    {
18446                        buffer.push_transaction(&transaction.0, cx);
18447                    }
18448                    cx.notify();
18449                })
18450                .ok();
18451            Ok(())
18452        })
18453    }
18454
18455    pub fn restart_language_server(
18456        &mut self,
18457        _: &RestartLanguageServer,
18458        _: &mut Window,
18459        cx: &mut Context<Self>,
18460    ) {
18461        if let Some(project) = self.project.clone() {
18462            self.buffer.update(cx, |multi_buffer, cx| {
18463                project.update(cx, |project, cx| {
18464                    project.restart_language_servers_for_buffers(
18465                        multi_buffer.all_buffers().into_iter().collect(),
18466                        HashSet::default(),
18467                        cx,
18468                    );
18469                });
18470            })
18471        }
18472    }
18473
18474    pub fn stop_language_server(
18475        &mut self,
18476        _: &StopLanguageServer,
18477        _: &mut Window,
18478        cx: &mut Context<Self>,
18479    ) {
18480        if let Some(project) = self.project.clone() {
18481            self.buffer.update(cx, |multi_buffer, cx| {
18482                project.update(cx, |project, cx| {
18483                    project.stop_language_servers_for_buffers(
18484                        multi_buffer.all_buffers().into_iter().collect(),
18485                        HashSet::default(),
18486                        cx,
18487                    );
18488                });
18489            });
18490            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18491        }
18492    }
18493
18494    fn cancel_language_server_work(
18495        workspace: &mut Workspace,
18496        _: &actions::CancelLanguageServerWork,
18497        _: &mut Window,
18498        cx: &mut Context<Workspace>,
18499    ) {
18500        let project = workspace.project();
18501        let buffers = workspace
18502            .active_item(cx)
18503            .and_then(|item| item.act_as::<Editor>(cx))
18504            .map_or(HashSet::default(), |editor| {
18505                editor.read(cx).buffer.read(cx).all_buffers()
18506            });
18507        project.update(cx, |project, cx| {
18508            project.cancel_language_server_work_for_buffers(buffers, cx);
18509        });
18510    }
18511
18512    fn show_character_palette(
18513        &mut self,
18514        _: &ShowCharacterPalette,
18515        window: &mut Window,
18516        _: &mut Context<Self>,
18517    ) {
18518        window.show_character_palette();
18519    }
18520
18521    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
18522        if !self.diagnostics_enabled() {
18523            return;
18524        }
18525
18526        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
18527            let buffer = self.buffer.read(cx).snapshot(cx);
18528            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
18529            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
18530            let is_valid = buffer
18531                .diagnostics_in_range::<MultiBufferOffset>(primary_range_start..primary_range_end)
18532                .any(|entry| {
18533                    entry.diagnostic.is_primary
18534                        && !entry.range.is_empty()
18535                        && entry.range.start == primary_range_start
18536                        && entry.diagnostic.message == active_diagnostics.active_message
18537                });
18538
18539            if !is_valid {
18540                self.dismiss_diagnostics(cx);
18541            }
18542        }
18543    }
18544
18545    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
18546        match &self.active_diagnostics {
18547            ActiveDiagnostic::Group(group) => Some(group),
18548            _ => None,
18549        }
18550    }
18551
18552    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
18553        if !self.diagnostics_enabled() {
18554            return;
18555        }
18556        self.dismiss_diagnostics(cx);
18557        self.active_diagnostics = ActiveDiagnostic::All;
18558    }
18559
18560    fn activate_diagnostics(
18561        &mut self,
18562        buffer_id: BufferId,
18563        diagnostic: DiagnosticEntryRef<'_, MultiBufferOffset>,
18564        window: &mut Window,
18565        cx: &mut Context<Self>,
18566    ) {
18567        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18568            return;
18569        }
18570        self.dismiss_diagnostics(cx);
18571        let snapshot = self.snapshot(window, cx);
18572        let buffer = self.buffer.read(cx).snapshot(cx);
18573        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
18574            return;
18575        };
18576
18577        let diagnostic_group = buffer
18578            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
18579            .collect::<Vec<_>>();
18580
18581        let language_registry = self
18582            .project()
18583            .map(|project| project.read(cx).languages().clone());
18584
18585        let blocks = renderer.render_group(
18586            diagnostic_group,
18587            buffer_id,
18588            snapshot,
18589            cx.weak_entity(),
18590            language_registry,
18591            cx,
18592        );
18593
18594        let blocks = self.display_map.update(cx, |display_map, cx| {
18595            display_map.insert_blocks(blocks, cx).into_iter().collect()
18596        });
18597        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
18598            active_range: buffer.anchor_before(diagnostic.range.start)
18599                ..buffer.anchor_after(diagnostic.range.end),
18600            active_message: diagnostic.diagnostic.message.clone(),
18601            group_id: diagnostic.diagnostic.group_id,
18602            blocks,
18603        });
18604        cx.notify();
18605    }
18606
18607    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
18608        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18609            return;
18610        };
18611
18612        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
18613        if let ActiveDiagnostic::Group(group) = prev {
18614            self.display_map.update(cx, |display_map, cx| {
18615                display_map.remove_blocks(group.blocks, cx);
18616            });
18617            cx.notify();
18618        }
18619    }
18620
18621    /// Disable inline diagnostics rendering for this editor.
18622    pub fn disable_inline_diagnostics(&mut self) {
18623        self.inline_diagnostics_enabled = false;
18624        self.inline_diagnostics_update = Task::ready(());
18625        self.inline_diagnostics.clear();
18626    }
18627
18628    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
18629        self.diagnostics_enabled = false;
18630        self.dismiss_diagnostics(cx);
18631        self.inline_diagnostics_update = Task::ready(());
18632        self.inline_diagnostics.clear();
18633    }
18634
18635    pub fn disable_word_completions(&mut self) {
18636        self.word_completions_enabled = false;
18637    }
18638
18639    pub fn diagnostics_enabled(&self) -> bool {
18640        self.diagnostics_enabled && self.mode.is_full()
18641    }
18642
18643    pub fn inline_diagnostics_enabled(&self) -> bool {
18644        self.inline_diagnostics_enabled && self.diagnostics_enabled()
18645    }
18646
18647    pub fn show_inline_diagnostics(&self) -> bool {
18648        self.show_inline_diagnostics
18649    }
18650
18651    pub fn toggle_inline_diagnostics(
18652        &mut self,
18653        _: &ToggleInlineDiagnostics,
18654        window: &mut Window,
18655        cx: &mut Context<Editor>,
18656    ) {
18657        self.show_inline_diagnostics = !self.show_inline_diagnostics;
18658        self.refresh_inline_diagnostics(false, window, cx);
18659    }
18660
18661    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
18662        self.diagnostics_max_severity = severity;
18663        self.display_map.update(cx, |display_map, _| {
18664            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
18665        });
18666    }
18667
18668    pub fn toggle_diagnostics(
18669        &mut self,
18670        _: &ToggleDiagnostics,
18671        window: &mut Window,
18672        cx: &mut Context<Editor>,
18673    ) {
18674        if !self.diagnostics_enabled() {
18675            return;
18676        }
18677
18678        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18679            EditorSettings::get_global(cx)
18680                .diagnostics_max_severity
18681                .filter(|severity| severity != &DiagnosticSeverity::Off)
18682                .unwrap_or(DiagnosticSeverity::Hint)
18683        } else {
18684            DiagnosticSeverity::Off
18685        };
18686        self.set_max_diagnostics_severity(new_severity, cx);
18687        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18688            self.active_diagnostics = ActiveDiagnostic::None;
18689            self.inline_diagnostics_update = Task::ready(());
18690            self.inline_diagnostics.clear();
18691        } else {
18692            self.refresh_inline_diagnostics(false, window, cx);
18693        }
18694
18695        cx.notify();
18696    }
18697
18698    pub fn toggle_minimap(
18699        &mut self,
18700        _: &ToggleMinimap,
18701        window: &mut Window,
18702        cx: &mut Context<Editor>,
18703    ) {
18704        if self.supports_minimap(cx) {
18705            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
18706        }
18707    }
18708
18709    fn refresh_inline_diagnostics(
18710        &mut self,
18711        debounce: bool,
18712        window: &mut Window,
18713        cx: &mut Context<Self>,
18714    ) {
18715        let max_severity = ProjectSettings::get_global(cx)
18716            .diagnostics
18717            .inline
18718            .max_severity
18719            .unwrap_or(self.diagnostics_max_severity);
18720
18721        if !self.inline_diagnostics_enabled()
18722            || !self.diagnostics_enabled()
18723            || !self.show_inline_diagnostics
18724            || max_severity == DiagnosticSeverity::Off
18725        {
18726            self.inline_diagnostics_update = Task::ready(());
18727            self.inline_diagnostics.clear();
18728            return;
18729        }
18730
18731        let debounce_ms = ProjectSettings::get_global(cx)
18732            .diagnostics
18733            .inline
18734            .update_debounce_ms;
18735        let debounce = if debounce && debounce_ms > 0 {
18736            Some(Duration::from_millis(debounce_ms))
18737        } else {
18738            None
18739        };
18740        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
18741            if let Some(debounce) = debounce {
18742                cx.background_executor().timer(debounce).await;
18743            }
18744            let Some(snapshot) = editor.upgrade().and_then(|editor| {
18745                editor
18746                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
18747                    .ok()
18748            }) else {
18749                return;
18750            };
18751
18752            let new_inline_diagnostics = cx
18753                .background_spawn(async move {
18754                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
18755                    for diagnostic_entry in
18756                        snapshot.diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
18757                    {
18758                        let message = diagnostic_entry
18759                            .diagnostic
18760                            .message
18761                            .split_once('\n')
18762                            .map(|(line, _)| line)
18763                            .map(SharedString::new)
18764                            .unwrap_or_else(|| {
18765                                SharedString::new(&*diagnostic_entry.diagnostic.message)
18766                            });
18767                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
18768                        let (Ok(i) | Err(i)) = inline_diagnostics
18769                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
18770                        inline_diagnostics.insert(
18771                            i,
18772                            (
18773                                start_anchor,
18774                                InlineDiagnostic {
18775                                    message,
18776                                    group_id: diagnostic_entry.diagnostic.group_id,
18777                                    start: diagnostic_entry.range.start.to_point(&snapshot),
18778                                    is_primary: diagnostic_entry.diagnostic.is_primary,
18779                                    severity: diagnostic_entry.diagnostic.severity,
18780                                },
18781                            ),
18782                        );
18783                    }
18784                    inline_diagnostics
18785                })
18786                .await;
18787
18788            editor
18789                .update(cx, |editor, cx| {
18790                    editor.inline_diagnostics = new_inline_diagnostics;
18791                    cx.notify();
18792                })
18793                .ok();
18794        });
18795    }
18796
18797    fn pull_diagnostics(
18798        &mut self,
18799        buffer_id: Option<BufferId>,
18800        window: &Window,
18801        cx: &mut Context<Self>,
18802    ) -> Option<()> {
18803        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
18804            return None;
18805        }
18806        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
18807            .diagnostics
18808            .lsp_pull_diagnostics;
18809        if !pull_diagnostics_settings.enabled {
18810            return None;
18811        }
18812        let project = self.project()?.downgrade();
18813
18814        let mut edited_buffer_ids = HashSet::default();
18815        let mut edited_worktree_ids = HashSet::default();
18816        let edited_buffers = match buffer_id {
18817            Some(buffer_id) => {
18818                let buffer = self.buffer().read(cx).buffer(buffer_id)?;
18819                let worktree_id = buffer.read(cx).file().map(|f| f.worktree_id(cx))?;
18820                edited_buffer_ids.insert(buffer.read(cx).remote_id());
18821                edited_worktree_ids.insert(worktree_id);
18822                vec![buffer]
18823            }
18824            None => self
18825                .buffer()
18826                .read(cx)
18827                .all_buffers()
18828                .into_iter()
18829                .filter(|buffer| {
18830                    let buffer = buffer.read(cx);
18831                    match buffer.file().map(|f| f.worktree_id(cx)) {
18832                        Some(worktree_id) => {
18833                            edited_buffer_ids.insert(buffer.remote_id());
18834                            edited_worktree_ids.insert(worktree_id);
18835                            true
18836                        }
18837                        None => false,
18838                    }
18839                })
18840                .collect::<Vec<_>>(),
18841        };
18842
18843        if edited_buffers.is_empty() {
18844            self.pull_diagnostics_task = Task::ready(());
18845            self.pull_diagnostics_background_task = Task::ready(());
18846            return None;
18847        }
18848
18849        let mut already_used_buffers = HashSet::default();
18850        let related_open_buffers = self
18851            .workspace
18852            .as_ref()
18853            .and_then(|(workspace, _)| workspace.upgrade())
18854            .into_iter()
18855            .flat_map(|workspace| workspace.read(cx).panes())
18856            .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
18857            .filter(|editor| editor != &cx.entity())
18858            .flat_map(|editor| editor.read(cx).buffer().read(cx).all_buffers())
18859            .filter(|buffer| {
18860                let buffer = buffer.read(cx);
18861                let buffer_id = buffer.remote_id();
18862                if already_used_buffers.insert(buffer_id) {
18863                    if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx)) {
18864                        return !edited_buffer_ids.contains(&buffer_id)
18865                            && !edited_worktree_ids.contains(&worktree_id);
18866                    }
18867                }
18868                false
18869            })
18870            .collect::<Vec<_>>();
18871
18872        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
18873        let make_spawn = |buffers: Vec<Entity<Buffer>>, delay: Duration| {
18874            if buffers.is_empty() {
18875                return Task::ready(());
18876            }
18877            let project_weak = project.clone();
18878            cx.spawn_in(window, async move |_, cx| {
18879                cx.background_executor().timer(delay).await;
18880
18881                let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
18882                    buffers
18883                        .into_iter()
18884                        .filter_map(|buffer| {
18885                            project_weak
18886                                .update(cx, |project, cx| {
18887                                    project.lsp_store().update(cx, |lsp_store, cx| {
18888                                        lsp_store.pull_diagnostics_for_buffer(buffer, cx)
18889                                    })
18890                                })
18891                                .ok()
18892                        })
18893                        .collect::<FuturesUnordered<_>>()
18894                }) else {
18895                    return;
18896                };
18897
18898                while let Some(pull_task) = pull_diagnostics_tasks.next().await {
18899                    if let Err(e) = pull_task {
18900                        log::error!("Failed to update project diagnostics: {e:#}");
18901                    }
18902                }
18903            })
18904        };
18905
18906        self.pull_diagnostics_task = make_spawn(edited_buffers, debounce);
18907        self.pull_diagnostics_background_task = make_spawn(related_open_buffers, debounce * 2);
18908
18909        Some(())
18910    }
18911
18912    pub fn set_selections_from_remote(
18913        &mut self,
18914        selections: Vec<Selection<Anchor>>,
18915        pending_selection: Option<Selection<Anchor>>,
18916        window: &mut Window,
18917        cx: &mut Context<Self>,
18918    ) {
18919        let old_cursor_position = self.selections.newest_anchor().head();
18920        self.selections
18921            .change_with(&self.display_snapshot(cx), |s| {
18922                s.select_anchors(selections);
18923                if let Some(pending_selection) = pending_selection {
18924                    s.set_pending(pending_selection, SelectMode::Character);
18925                } else {
18926                    s.clear_pending();
18927                }
18928            });
18929        self.selections_did_change(
18930            false,
18931            &old_cursor_position,
18932            SelectionEffects::default(),
18933            window,
18934            cx,
18935        );
18936    }
18937
18938    pub fn transact(
18939        &mut self,
18940        window: &mut Window,
18941        cx: &mut Context<Self>,
18942        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
18943    ) -> Option<TransactionId> {
18944        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18945            this.start_transaction_at(Instant::now(), window, cx);
18946            update(this, window, cx);
18947            this.end_transaction_at(Instant::now(), cx)
18948        })
18949    }
18950
18951    pub fn start_transaction_at(
18952        &mut self,
18953        now: Instant,
18954        window: &mut Window,
18955        cx: &mut Context<Self>,
18956    ) -> Option<TransactionId> {
18957        self.end_selection(window, cx);
18958        if let Some(tx_id) = self
18959            .buffer
18960            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
18961        {
18962            self.selection_history
18963                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
18964            cx.emit(EditorEvent::TransactionBegun {
18965                transaction_id: tx_id,
18966            });
18967            Some(tx_id)
18968        } else {
18969            None
18970        }
18971    }
18972
18973    pub fn end_transaction_at(
18974        &mut self,
18975        now: Instant,
18976        cx: &mut Context<Self>,
18977    ) -> Option<TransactionId> {
18978        if let Some(transaction_id) = self
18979            .buffer
18980            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
18981        {
18982            if let Some((_, end_selections)) =
18983                self.selection_history.transaction_mut(transaction_id)
18984            {
18985                *end_selections = Some(self.selections.disjoint_anchors_arc());
18986            } else {
18987                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
18988            }
18989
18990            cx.emit(EditorEvent::Edited { transaction_id });
18991            Some(transaction_id)
18992        } else {
18993            None
18994        }
18995    }
18996
18997    pub fn modify_transaction_selection_history(
18998        &mut self,
18999        transaction_id: TransactionId,
19000        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
19001    ) -> bool {
19002        self.selection_history
19003            .transaction_mut(transaction_id)
19004            .map(modify)
19005            .is_some()
19006    }
19007
19008    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
19009        if self.selection_mark_mode {
19010            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
19011                s.move_with(|_, sel| {
19012                    sel.collapse_to(sel.head(), SelectionGoal::None);
19013                });
19014            })
19015        }
19016        self.selection_mark_mode = true;
19017        cx.notify();
19018    }
19019
19020    pub fn swap_selection_ends(
19021        &mut self,
19022        _: &actions::SwapSelectionEnds,
19023        window: &mut Window,
19024        cx: &mut Context<Self>,
19025    ) {
19026        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
19027            s.move_with(|_, sel| {
19028                if sel.start != sel.end {
19029                    sel.reversed = !sel.reversed
19030                }
19031            });
19032        });
19033        self.request_autoscroll(Autoscroll::newest(), cx);
19034        cx.notify();
19035    }
19036
19037    pub fn toggle_focus(
19038        workspace: &mut Workspace,
19039        _: &actions::ToggleFocus,
19040        window: &mut Window,
19041        cx: &mut Context<Workspace>,
19042    ) {
19043        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
19044            return;
19045        };
19046        workspace.activate_item(&item, true, true, window, cx);
19047    }
19048
19049    pub fn toggle_fold(
19050        &mut self,
19051        _: &actions::ToggleFold,
19052        window: &mut Window,
19053        cx: &mut Context<Self>,
19054    ) {
19055        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19056            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19057            let selection = self.selections.newest::<Point>(&display_map);
19058
19059            let range = if selection.is_empty() {
19060                let point = selection.head().to_display_point(&display_map);
19061                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
19062                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
19063                    .to_point(&display_map);
19064                start..end
19065            } else {
19066                selection.range()
19067            };
19068            if display_map.folds_in_range(range).next().is_some() {
19069                self.unfold_lines(&Default::default(), window, cx)
19070            } else {
19071                self.fold(&Default::default(), window, cx)
19072            }
19073        } else {
19074            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19075            let buffer_ids: HashSet<_> = self
19076                .selections
19077                .disjoint_anchor_ranges()
19078                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19079                .collect();
19080
19081            let should_unfold = buffer_ids
19082                .iter()
19083                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
19084
19085            for buffer_id in buffer_ids {
19086                if should_unfold {
19087                    self.unfold_buffer(buffer_id, cx);
19088                } else {
19089                    self.fold_buffer(buffer_id, cx);
19090                }
19091            }
19092        }
19093    }
19094
19095    pub fn toggle_fold_recursive(
19096        &mut self,
19097        _: &actions::ToggleFoldRecursive,
19098        window: &mut Window,
19099        cx: &mut Context<Self>,
19100    ) {
19101        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
19102
19103        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19104        let range = if selection.is_empty() {
19105            let point = selection.head().to_display_point(&display_map);
19106            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
19107            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
19108                .to_point(&display_map);
19109            start..end
19110        } else {
19111            selection.range()
19112        };
19113        if display_map.folds_in_range(range).next().is_some() {
19114            self.unfold_recursive(&Default::default(), window, cx)
19115        } else {
19116            self.fold_recursive(&Default::default(), window, cx)
19117        }
19118    }
19119
19120    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
19121        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19122            let mut to_fold = Vec::new();
19123            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19124            let selections = self.selections.all_adjusted(&display_map);
19125
19126            for selection in selections {
19127                let range = selection.range().sorted();
19128                let buffer_start_row = range.start.row;
19129
19130                if range.start.row != range.end.row {
19131                    let mut found = false;
19132                    let mut row = range.start.row;
19133                    while row <= range.end.row {
19134                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19135                        {
19136                            found = true;
19137                            row = crease.range().end.row + 1;
19138                            to_fold.push(crease);
19139                        } else {
19140                            row += 1
19141                        }
19142                    }
19143                    if found {
19144                        continue;
19145                    }
19146                }
19147
19148                for row in (0..=range.start.row).rev() {
19149                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19150                        && crease.range().end.row >= buffer_start_row
19151                    {
19152                        to_fold.push(crease);
19153                        if row <= range.start.row {
19154                            break;
19155                        }
19156                    }
19157                }
19158            }
19159
19160            self.fold_creases(to_fold, true, window, cx);
19161        } else {
19162            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19163            let buffer_ids = self
19164                .selections
19165                .disjoint_anchor_ranges()
19166                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19167                .collect::<HashSet<_>>();
19168            for buffer_id in buffer_ids {
19169                self.fold_buffer(buffer_id, cx);
19170            }
19171        }
19172    }
19173
19174    pub fn toggle_fold_all(
19175        &mut self,
19176        _: &actions::ToggleFoldAll,
19177        window: &mut Window,
19178        cx: &mut Context<Self>,
19179    ) {
19180        if self.buffer.read(cx).is_singleton() {
19181            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19182            let has_folds = display_map
19183                .folds_in_range(MultiBufferOffset(0)..display_map.buffer_snapshot().len())
19184                .next()
19185                .is_some();
19186
19187            if has_folds {
19188                self.unfold_all(&actions::UnfoldAll, window, cx);
19189            } else {
19190                self.fold_all(&actions::FoldAll, window, cx);
19191            }
19192        } else {
19193            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
19194            let should_unfold = buffer_ids
19195                .iter()
19196                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
19197
19198            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
19199                editor
19200                    .update_in(cx, |editor, _, cx| {
19201                        for buffer_id in buffer_ids {
19202                            if should_unfold {
19203                                editor.unfold_buffer(buffer_id, cx);
19204                            } else {
19205                                editor.fold_buffer(buffer_id, cx);
19206                            }
19207                        }
19208                    })
19209                    .ok();
19210            });
19211        }
19212    }
19213
19214    fn fold_at_level(
19215        &mut self,
19216        fold_at: &FoldAtLevel,
19217        window: &mut Window,
19218        cx: &mut Context<Self>,
19219    ) {
19220        if !self.buffer.read(cx).is_singleton() {
19221            return;
19222        }
19223
19224        let fold_at_level = fold_at.0;
19225        let snapshot = self.buffer.read(cx).snapshot(cx);
19226        let mut to_fold = Vec::new();
19227        let mut stack = vec![(0, snapshot.max_row().0, 1)];
19228
19229        let row_ranges_to_keep: Vec<Range<u32>> = self
19230            .selections
19231            .all::<Point>(&self.display_snapshot(cx))
19232            .into_iter()
19233            .map(|sel| sel.start.row..sel.end.row)
19234            .collect();
19235
19236        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
19237            while start_row < end_row {
19238                match self
19239                    .snapshot(window, cx)
19240                    .crease_for_buffer_row(MultiBufferRow(start_row))
19241                {
19242                    Some(crease) => {
19243                        let nested_start_row = crease.range().start.row + 1;
19244                        let nested_end_row = crease.range().end.row;
19245
19246                        if current_level < fold_at_level {
19247                            stack.push((nested_start_row, nested_end_row, current_level + 1));
19248                        } else if current_level == fold_at_level {
19249                            // Fold iff there is no selection completely contained within the fold region
19250                            if !row_ranges_to_keep.iter().any(|selection| {
19251                                selection.end >= nested_start_row
19252                                    && selection.start <= nested_end_row
19253                            }) {
19254                                to_fold.push(crease);
19255                            }
19256                        }
19257
19258                        start_row = nested_end_row + 1;
19259                    }
19260                    None => start_row += 1,
19261                }
19262            }
19263        }
19264
19265        self.fold_creases(to_fold, true, window, cx);
19266    }
19267
19268    pub fn fold_at_level_1(
19269        &mut self,
19270        _: &actions::FoldAtLevel1,
19271        window: &mut Window,
19272        cx: &mut Context<Self>,
19273    ) {
19274        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
19275    }
19276
19277    pub fn fold_at_level_2(
19278        &mut self,
19279        _: &actions::FoldAtLevel2,
19280        window: &mut Window,
19281        cx: &mut Context<Self>,
19282    ) {
19283        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
19284    }
19285
19286    pub fn fold_at_level_3(
19287        &mut self,
19288        _: &actions::FoldAtLevel3,
19289        window: &mut Window,
19290        cx: &mut Context<Self>,
19291    ) {
19292        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
19293    }
19294
19295    pub fn fold_at_level_4(
19296        &mut self,
19297        _: &actions::FoldAtLevel4,
19298        window: &mut Window,
19299        cx: &mut Context<Self>,
19300    ) {
19301        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
19302    }
19303
19304    pub fn fold_at_level_5(
19305        &mut self,
19306        _: &actions::FoldAtLevel5,
19307        window: &mut Window,
19308        cx: &mut Context<Self>,
19309    ) {
19310        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
19311    }
19312
19313    pub fn fold_at_level_6(
19314        &mut self,
19315        _: &actions::FoldAtLevel6,
19316        window: &mut Window,
19317        cx: &mut Context<Self>,
19318    ) {
19319        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
19320    }
19321
19322    pub fn fold_at_level_7(
19323        &mut self,
19324        _: &actions::FoldAtLevel7,
19325        window: &mut Window,
19326        cx: &mut Context<Self>,
19327    ) {
19328        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
19329    }
19330
19331    pub fn fold_at_level_8(
19332        &mut self,
19333        _: &actions::FoldAtLevel8,
19334        window: &mut Window,
19335        cx: &mut Context<Self>,
19336    ) {
19337        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
19338    }
19339
19340    pub fn fold_at_level_9(
19341        &mut self,
19342        _: &actions::FoldAtLevel9,
19343        window: &mut Window,
19344        cx: &mut Context<Self>,
19345    ) {
19346        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
19347    }
19348
19349    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
19350        if self.buffer.read(cx).is_singleton() {
19351            let mut fold_ranges = Vec::new();
19352            let snapshot = self.buffer.read(cx).snapshot(cx);
19353
19354            for row in 0..snapshot.max_row().0 {
19355                if let Some(foldable_range) = self
19356                    .snapshot(window, cx)
19357                    .crease_for_buffer_row(MultiBufferRow(row))
19358                {
19359                    fold_ranges.push(foldable_range);
19360                }
19361            }
19362
19363            self.fold_creases(fold_ranges, true, window, cx);
19364        } else {
19365            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
19366                editor
19367                    .update_in(cx, |editor, _, cx| {
19368                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19369                            editor.fold_buffer(buffer_id, cx);
19370                        }
19371                    })
19372                    .ok();
19373            });
19374        }
19375    }
19376
19377    pub fn fold_function_bodies(
19378        &mut self,
19379        _: &actions::FoldFunctionBodies,
19380        window: &mut Window,
19381        cx: &mut Context<Self>,
19382    ) {
19383        let snapshot = self.buffer.read(cx).snapshot(cx);
19384
19385        let ranges = snapshot
19386            .text_object_ranges(
19387                MultiBufferOffset(0)..snapshot.len(),
19388                TreeSitterOptions::default(),
19389            )
19390            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
19391            .collect::<Vec<_>>();
19392
19393        let creases = ranges
19394            .into_iter()
19395            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
19396            .collect();
19397
19398        self.fold_creases(creases, true, window, cx);
19399    }
19400
19401    pub fn fold_recursive(
19402        &mut self,
19403        _: &actions::FoldRecursive,
19404        window: &mut Window,
19405        cx: &mut Context<Self>,
19406    ) {
19407        let mut to_fold = Vec::new();
19408        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19409        let selections = self.selections.all_adjusted(&display_map);
19410
19411        for selection in selections {
19412            let range = selection.range().sorted();
19413            let buffer_start_row = range.start.row;
19414
19415            if range.start.row != range.end.row {
19416                let mut found = false;
19417                for row in range.start.row..=range.end.row {
19418                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19419                        found = true;
19420                        to_fold.push(crease);
19421                    }
19422                }
19423                if found {
19424                    continue;
19425                }
19426            }
19427
19428            for row in (0..=range.start.row).rev() {
19429                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19430                    if crease.range().end.row >= buffer_start_row {
19431                        to_fold.push(crease);
19432                    } else {
19433                        break;
19434                    }
19435                }
19436            }
19437        }
19438
19439        self.fold_creases(to_fold, true, window, cx);
19440    }
19441
19442    pub fn fold_at(
19443        &mut self,
19444        buffer_row: MultiBufferRow,
19445        window: &mut Window,
19446        cx: &mut Context<Self>,
19447    ) {
19448        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19449
19450        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
19451            let autoscroll = self
19452                .selections
19453                .all::<Point>(&display_map)
19454                .iter()
19455                .any(|selection| crease.range().overlaps(&selection.range()));
19456
19457            self.fold_creases(vec![crease], autoscroll, window, cx);
19458        }
19459    }
19460
19461    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
19462        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19463            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19464            let buffer = display_map.buffer_snapshot();
19465            let selections = self.selections.all::<Point>(&display_map);
19466            let ranges = selections
19467                .iter()
19468                .map(|s| {
19469                    let range = s.display_range(&display_map).sorted();
19470                    let mut start = range.start.to_point(&display_map);
19471                    let mut end = range.end.to_point(&display_map);
19472                    start.column = 0;
19473                    end.column = buffer.line_len(MultiBufferRow(end.row));
19474                    start..end
19475                })
19476                .collect::<Vec<_>>();
19477
19478            self.unfold_ranges(&ranges, true, true, cx);
19479        } else {
19480            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19481            let buffer_ids = self
19482                .selections
19483                .disjoint_anchor_ranges()
19484                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19485                .collect::<HashSet<_>>();
19486            for buffer_id in buffer_ids {
19487                self.unfold_buffer(buffer_id, cx);
19488            }
19489        }
19490    }
19491
19492    pub fn unfold_recursive(
19493        &mut self,
19494        _: &UnfoldRecursive,
19495        _window: &mut Window,
19496        cx: &mut Context<Self>,
19497    ) {
19498        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19499        let selections = self.selections.all::<Point>(&display_map);
19500        let ranges = selections
19501            .iter()
19502            .map(|s| {
19503                let mut range = s.display_range(&display_map).sorted();
19504                *range.start.column_mut() = 0;
19505                *range.end.column_mut() = display_map.line_len(range.end.row());
19506                let start = range.start.to_point(&display_map);
19507                let end = range.end.to_point(&display_map);
19508                start..end
19509            })
19510            .collect::<Vec<_>>();
19511
19512        self.unfold_ranges(&ranges, true, true, cx);
19513    }
19514
19515    pub fn unfold_at(
19516        &mut self,
19517        buffer_row: MultiBufferRow,
19518        _window: &mut Window,
19519        cx: &mut Context<Self>,
19520    ) {
19521        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19522
19523        let intersection_range = Point::new(buffer_row.0, 0)
19524            ..Point::new(
19525                buffer_row.0,
19526                display_map.buffer_snapshot().line_len(buffer_row),
19527            );
19528
19529        let autoscroll = self
19530            .selections
19531            .all::<Point>(&display_map)
19532            .iter()
19533            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
19534
19535        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
19536    }
19537
19538    pub fn unfold_all(
19539        &mut self,
19540        _: &actions::UnfoldAll,
19541        _window: &mut Window,
19542        cx: &mut Context<Self>,
19543    ) {
19544        if self.buffer.read(cx).is_singleton() {
19545            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19546            self.unfold_ranges(
19547                &[MultiBufferOffset(0)..display_map.buffer_snapshot().len()],
19548                true,
19549                true,
19550                cx,
19551            );
19552        } else {
19553            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
19554                editor
19555                    .update(cx, |editor, cx| {
19556                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19557                            editor.unfold_buffer(buffer_id, cx);
19558                        }
19559                    })
19560                    .ok();
19561            });
19562        }
19563    }
19564
19565    pub fn fold_selected_ranges(
19566        &mut self,
19567        _: &FoldSelectedRanges,
19568        window: &mut Window,
19569        cx: &mut Context<Self>,
19570    ) {
19571        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19572        let selections = self.selections.all_adjusted(&display_map);
19573        let ranges = selections
19574            .into_iter()
19575            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
19576            .collect::<Vec<_>>();
19577        self.fold_creases(ranges, true, window, cx);
19578    }
19579
19580    pub fn fold_ranges<T: ToOffset + Clone>(
19581        &mut self,
19582        ranges: Vec<Range<T>>,
19583        auto_scroll: bool,
19584        window: &mut Window,
19585        cx: &mut Context<Self>,
19586    ) {
19587        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19588        let ranges = ranges
19589            .into_iter()
19590            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
19591            .collect::<Vec<_>>();
19592        self.fold_creases(ranges, auto_scroll, window, cx);
19593    }
19594
19595    pub fn fold_creases<T: ToOffset + Clone>(
19596        &mut self,
19597        creases: Vec<Crease<T>>,
19598        auto_scroll: bool,
19599        _window: &mut Window,
19600        cx: &mut Context<Self>,
19601    ) {
19602        if creases.is_empty() {
19603            return;
19604        }
19605
19606        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
19607
19608        if auto_scroll {
19609            self.request_autoscroll(Autoscroll::fit(), cx);
19610        }
19611
19612        cx.notify();
19613
19614        self.scrollbar_marker_state.dirty = true;
19615        self.folds_did_change(cx);
19616    }
19617
19618    /// Removes any folds whose ranges intersect any of the given ranges.
19619    pub fn unfold_ranges<T: ToOffset + Clone>(
19620        &mut self,
19621        ranges: &[Range<T>],
19622        inclusive: bool,
19623        auto_scroll: bool,
19624        cx: &mut Context<Self>,
19625    ) {
19626        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19627            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
19628        });
19629        self.folds_did_change(cx);
19630    }
19631
19632    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19633        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
19634            return;
19635        }
19636
19637        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19638        self.display_map.update(cx, |display_map, cx| {
19639            display_map.fold_buffers([buffer_id], cx)
19640        });
19641
19642        let snapshot = self.display_snapshot(cx);
19643        self.selections.change_with(&snapshot, |selections| {
19644            selections.remove_selections_from_buffer(buffer_id);
19645        });
19646
19647        cx.emit(EditorEvent::BufferFoldToggled {
19648            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
19649            folded: true,
19650        });
19651        cx.notify();
19652    }
19653
19654    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19655        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
19656            return;
19657        }
19658        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19659        self.display_map.update(cx, |display_map, cx| {
19660            display_map.unfold_buffers([buffer_id], cx);
19661        });
19662        cx.emit(EditorEvent::BufferFoldToggled {
19663            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
19664            folded: false,
19665        });
19666        cx.notify();
19667    }
19668
19669    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
19670        self.display_map.read(cx).is_buffer_folded(buffer)
19671    }
19672
19673    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
19674        self.display_map.read(cx).folded_buffers()
19675    }
19676
19677    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19678        self.display_map.update(cx, |display_map, cx| {
19679            display_map.disable_header_for_buffer(buffer_id, cx);
19680        });
19681        cx.notify();
19682    }
19683
19684    /// Removes any folds with the given ranges.
19685    pub fn remove_folds_with_type<T: ToOffset + Clone>(
19686        &mut self,
19687        ranges: &[Range<T>],
19688        type_id: TypeId,
19689        auto_scroll: bool,
19690        cx: &mut Context<Self>,
19691    ) {
19692        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19693            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
19694        });
19695        self.folds_did_change(cx);
19696    }
19697
19698    fn remove_folds_with<T: ToOffset + Clone>(
19699        &mut self,
19700        ranges: &[Range<T>],
19701        auto_scroll: bool,
19702        cx: &mut Context<Self>,
19703        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
19704    ) {
19705        if ranges.is_empty() {
19706            return;
19707        }
19708
19709        let mut buffers_affected = HashSet::default();
19710        let multi_buffer = self.buffer().read(cx);
19711        for range in ranges {
19712            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
19713                buffers_affected.insert(buffer.read(cx).remote_id());
19714            };
19715        }
19716
19717        self.display_map.update(cx, update);
19718
19719        if auto_scroll {
19720            self.request_autoscroll(Autoscroll::fit(), cx);
19721        }
19722
19723        cx.notify();
19724        self.scrollbar_marker_state.dirty = true;
19725        self.active_indent_guides_state.dirty = true;
19726    }
19727
19728    pub fn update_renderer_widths(
19729        &mut self,
19730        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
19731        cx: &mut Context<Self>,
19732    ) -> bool {
19733        self.display_map
19734            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
19735    }
19736
19737    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
19738        self.display_map.read(cx).fold_placeholder.clone()
19739    }
19740
19741    pub fn set_use_base_text_line_numbers(&mut self, show: bool, _cx: &mut Context<Self>) {
19742        self.use_base_text_line_numbers = show;
19743    }
19744
19745    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
19746        self.buffer.update(cx, |buffer, cx| {
19747            buffer.set_all_diff_hunks_expanded(cx);
19748        });
19749    }
19750
19751    pub fn expand_all_diff_hunks(
19752        &mut self,
19753        _: &ExpandAllDiffHunks,
19754        _window: &mut Window,
19755        cx: &mut Context<Self>,
19756    ) {
19757        self.buffer.update(cx, |buffer, cx| {
19758            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19759        });
19760    }
19761
19762    pub fn collapse_all_diff_hunks(
19763        &mut self,
19764        _: &CollapseAllDiffHunks,
19765        _window: &mut Window,
19766        cx: &mut Context<Self>,
19767    ) {
19768        self.buffer.update(cx, |buffer, cx| {
19769            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19770        });
19771    }
19772
19773    pub fn toggle_selected_diff_hunks(
19774        &mut self,
19775        _: &ToggleSelectedDiffHunks,
19776        _window: &mut Window,
19777        cx: &mut Context<Self>,
19778    ) {
19779        let ranges: Vec<_> = self
19780            .selections
19781            .disjoint_anchors()
19782            .iter()
19783            .map(|s| s.range())
19784            .collect();
19785        self.toggle_diff_hunks_in_ranges(ranges, cx);
19786    }
19787
19788    pub fn diff_hunks_in_ranges<'a>(
19789        &'a self,
19790        ranges: &'a [Range<Anchor>],
19791        buffer: &'a MultiBufferSnapshot,
19792    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
19793        ranges.iter().flat_map(move |range| {
19794            let end_excerpt_id = range.end.excerpt_id;
19795            let range = range.to_point(buffer);
19796            let mut peek_end = range.end;
19797            if range.end.row < buffer.max_row().0 {
19798                peek_end = Point::new(range.end.row + 1, 0);
19799            }
19800            buffer
19801                .diff_hunks_in_range(range.start..peek_end)
19802                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
19803        })
19804    }
19805
19806    pub fn has_stageable_diff_hunks_in_ranges(
19807        &self,
19808        ranges: &[Range<Anchor>],
19809        snapshot: &MultiBufferSnapshot,
19810    ) -> bool {
19811        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
19812        hunks.any(|hunk| hunk.status().has_secondary_hunk())
19813    }
19814
19815    pub fn toggle_staged_selected_diff_hunks(
19816        &mut self,
19817        _: &::git::ToggleStaged,
19818        _: &mut Window,
19819        cx: &mut Context<Self>,
19820    ) {
19821        let snapshot = self.buffer.read(cx).snapshot(cx);
19822        let ranges: Vec<_> = self
19823            .selections
19824            .disjoint_anchors()
19825            .iter()
19826            .map(|s| s.range())
19827            .collect();
19828        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
19829        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19830    }
19831
19832    pub fn set_render_diff_hunk_controls(
19833        &mut self,
19834        render_diff_hunk_controls: RenderDiffHunkControlsFn,
19835        cx: &mut Context<Self>,
19836    ) {
19837        self.render_diff_hunk_controls = render_diff_hunk_controls;
19838        cx.notify();
19839    }
19840
19841    pub fn stage_and_next(
19842        &mut self,
19843        _: &::git::StageAndNext,
19844        window: &mut Window,
19845        cx: &mut Context<Self>,
19846    ) {
19847        self.do_stage_or_unstage_and_next(true, window, cx);
19848    }
19849
19850    pub fn unstage_and_next(
19851        &mut self,
19852        _: &::git::UnstageAndNext,
19853        window: &mut Window,
19854        cx: &mut Context<Self>,
19855    ) {
19856        self.do_stage_or_unstage_and_next(false, window, cx);
19857    }
19858
19859    pub fn stage_or_unstage_diff_hunks(
19860        &mut self,
19861        stage: bool,
19862        ranges: Vec<Range<Anchor>>,
19863        cx: &mut Context<Self>,
19864    ) {
19865        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
19866        cx.spawn(async move |this, cx| {
19867            task.await?;
19868            this.update(cx, |this, cx| {
19869                let snapshot = this.buffer.read(cx).snapshot(cx);
19870                let chunk_by = this
19871                    .diff_hunks_in_ranges(&ranges, &snapshot)
19872                    .chunk_by(|hunk| hunk.buffer_id);
19873                for (buffer_id, hunks) in &chunk_by {
19874                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
19875                }
19876            })
19877        })
19878        .detach_and_log_err(cx);
19879    }
19880
19881    fn save_buffers_for_ranges_if_needed(
19882        &mut self,
19883        ranges: &[Range<Anchor>],
19884        cx: &mut Context<Editor>,
19885    ) -> Task<Result<()>> {
19886        let multibuffer = self.buffer.read(cx);
19887        let snapshot = multibuffer.read(cx);
19888        let buffer_ids: HashSet<_> = ranges
19889            .iter()
19890            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
19891            .collect();
19892        drop(snapshot);
19893
19894        let mut buffers = HashSet::default();
19895        for buffer_id in buffer_ids {
19896            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
19897                let buffer = buffer_entity.read(cx);
19898                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
19899                {
19900                    buffers.insert(buffer_entity);
19901                }
19902            }
19903        }
19904
19905        if let Some(project) = &self.project {
19906            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
19907        } else {
19908            Task::ready(Ok(()))
19909        }
19910    }
19911
19912    fn do_stage_or_unstage_and_next(
19913        &mut self,
19914        stage: bool,
19915        window: &mut Window,
19916        cx: &mut Context<Self>,
19917    ) {
19918        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
19919
19920        if ranges.iter().any(|range| range.start != range.end) {
19921            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19922            return;
19923        }
19924
19925        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19926        let snapshot = self.snapshot(window, cx);
19927        let position = self
19928            .selections
19929            .newest::<Point>(&snapshot.display_snapshot)
19930            .head();
19931        let mut row = snapshot
19932            .buffer_snapshot()
19933            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
19934            .find(|hunk| hunk.row_range.start.0 > position.row)
19935            .map(|hunk| hunk.row_range.start);
19936
19937        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
19938        // Outside of the project diff editor, wrap around to the beginning.
19939        if !all_diff_hunks_expanded {
19940            row = row.or_else(|| {
19941                snapshot
19942                    .buffer_snapshot()
19943                    .diff_hunks_in_range(Point::zero()..position)
19944                    .find(|hunk| hunk.row_range.end.0 < position.row)
19945                    .map(|hunk| hunk.row_range.start)
19946            });
19947        }
19948
19949        if let Some(row) = row {
19950            let destination = Point::new(row.0, 0);
19951            let autoscroll = Autoscroll::center();
19952
19953            self.unfold_ranges(&[destination..destination], false, false, cx);
19954            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
19955                s.select_ranges([destination..destination]);
19956            });
19957        }
19958    }
19959
19960    fn do_stage_or_unstage(
19961        &self,
19962        stage: bool,
19963        buffer_id: BufferId,
19964        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
19965        cx: &mut App,
19966    ) -> Option<()> {
19967        let project = self.project()?;
19968        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
19969        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
19970        let buffer_snapshot = buffer.read(cx).snapshot();
19971        let file_exists = buffer_snapshot
19972            .file()
19973            .is_some_and(|file| file.disk_state().exists());
19974        diff.update(cx, |diff, cx| {
19975            diff.stage_or_unstage_hunks(
19976                stage,
19977                &hunks
19978                    .map(|hunk| buffer_diff::DiffHunk {
19979                        buffer_range: hunk.buffer_range,
19980                        // We don't need to pass in word diffs here because they're only used for rendering and
19981                        // this function changes internal state
19982                        base_word_diffs: Vec::default(),
19983                        buffer_word_diffs: Vec::default(),
19984                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
19985                            ..hunk.diff_base_byte_range.end.0,
19986                        secondary_status: hunk.secondary_status,
19987                        range: Point::zero()..Point::zero(), // unused
19988                    })
19989                    .collect::<Vec<_>>(),
19990                &buffer_snapshot,
19991                file_exists,
19992                cx,
19993            )
19994        });
19995        None
19996    }
19997
19998    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
19999        let ranges: Vec<_> = self
20000            .selections
20001            .disjoint_anchors()
20002            .iter()
20003            .map(|s| s.range())
20004            .collect();
20005        self.buffer
20006            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
20007    }
20008
20009    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
20010        self.buffer.update(cx, |buffer, cx| {
20011            let ranges = vec![Anchor::min()..Anchor::max()];
20012            if !buffer.all_diff_hunks_expanded()
20013                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
20014            {
20015                buffer.collapse_diff_hunks(ranges, cx);
20016                true
20017            } else {
20018                false
20019            }
20020        })
20021    }
20022
20023    fn has_any_expanded_diff_hunks(&self, cx: &App) -> bool {
20024        if self.buffer.read(cx).all_diff_hunks_expanded() {
20025            return true;
20026        }
20027        let ranges = vec![Anchor::min()..Anchor::max()];
20028        self.buffer
20029            .read(cx)
20030            .has_expanded_diff_hunks_in_ranges(&ranges, cx)
20031    }
20032
20033    fn toggle_diff_hunks_in_ranges(
20034        &mut self,
20035        ranges: Vec<Range<Anchor>>,
20036        cx: &mut Context<Editor>,
20037    ) {
20038        self.buffer.update(cx, |buffer, cx| {
20039            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
20040            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
20041        })
20042    }
20043
20044    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
20045        self.buffer.update(cx, |buffer, cx| {
20046            let snapshot = buffer.snapshot(cx);
20047            let excerpt_id = range.end.excerpt_id;
20048            let point_range = range.to_point(&snapshot);
20049            let expand = !buffer.single_hunk_is_expanded(range, cx);
20050            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
20051        })
20052    }
20053
20054    pub(crate) fn apply_all_diff_hunks(
20055        &mut self,
20056        _: &ApplyAllDiffHunks,
20057        window: &mut Window,
20058        cx: &mut Context<Self>,
20059    ) {
20060        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20061
20062        let buffers = self.buffer.read(cx).all_buffers();
20063        for branch_buffer in buffers {
20064            branch_buffer.update(cx, |branch_buffer, cx| {
20065                branch_buffer.merge_into_base(Vec::new(), cx);
20066            });
20067        }
20068
20069        if let Some(project) = self.project.clone() {
20070            self.save(
20071                SaveOptions {
20072                    format: true,
20073                    autosave: false,
20074                },
20075                project,
20076                window,
20077                cx,
20078            )
20079            .detach_and_log_err(cx);
20080        }
20081    }
20082
20083    pub(crate) fn apply_selected_diff_hunks(
20084        &mut self,
20085        _: &ApplyDiffHunk,
20086        window: &mut Window,
20087        cx: &mut Context<Self>,
20088    ) {
20089        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20090        let snapshot = self.snapshot(window, cx);
20091        let hunks = snapshot.hunks_for_ranges(
20092            self.selections
20093                .all(&snapshot.display_snapshot)
20094                .into_iter()
20095                .map(|selection| selection.range()),
20096        );
20097        let mut ranges_by_buffer = HashMap::default();
20098        self.transact(window, cx, |editor, _window, cx| {
20099            for hunk in hunks {
20100                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
20101                    ranges_by_buffer
20102                        .entry(buffer.clone())
20103                        .or_insert_with(Vec::new)
20104                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
20105                }
20106            }
20107
20108            for (buffer, ranges) in ranges_by_buffer {
20109                buffer.update(cx, |buffer, cx| {
20110                    buffer.merge_into_base(ranges, cx);
20111                });
20112            }
20113        });
20114
20115        if let Some(project) = self.project.clone() {
20116            self.save(
20117                SaveOptions {
20118                    format: true,
20119                    autosave: false,
20120                },
20121                project,
20122                window,
20123                cx,
20124            )
20125            .detach_and_log_err(cx);
20126        }
20127    }
20128
20129    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
20130        if hovered != self.gutter_hovered {
20131            self.gutter_hovered = hovered;
20132            cx.notify();
20133        }
20134    }
20135
20136    pub fn insert_blocks(
20137        &mut self,
20138        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
20139        autoscroll: Option<Autoscroll>,
20140        cx: &mut Context<Self>,
20141    ) -> Vec<CustomBlockId> {
20142        let blocks = self
20143            .display_map
20144            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
20145        if let Some(autoscroll) = autoscroll {
20146            self.request_autoscroll(autoscroll, cx);
20147        }
20148        cx.notify();
20149        blocks
20150    }
20151
20152    pub fn resize_blocks(
20153        &mut self,
20154        heights: HashMap<CustomBlockId, u32>,
20155        autoscroll: Option<Autoscroll>,
20156        cx: &mut Context<Self>,
20157    ) {
20158        self.display_map
20159            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
20160        if let Some(autoscroll) = autoscroll {
20161            self.request_autoscroll(autoscroll, cx);
20162        }
20163        cx.notify();
20164    }
20165
20166    pub fn replace_blocks(
20167        &mut self,
20168        renderers: HashMap<CustomBlockId, RenderBlock>,
20169        autoscroll: Option<Autoscroll>,
20170        cx: &mut Context<Self>,
20171    ) {
20172        self.display_map
20173            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
20174        if let Some(autoscroll) = autoscroll {
20175            self.request_autoscroll(autoscroll, cx);
20176        }
20177        cx.notify();
20178    }
20179
20180    pub fn remove_blocks(
20181        &mut self,
20182        block_ids: HashSet<CustomBlockId>,
20183        autoscroll: Option<Autoscroll>,
20184        cx: &mut Context<Self>,
20185    ) {
20186        self.display_map.update(cx, |display_map, cx| {
20187            display_map.remove_blocks(block_ids, cx)
20188        });
20189        if let Some(autoscroll) = autoscroll {
20190            self.request_autoscroll(autoscroll, cx);
20191        }
20192        cx.notify();
20193    }
20194
20195    pub fn row_for_block(
20196        &self,
20197        block_id: CustomBlockId,
20198        cx: &mut Context<Self>,
20199    ) -> Option<DisplayRow> {
20200        self.display_map
20201            .update(cx, |map, cx| map.row_for_block(block_id, cx))
20202    }
20203
20204    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
20205        self.focused_block = Some(focused_block);
20206    }
20207
20208    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
20209        self.focused_block.take()
20210    }
20211
20212    pub fn insert_creases(
20213        &mut self,
20214        creases: impl IntoIterator<Item = Crease<Anchor>>,
20215        cx: &mut Context<Self>,
20216    ) -> Vec<CreaseId> {
20217        self.display_map
20218            .update(cx, |map, cx| map.insert_creases(creases, cx))
20219    }
20220
20221    pub fn remove_creases(
20222        &mut self,
20223        ids: impl IntoIterator<Item = CreaseId>,
20224        cx: &mut Context<Self>,
20225    ) -> Vec<(CreaseId, Range<Anchor>)> {
20226        self.display_map
20227            .update(cx, |map, cx| map.remove_creases(ids, cx))
20228    }
20229
20230    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
20231        self.display_map
20232            .update(cx, |map, cx| map.snapshot(cx))
20233            .longest_row()
20234    }
20235
20236    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
20237        self.display_map
20238            .update(cx, |map, cx| map.snapshot(cx))
20239            .max_point()
20240    }
20241
20242    pub fn text(&self, cx: &App) -> String {
20243        self.buffer.read(cx).read(cx).text()
20244    }
20245
20246    pub fn is_empty(&self, cx: &App) -> bool {
20247        self.buffer.read(cx).read(cx).is_empty()
20248    }
20249
20250    pub fn text_option(&self, cx: &App) -> Option<String> {
20251        let text = self.text(cx);
20252        let text = text.trim();
20253
20254        if text.is_empty() {
20255            return None;
20256        }
20257
20258        Some(text.to_string())
20259    }
20260
20261    pub fn set_text(
20262        &mut self,
20263        text: impl Into<Arc<str>>,
20264        window: &mut Window,
20265        cx: &mut Context<Self>,
20266    ) {
20267        self.transact(window, cx, |this, _, cx| {
20268            this.buffer
20269                .read(cx)
20270                .as_singleton()
20271                .expect("you can only call set_text on editors for singleton buffers")
20272                .update(cx, |buffer, cx| buffer.set_text(text, cx));
20273        });
20274    }
20275
20276    pub fn display_text(&self, cx: &mut App) -> String {
20277        self.display_map
20278            .update(cx, |map, cx| map.snapshot(cx))
20279            .text()
20280    }
20281
20282    fn create_minimap(
20283        &self,
20284        minimap_settings: MinimapSettings,
20285        window: &mut Window,
20286        cx: &mut Context<Self>,
20287    ) -> Option<Entity<Self>> {
20288        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
20289            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
20290    }
20291
20292    fn initialize_new_minimap(
20293        &self,
20294        minimap_settings: MinimapSettings,
20295        window: &mut Window,
20296        cx: &mut Context<Self>,
20297    ) -> Entity<Self> {
20298        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
20299
20300        let mut minimap = Editor::new_internal(
20301            EditorMode::Minimap {
20302                parent: cx.weak_entity(),
20303            },
20304            self.buffer.clone(),
20305            None,
20306            Some(self.display_map.clone()),
20307            window,
20308            cx,
20309        );
20310        minimap.scroll_manager.clone_state(&self.scroll_manager);
20311        minimap.set_text_style_refinement(TextStyleRefinement {
20312            font_size: Some(MINIMAP_FONT_SIZE),
20313            font_weight: Some(MINIMAP_FONT_WEIGHT),
20314            ..Default::default()
20315        });
20316        minimap.update_minimap_configuration(minimap_settings, cx);
20317        cx.new(|_| minimap)
20318    }
20319
20320    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
20321        let current_line_highlight = minimap_settings
20322            .current_line_highlight
20323            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
20324        self.set_current_line_highlight(Some(current_line_highlight));
20325    }
20326
20327    pub fn minimap(&self) -> Option<&Entity<Self>> {
20328        self.minimap
20329            .as_ref()
20330            .filter(|_| self.minimap_visibility.visible())
20331    }
20332
20333    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
20334        let mut wrap_guides = smallvec![];
20335
20336        if self.show_wrap_guides == Some(false) {
20337            return wrap_guides;
20338        }
20339
20340        let settings = self.buffer.read(cx).language_settings(cx);
20341        if settings.show_wrap_guides {
20342            match self.soft_wrap_mode(cx) {
20343                SoftWrap::Column(soft_wrap) => {
20344                    wrap_guides.push((soft_wrap as usize, true));
20345                }
20346                SoftWrap::Bounded(soft_wrap) => {
20347                    wrap_guides.push((soft_wrap as usize, true));
20348                }
20349                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
20350            }
20351            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
20352        }
20353
20354        wrap_guides
20355    }
20356
20357    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
20358        let settings = self.buffer.read(cx).language_settings(cx);
20359        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
20360        match mode {
20361            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
20362                SoftWrap::None
20363            }
20364            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
20365            language_settings::SoftWrap::PreferredLineLength => {
20366                SoftWrap::Column(settings.preferred_line_length)
20367            }
20368            language_settings::SoftWrap::Bounded => {
20369                SoftWrap::Bounded(settings.preferred_line_length)
20370            }
20371        }
20372    }
20373
20374    pub fn set_soft_wrap_mode(
20375        &mut self,
20376        mode: language_settings::SoftWrap,
20377
20378        cx: &mut Context<Self>,
20379    ) {
20380        self.soft_wrap_mode_override = Some(mode);
20381        cx.notify();
20382    }
20383
20384    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
20385        self.hard_wrap = hard_wrap;
20386        cx.notify();
20387    }
20388
20389    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
20390        self.text_style_refinement = Some(style);
20391    }
20392
20393    /// called by the Element so we know what style we were most recently rendered with.
20394    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
20395        // We intentionally do not inform the display map about the minimap style
20396        // so that wrapping is not recalculated and stays consistent for the editor
20397        // and its linked minimap.
20398        if !self.mode.is_minimap() {
20399            let font = style.text.font();
20400            let font_size = style.text.font_size.to_pixels(window.rem_size());
20401            let display_map = self
20402                .placeholder_display_map
20403                .as_ref()
20404                .filter(|_| self.is_empty(cx))
20405                .unwrap_or(&self.display_map);
20406
20407            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
20408        }
20409        self.style = Some(style);
20410    }
20411
20412    pub fn style(&mut self, cx: &App) -> &EditorStyle {
20413        if self.style.is_none() {
20414            self.style = Some(self.create_style(cx));
20415        }
20416        self.style.as_ref().unwrap()
20417    }
20418
20419    // Called by the element. This method is not designed to be called outside of the editor
20420    // element's layout code because it does not notify when rewrapping is computed synchronously.
20421    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
20422        if self.is_empty(cx) {
20423            self.placeholder_display_map
20424                .as_ref()
20425                .map_or(false, |display_map| {
20426                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
20427                })
20428        } else {
20429            self.display_map
20430                .update(cx, |map, cx| map.set_wrap_width(width, cx))
20431        }
20432    }
20433
20434    pub fn set_soft_wrap(&mut self) {
20435        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
20436    }
20437
20438    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
20439        if self.soft_wrap_mode_override.is_some() {
20440            self.soft_wrap_mode_override.take();
20441        } else {
20442            let soft_wrap = match self.soft_wrap_mode(cx) {
20443                SoftWrap::GitDiff => return,
20444                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
20445                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
20446                    language_settings::SoftWrap::None
20447                }
20448            };
20449            self.soft_wrap_mode_override = Some(soft_wrap);
20450        }
20451        cx.notify();
20452    }
20453
20454    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
20455        let Some(workspace) = self.workspace() else {
20456            return;
20457        };
20458        let fs = workspace.read(cx).app_state().fs.clone();
20459        let current_show = TabBarSettings::get_global(cx).show;
20460        update_settings_file(fs, cx, move |setting, _| {
20461            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
20462        });
20463    }
20464
20465    pub fn toggle_indent_guides(
20466        &mut self,
20467        _: &ToggleIndentGuides,
20468        _: &mut Window,
20469        cx: &mut Context<Self>,
20470    ) {
20471        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
20472            self.buffer
20473                .read(cx)
20474                .language_settings(cx)
20475                .indent_guides
20476                .enabled
20477        });
20478        self.show_indent_guides = Some(!currently_enabled);
20479        cx.notify();
20480    }
20481
20482    fn should_show_indent_guides(&self) -> Option<bool> {
20483        self.show_indent_guides
20484    }
20485
20486    pub fn disable_indent_guides_for_buffer(
20487        &mut self,
20488        buffer_id: BufferId,
20489        cx: &mut Context<Self>,
20490    ) {
20491        self.buffers_with_disabled_indent_guides.insert(buffer_id);
20492        cx.notify();
20493    }
20494
20495    pub fn has_indent_guides_disabled_for_buffer(&self, buffer_id: BufferId) -> bool {
20496        self.buffers_with_disabled_indent_guides
20497            .contains(&buffer_id)
20498    }
20499
20500    pub fn toggle_line_numbers(
20501        &mut self,
20502        _: &ToggleLineNumbers,
20503        _: &mut Window,
20504        cx: &mut Context<Self>,
20505    ) {
20506        let mut editor_settings = EditorSettings::get_global(cx).clone();
20507        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
20508        EditorSettings::override_global(editor_settings, cx);
20509    }
20510
20511    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
20512        if let Some(show_line_numbers) = self.show_line_numbers {
20513            return show_line_numbers;
20514        }
20515        EditorSettings::get_global(cx).gutter.line_numbers
20516    }
20517
20518    pub fn relative_line_numbers(&self, cx: &mut App) -> RelativeLineNumbers {
20519        match (
20520            self.use_relative_line_numbers,
20521            EditorSettings::get_global(cx).relative_line_numbers,
20522        ) {
20523            (None, setting) => setting,
20524            (Some(false), _) => RelativeLineNumbers::Disabled,
20525            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
20526            (Some(true), _) => RelativeLineNumbers::Enabled,
20527        }
20528    }
20529
20530    pub fn toggle_relative_line_numbers(
20531        &mut self,
20532        _: &ToggleRelativeLineNumbers,
20533        _: &mut Window,
20534        cx: &mut Context<Self>,
20535    ) {
20536        let is_relative = self.relative_line_numbers(cx);
20537        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
20538    }
20539
20540    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
20541        self.use_relative_line_numbers = is_relative;
20542        cx.notify();
20543    }
20544
20545    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
20546        self.show_gutter = show_gutter;
20547        cx.notify();
20548    }
20549
20550    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
20551        self.show_scrollbars = ScrollbarAxes {
20552            horizontal: show,
20553            vertical: show,
20554        };
20555        cx.notify();
20556    }
20557
20558    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20559        self.show_scrollbars.vertical = show;
20560        cx.notify();
20561    }
20562
20563    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20564        self.show_scrollbars.horizontal = show;
20565        cx.notify();
20566    }
20567
20568    pub fn set_minimap_visibility(
20569        &mut self,
20570        minimap_visibility: MinimapVisibility,
20571        window: &mut Window,
20572        cx: &mut Context<Self>,
20573    ) {
20574        if self.minimap_visibility != minimap_visibility {
20575            if minimap_visibility.visible() && self.minimap.is_none() {
20576                let minimap_settings = EditorSettings::get_global(cx).minimap;
20577                self.minimap =
20578                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
20579            }
20580            self.minimap_visibility = minimap_visibility;
20581            cx.notify();
20582        }
20583    }
20584
20585    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20586        self.set_show_scrollbars(false, cx);
20587        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
20588    }
20589
20590    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20591        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
20592    }
20593
20594    /// Normally the text in full mode and auto height editors is padded on the
20595    /// left side by roughly half a character width for improved hit testing.
20596    ///
20597    /// Use this method to disable this for cases where this is not wanted (e.g.
20598    /// if you want to align the editor text with some other text above or below)
20599    /// or if you want to add this padding to single-line editors.
20600    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
20601        self.offset_content = offset_content;
20602        cx.notify();
20603    }
20604
20605    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
20606        self.show_line_numbers = Some(show_line_numbers);
20607        cx.notify();
20608    }
20609
20610    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
20611        self.disable_expand_excerpt_buttons = true;
20612        cx.notify();
20613    }
20614
20615    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
20616        self.show_git_diff_gutter = Some(show_git_diff_gutter);
20617        cx.notify();
20618    }
20619
20620    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
20621        self.show_code_actions = Some(show_code_actions);
20622        cx.notify();
20623    }
20624
20625    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
20626        self.show_runnables = Some(show_runnables);
20627        cx.notify();
20628    }
20629
20630    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
20631        self.show_breakpoints = Some(show_breakpoints);
20632        cx.notify();
20633    }
20634
20635    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
20636        if self.display_map.read(cx).masked != masked {
20637            self.display_map.update(cx, |map, _| map.masked = masked);
20638        }
20639        cx.notify()
20640    }
20641
20642    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
20643        self.show_wrap_guides = Some(show_wrap_guides);
20644        cx.notify();
20645    }
20646
20647    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
20648        self.show_indent_guides = Some(show_indent_guides);
20649        cx.notify();
20650    }
20651
20652    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
20653        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
20654            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
20655                && let Some(dir) = file.abs_path(cx).parent()
20656            {
20657                return Some(dir.to_owned());
20658            }
20659        }
20660
20661        None
20662    }
20663
20664    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
20665        self.active_excerpt(cx)?
20666            .1
20667            .read(cx)
20668            .file()
20669            .and_then(|f| f.as_local())
20670    }
20671
20672    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
20673        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20674            let buffer = buffer.read(cx);
20675            if let Some(project_path) = buffer.project_path(cx) {
20676                let project = self.project()?.read(cx);
20677                project.absolute_path(&project_path, cx)
20678            } else {
20679                buffer
20680                    .file()
20681                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
20682            }
20683        })
20684    }
20685
20686    pub fn reveal_in_finder(
20687        &mut self,
20688        _: &RevealInFileManager,
20689        _window: &mut Window,
20690        cx: &mut Context<Self>,
20691    ) {
20692        if let Some(target) = self.target_file(cx) {
20693            cx.reveal_path(&target.abs_path(cx));
20694        }
20695    }
20696
20697    pub fn copy_path(
20698        &mut self,
20699        _: &zed_actions::workspace::CopyPath,
20700        _window: &mut Window,
20701        cx: &mut Context<Self>,
20702    ) {
20703        if let Some(path) = self.target_file_abs_path(cx)
20704            && let Some(path) = path.to_str()
20705        {
20706            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20707        } else {
20708            cx.propagate();
20709        }
20710    }
20711
20712    pub fn copy_relative_path(
20713        &mut self,
20714        _: &zed_actions::workspace::CopyRelativePath,
20715        _window: &mut Window,
20716        cx: &mut Context<Self>,
20717    ) {
20718        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20719            let project = self.project()?.read(cx);
20720            let path = buffer.read(cx).file()?.path();
20721            let path = path.display(project.path_style(cx));
20722            Some(path)
20723        }) {
20724            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20725        } else {
20726            cx.propagate();
20727        }
20728    }
20729
20730    /// Returns the project path for the editor's buffer, if any buffer is
20731    /// opened in the editor.
20732    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
20733        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
20734            buffer.read(cx).project_path(cx)
20735        } else {
20736            None
20737        }
20738    }
20739
20740    // Returns true if the editor handled a go-to-line request
20741    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
20742        maybe!({
20743            let breakpoint_store = self.breakpoint_store.as_ref()?;
20744
20745            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
20746            else {
20747                self.clear_row_highlights::<ActiveDebugLine>();
20748                return None;
20749            };
20750
20751            let position = active_stack_frame.position;
20752            let buffer_id = position.buffer_id?;
20753            let snapshot = self
20754                .project
20755                .as_ref()?
20756                .read(cx)
20757                .buffer_for_id(buffer_id, cx)?
20758                .read(cx)
20759                .snapshot();
20760
20761            let mut handled = false;
20762            for (id, ExcerptRange { context, .. }) in
20763                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
20764            {
20765                if context.start.cmp(&position, &snapshot).is_ge()
20766                    || context.end.cmp(&position, &snapshot).is_lt()
20767                {
20768                    continue;
20769                }
20770                let snapshot = self.buffer.read(cx).snapshot(cx);
20771                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
20772
20773                handled = true;
20774                self.clear_row_highlights::<ActiveDebugLine>();
20775
20776                self.go_to_line::<ActiveDebugLine>(
20777                    multibuffer_anchor,
20778                    Some(cx.theme().colors().editor_debugger_active_line_background),
20779                    window,
20780                    cx,
20781                );
20782
20783                cx.notify();
20784            }
20785
20786            handled.then_some(())
20787        })
20788        .is_some()
20789    }
20790
20791    pub fn copy_file_name_without_extension(
20792        &mut self,
20793        _: &CopyFileNameWithoutExtension,
20794        _: &mut Window,
20795        cx: &mut Context<Self>,
20796    ) {
20797        if let Some(file_stem) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20798            let file = buffer.read(cx).file()?;
20799            file.path().file_stem()
20800        }) {
20801            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
20802        }
20803    }
20804
20805    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
20806        if let Some(file_name) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20807            let file = buffer.read(cx).file()?;
20808            Some(file.file_name(cx))
20809        }) {
20810            cx.write_to_clipboard(ClipboardItem::new_string(file_name.to_string()));
20811        }
20812    }
20813
20814    pub fn toggle_git_blame(
20815        &mut self,
20816        _: &::git::Blame,
20817        window: &mut Window,
20818        cx: &mut Context<Self>,
20819    ) {
20820        self.show_git_blame_gutter = !self.show_git_blame_gutter;
20821
20822        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
20823            self.start_git_blame(true, window, cx);
20824        }
20825
20826        cx.notify();
20827    }
20828
20829    pub fn toggle_git_blame_inline(
20830        &mut self,
20831        _: &ToggleGitBlameInline,
20832        window: &mut Window,
20833        cx: &mut Context<Self>,
20834    ) {
20835        self.toggle_git_blame_inline_internal(true, window, cx);
20836        cx.notify();
20837    }
20838
20839    pub fn open_git_blame_commit(
20840        &mut self,
20841        _: &OpenGitBlameCommit,
20842        window: &mut Window,
20843        cx: &mut Context<Self>,
20844    ) {
20845        self.open_git_blame_commit_internal(window, cx);
20846    }
20847
20848    fn open_git_blame_commit_internal(
20849        &mut self,
20850        window: &mut Window,
20851        cx: &mut Context<Self>,
20852    ) -> Option<()> {
20853        let blame = self.blame.as_ref()?;
20854        let snapshot = self.snapshot(window, cx);
20855        let cursor = self
20856            .selections
20857            .newest::<Point>(&snapshot.display_snapshot)
20858            .head();
20859        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
20860        let (_, blame_entry) = blame
20861            .update(cx, |blame, cx| {
20862                blame
20863                    .blame_for_rows(
20864                        &[RowInfo {
20865                            buffer_id: Some(buffer.remote_id()),
20866                            buffer_row: Some(point.row),
20867                            ..Default::default()
20868                        }],
20869                        cx,
20870                    )
20871                    .next()
20872            })
20873            .flatten()?;
20874        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20875        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
20876        let workspace = self.workspace()?.downgrade();
20877        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
20878        None
20879    }
20880
20881    pub fn git_blame_inline_enabled(&self) -> bool {
20882        self.git_blame_inline_enabled
20883    }
20884
20885    pub fn toggle_selection_menu(
20886        &mut self,
20887        _: &ToggleSelectionMenu,
20888        _: &mut Window,
20889        cx: &mut Context<Self>,
20890    ) {
20891        self.show_selection_menu = self
20892            .show_selection_menu
20893            .map(|show_selections_menu| !show_selections_menu)
20894            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
20895
20896        cx.notify();
20897    }
20898
20899    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
20900        self.show_selection_menu
20901            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
20902    }
20903
20904    fn start_git_blame(
20905        &mut self,
20906        user_triggered: bool,
20907        window: &mut Window,
20908        cx: &mut Context<Self>,
20909    ) {
20910        if let Some(project) = self.project() {
20911            if let Some(buffer) = self.buffer().read(cx).as_singleton()
20912                && buffer.read(cx).file().is_none()
20913            {
20914                return;
20915            }
20916
20917            let focused = self.focus_handle(cx).contains_focused(window, cx);
20918
20919            let project = project.clone();
20920            let blame = cx
20921                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
20922            self.blame_subscription =
20923                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
20924            self.blame = Some(blame);
20925        }
20926    }
20927
20928    fn toggle_git_blame_inline_internal(
20929        &mut self,
20930        user_triggered: bool,
20931        window: &mut Window,
20932        cx: &mut Context<Self>,
20933    ) {
20934        if self.git_blame_inline_enabled {
20935            self.git_blame_inline_enabled = false;
20936            self.show_git_blame_inline = false;
20937            self.show_git_blame_inline_delay_task.take();
20938        } else {
20939            self.git_blame_inline_enabled = true;
20940            self.start_git_blame_inline(user_triggered, window, cx);
20941        }
20942
20943        cx.notify();
20944    }
20945
20946    fn start_git_blame_inline(
20947        &mut self,
20948        user_triggered: bool,
20949        window: &mut Window,
20950        cx: &mut Context<Self>,
20951    ) {
20952        self.start_git_blame(user_triggered, window, cx);
20953
20954        if ProjectSettings::get_global(cx)
20955            .git
20956            .inline_blame_delay()
20957            .is_some()
20958        {
20959            self.start_inline_blame_timer(window, cx);
20960        } else {
20961            self.show_git_blame_inline = true
20962        }
20963    }
20964
20965    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
20966        self.blame.as_ref()
20967    }
20968
20969    pub fn show_git_blame_gutter(&self) -> bool {
20970        self.show_git_blame_gutter
20971    }
20972
20973    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
20974        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
20975    }
20976
20977    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
20978        self.show_git_blame_inline
20979            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
20980            && !self.newest_selection_head_on_empty_line(cx)
20981            && self.has_blame_entries(cx)
20982    }
20983
20984    fn has_blame_entries(&self, cx: &App) -> bool {
20985        self.blame()
20986            .is_some_and(|blame| blame.read(cx).has_generated_entries())
20987    }
20988
20989    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
20990        let cursor_anchor = self.selections.newest_anchor().head();
20991
20992        let snapshot = self.buffer.read(cx).snapshot(cx);
20993        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
20994
20995        snapshot.line_len(buffer_row) == 0
20996    }
20997
20998    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
20999        let buffer_and_selection = maybe!({
21000            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
21001            let selection_range = selection.range();
21002
21003            let multi_buffer = self.buffer().read(cx);
21004            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
21005            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
21006
21007            let (buffer, range, _) = if selection.reversed {
21008                buffer_ranges.first()
21009            } else {
21010                buffer_ranges.last()
21011            }?;
21012
21013            let start_row_in_buffer = text::ToPoint::to_point(&range.start, buffer).row;
21014            let end_row_in_buffer = text::ToPoint::to_point(&range.end, buffer).row;
21015
21016            let Some(buffer_diff) = multi_buffer.diff_for(buffer.remote_id()) else {
21017                let selection = start_row_in_buffer..end_row_in_buffer;
21018
21019                return Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection));
21020            };
21021
21022            let buffer_diff_snapshot = buffer_diff.read(cx).snapshot(cx);
21023
21024            Some((
21025                multi_buffer.buffer(buffer.remote_id()).unwrap(),
21026                buffer_diff_snapshot.row_to_base_text_row(start_row_in_buffer, buffer)
21027                    ..buffer_diff_snapshot.row_to_base_text_row(end_row_in_buffer, buffer),
21028            ))
21029        });
21030
21031        let Some((buffer, selection)) = buffer_and_selection else {
21032            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
21033        };
21034
21035        let Some(project) = self.project() else {
21036            return Task::ready(Err(anyhow!("editor does not have project")));
21037        };
21038
21039        project.update(cx, |project, cx| {
21040            project.get_permalink_to_line(&buffer, selection, cx)
21041        })
21042    }
21043
21044    pub fn copy_permalink_to_line(
21045        &mut self,
21046        _: &CopyPermalinkToLine,
21047        window: &mut Window,
21048        cx: &mut Context<Self>,
21049    ) {
21050        let permalink_task = self.get_permalink_to_line(cx);
21051        let workspace = self.workspace();
21052
21053        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
21054            Ok(permalink) => {
21055                cx.update(|_, cx| {
21056                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
21057                })
21058                .ok();
21059            }
21060            Err(err) => {
21061                let message = format!("Failed to copy permalink: {err}");
21062
21063                anyhow::Result::<()>::Err(err).log_err();
21064
21065                if let Some(workspace) = workspace {
21066                    workspace
21067                        .update_in(cx, |workspace, _, cx| {
21068                            struct CopyPermalinkToLine;
21069
21070                            workspace.show_toast(
21071                                Toast::new(
21072                                    NotificationId::unique::<CopyPermalinkToLine>(),
21073                                    message,
21074                                ),
21075                                cx,
21076                            )
21077                        })
21078                        .ok();
21079                }
21080            }
21081        })
21082        .detach();
21083    }
21084
21085    pub fn copy_file_location(
21086        &mut self,
21087        _: &CopyFileLocation,
21088        _: &mut Window,
21089        cx: &mut Context<Self>,
21090    ) {
21091        let selection = self
21092            .selections
21093            .newest::<Point>(&self.display_snapshot(cx))
21094            .start
21095            .row
21096            + 1;
21097        if let Some(file_location) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
21098            let project = self.project()?.read(cx);
21099            let file = buffer.read(cx).file()?;
21100            let path = file.path().display(project.path_style(cx));
21101
21102            Some(format!("{path}:{selection}"))
21103        }) {
21104            cx.write_to_clipboard(ClipboardItem::new_string(file_location));
21105        }
21106    }
21107
21108    pub fn open_permalink_to_line(
21109        &mut self,
21110        _: &OpenPermalinkToLine,
21111        window: &mut Window,
21112        cx: &mut Context<Self>,
21113    ) {
21114        let permalink_task = self.get_permalink_to_line(cx);
21115        let workspace = self.workspace();
21116
21117        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
21118            Ok(permalink) => {
21119                cx.update(|_, cx| {
21120                    cx.open_url(permalink.as_ref());
21121                })
21122                .ok();
21123            }
21124            Err(err) => {
21125                let message = format!("Failed to open permalink: {err}");
21126
21127                anyhow::Result::<()>::Err(err).log_err();
21128
21129                if let Some(workspace) = workspace {
21130                    workspace
21131                        .update(cx, |workspace, cx| {
21132                            struct OpenPermalinkToLine;
21133
21134                            workspace.show_toast(
21135                                Toast::new(
21136                                    NotificationId::unique::<OpenPermalinkToLine>(),
21137                                    message,
21138                                ),
21139                                cx,
21140                            )
21141                        })
21142                        .ok();
21143                }
21144            }
21145        })
21146        .detach();
21147    }
21148
21149    pub fn insert_uuid_v4(
21150        &mut self,
21151        _: &InsertUuidV4,
21152        window: &mut Window,
21153        cx: &mut Context<Self>,
21154    ) {
21155        self.insert_uuid(UuidVersion::V4, window, cx);
21156    }
21157
21158    pub fn insert_uuid_v7(
21159        &mut self,
21160        _: &InsertUuidV7,
21161        window: &mut Window,
21162        cx: &mut Context<Self>,
21163    ) {
21164        self.insert_uuid(UuidVersion::V7, window, cx);
21165    }
21166
21167    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
21168        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
21169        self.transact(window, cx, |this, window, cx| {
21170            let edits = this
21171                .selections
21172                .all::<Point>(&this.display_snapshot(cx))
21173                .into_iter()
21174                .map(|selection| {
21175                    let uuid = match version {
21176                        UuidVersion::V4 => uuid::Uuid::new_v4(),
21177                        UuidVersion::V7 => uuid::Uuid::now_v7(),
21178                    };
21179
21180                    (selection.range(), uuid.to_string())
21181                });
21182            this.edit(edits, cx);
21183            this.refresh_edit_prediction(true, false, window, cx);
21184        });
21185    }
21186
21187    pub fn open_selections_in_multibuffer(
21188        &mut self,
21189        _: &OpenSelectionsInMultibuffer,
21190        window: &mut Window,
21191        cx: &mut Context<Self>,
21192    ) {
21193        let multibuffer = self.buffer.read(cx);
21194
21195        let Some(buffer) = multibuffer.as_singleton() else {
21196            return;
21197        };
21198
21199        let Some(workspace) = self.workspace() else {
21200            return;
21201        };
21202
21203        let title = multibuffer.title(cx).to_string();
21204
21205        let locations = self
21206            .selections
21207            .all_anchors(&self.display_snapshot(cx))
21208            .iter()
21209            .map(|selection| {
21210                (
21211                    buffer.clone(),
21212                    (selection.start.text_anchor..selection.end.text_anchor)
21213                        .to_point(buffer.read(cx)),
21214                )
21215            })
21216            .into_group_map();
21217
21218        cx.spawn_in(window, async move |_, cx| {
21219            workspace.update_in(cx, |workspace, window, cx| {
21220                Self::open_locations_in_multibuffer(
21221                    workspace,
21222                    locations,
21223                    format!("Selections for '{title}'"),
21224                    false,
21225                    false,
21226                    MultibufferSelectionMode::All,
21227                    window,
21228                    cx,
21229                );
21230            })
21231        })
21232        .detach();
21233    }
21234
21235    /// Adds a row highlight for the given range. If a row has multiple highlights, the
21236    /// last highlight added will be used.
21237    ///
21238    /// If the range ends at the beginning of a line, then that line will not be highlighted.
21239    pub fn highlight_rows<T: 'static>(
21240        &mut self,
21241        range: Range<Anchor>,
21242        color: Hsla,
21243        options: RowHighlightOptions,
21244        cx: &mut Context<Self>,
21245    ) {
21246        let snapshot = self.buffer().read(cx).snapshot(cx);
21247        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
21248        let ix = row_highlights.binary_search_by(|highlight| {
21249            Ordering::Equal
21250                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
21251                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
21252        });
21253
21254        if let Err(mut ix) = ix {
21255            let index = post_inc(&mut self.highlight_order);
21256
21257            // If this range intersects with the preceding highlight, then merge it with
21258            // the preceding highlight. Otherwise insert a new highlight.
21259            let mut merged = false;
21260            if ix > 0 {
21261                let prev_highlight = &mut row_highlights[ix - 1];
21262                if prev_highlight
21263                    .range
21264                    .end
21265                    .cmp(&range.start, &snapshot)
21266                    .is_ge()
21267                {
21268                    ix -= 1;
21269                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
21270                        prev_highlight.range.end = range.end;
21271                    }
21272                    merged = true;
21273                    prev_highlight.index = index;
21274                    prev_highlight.color = color;
21275                    prev_highlight.options = options;
21276                }
21277            }
21278
21279            if !merged {
21280                row_highlights.insert(
21281                    ix,
21282                    RowHighlight {
21283                        range,
21284                        index,
21285                        color,
21286                        options,
21287                        type_id: TypeId::of::<T>(),
21288                    },
21289                );
21290            }
21291
21292            // If any of the following highlights intersect with this one, merge them.
21293            while let Some(next_highlight) = row_highlights.get(ix + 1) {
21294                let highlight = &row_highlights[ix];
21295                if next_highlight
21296                    .range
21297                    .start
21298                    .cmp(&highlight.range.end, &snapshot)
21299                    .is_le()
21300                {
21301                    if next_highlight
21302                        .range
21303                        .end
21304                        .cmp(&highlight.range.end, &snapshot)
21305                        .is_gt()
21306                    {
21307                        row_highlights[ix].range.end = next_highlight.range.end;
21308                    }
21309                    row_highlights.remove(ix + 1);
21310                } else {
21311                    break;
21312                }
21313            }
21314        }
21315    }
21316
21317    /// Remove any highlighted row ranges of the given type that intersect the
21318    /// given ranges.
21319    pub fn remove_highlighted_rows<T: 'static>(
21320        &mut self,
21321        ranges_to_remove: Vec<Range<Anchor>>,
21322        cx: &mut Context<Self>,
21323    ) {
21324        let snapshot = self.buffer().read(cx).snapshot(cx);
21325        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
21326        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
21327        row_highlights.retain(|highlight| {
21328            while let Some(range_to_remove) = ranges_to_remove.peek() {
21329                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
21330                    Ordering::Less | Ordering::Equal => {
21331                        ranges_to_remove.next();
21332                    }
21333                    Ordering::Greater => {
21334                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
21335                            Ordering::Less | Ordering::Equal => {
21336                                return false;
21337                            }
21338                            Ordering::Greater => break,
21339                        }
21340                    }
21341                }
21342            }
21343
21344            true
21345        })
21346    }
21347
21348    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
21349    pub fn clear_row_highlights<T: 'static>(&mut self) {
21350        self.highlighted_rows.remove(&TypeId::of::<T>());
21351    }
21352
21353    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
21354    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
21355        self.highlighted_rows
21356            .get(&TypeId::of::<T>())
21357            .map_or(&[] as &[_], |vec| vec.as_slice())
21358            .iter()
21359            .map(|highlight| (highlight.range.clone(), highlight.color))
21360    }
21361
21362    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
21363    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
21364    /// Allows to ignore certain kinds of highlights.
21365    pub fn highlighted_display_rows(
21366        &self,
21367        window: &mut Window,
21368        cx: &mut App,
21369    ) -> BTreeMap<DisplayRow, LineHighlight> {
21370        let snapshot = self.snapshot(window, cx);
21371        let mut used_highlight_orders = HashMap::default();
21372        self.highlighted_rows
21373            .iter()
21374            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
21375            .fold(
21376                BTreeMap::<DisplayRow, LineHighlight>::new(),
21377                |mut unique_rows, highlight| {
21378                    let start = highlight.range.start.to_display_point(&snapshot);
21379                    let end = highlight.range.end.to_display_point(&snapshot);
21380                    let start_row = start.row().0;
21381                    let end_row = if !highlight.range.end.text_anchor.is_max() && end.column() == 0
21382                    {
21383                        end.row().0.saturating_sub(1)
21384                    } else {
21385                        end.row().0
21386                    };
21387                    for row in start_row..=end_row {
21388                        let used_index =
21389                            used_highlight_orders.entry(row).or_insert(highlight.index);
21390                        if highlight.index >= *used_index {
21391                            *used_index = highlight.index;
21392                            unique_rows.insert(
21393                                DisplayRow(row),
21394                                LineHighlight {
21395                                    include_gutter: highlight.options.include_gutter,
21396                                    border: None,
21397                                    background: highlight.color.into(),
21398                                    type_id: Some(highlight.type_id),
21399                                },
21400                            );
21401                        }
21402                    }
21403                    unique_rows
21404                },
21405            )
21406    }
21407
21408    pub fn highlighted_display_row_for_autoscroll(
21409        &self,
21410        snapshot: &DisplaySnapshot,
21411    ) -> Option<DisplayRow> {
21412        self.highlighted_rows
21413            .values()
21414            .flat_map(|highlighted_rows| highlighted_rows.iter())
21415            .filter_map(|highlight| {
21416                if highlight.options.autoscroll {
21417                    Some(highlight.range.start.to_display_point(snapshot).row())
21418                } else {
21419                    None
21420                }
21421            })
21422            .min()
21423    }
21424
21425    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
21426        self.highlight_background::<SearchWithinRange>(
21427            ranges,
21428            |_, colors| colors.colors().editor_document_highlight_read_background,
21429            cx,
21430        )
21431    }
21432
21433    pub fn set_breadcrumb_header(&mut self, new_header: String) {
21434        self.breadcrumb_header = Some(new_header);
21435    }
21436
21437    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
21438        self.clear_background_highlights::<SearchWithinRange>(cx);
21439    }
21440
21441    pub fn highlight_background<T: 'static>(
21442        &mut self,
21443        ranges: &[Range<Anchor>],
21444        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
21445        cx: &mut Context<Self>,
21446    ) {
21447        self.background_highlights.insert(
21448            HighlightKey::Type(TypeId::of::<T>()),
21449            (Arc::new(color_fetcher), Arc::from(ranges)),
21450        );
21451        self.scrollbar_marker_state.dirty = true;
21452        cx.notify();
21453    }
21454
21455    pub fn highlight_background_key<T: 'static>(
21456        &mut self,
21457        key: usize,
21458        ranges: &[Range<Anchor>],
21459        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
21460        cx: &mut Context<Self>,
21461    ) {
21462        self.background_highlights.insert(
21463            HighlightKey::TypePlus(TypeId::of::<T>(), key),
21464            (Arc::new(color_fetcher), Arc::from(ranges)),
21465        );
21466        self.scrollbar_marker_state.dirty = true;
21467        cx.notify();
21468    }
21469
21470    pub fn clear_background_highlights<T: 'static>(
21471        &mut self,
21472        cx: &mut Context<Self>,
21473    ) -> Option<BackgroundHighlight> {
21474        let text_highlights = self
21475            .background_highlights
21476            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
21477        if !text_highlights.1.is_empty() {
21478            self.scrollbar_marker_state.dirty = true;
21479            cx.notify();
21480        }
21481        Some(text_highlights)
21482    }
21483
21484    pub fn highlight_gutter<T: 'static>(
21485        &mut self,
21486        ranges: impl Into<Vec<Range<Anchor>>>,
21487        color_fetcher: fn(&App) -> Hsla,
21488        cx: &mut Context<Self>,
21489    ) {
21490        self.gutter_highlights
21491            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
21492        cx.notify();
21493    }
21494
21495    pub fn clear_gutter_highlights<T: 'static>(
21496        &mut self,
21497        cx: &mut Context<Self>,
21498    ) -> Option<GutterHighlight> {
21499        cx.notify();
21500        self.gutter_highlights.remove(&TypeId::of::<T>())
21501    }
21502
21503    pub fn insert_gutter_highlight<T: 'static>(
21504        &mut self,
21505        range: Range<Anchor>,
21506        color_fetcher: fn(&App) -> Hsla,
21507        cx: &mut Context<Self>,
21508    ) {
21509        let snapshot = self.buffer().read(cx).snapshot(cx);
21510        let mut highlights = self
21511            .gutter_highlights
21512            .remove(&TypeId::of::<T>())
21513            .map(|(_, highlights)| highlights)
21514            .unwrap_or_default();
21515        let ix = highlights.binary_search_by(|highlight| {
21516            Ordering::Equal
21517                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
21518                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
21519        });
21520        if let Err(ix) = ix {
21521            highlights.insert(ix, range);
21522        }
21523        self.gutter_highlights
21524            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
21525    }
21526
21527    pub fn remove_gutter_highlights<T: 'static>(
21528        &mut self,
21529        ranges_to_remove: Vec<Range<Anchor>>,
21530        cx: &mut Context<Self>,
21531    ) {
21532        let snapshot = self.buffer().read(cx).snapshot(cx);
21533        let Some((color_fetcher, mut gutter_highlights)) =
21534            self.gutter_highlights.remove(&TypeId::of::<T>())
21535        else {
21536            return;
21537        };
21538        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
21539        gutter_highlights.retain(|highlight| {
21540            while let Some(range_to_remove) = ranges_to_remove.peek() {
21541                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
21542                    Ordering::Less | Ordering::Equal => {
21543                        ranges_to_remove.next();
21544                    }
21545                    Ordering::Greater => {
21546                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
21547                            Ordering::Less | Ordering::Equal => {
21548                                return false;
21549                            }
21550                            Ordering::Greater => break,
21551                        }
21552                    }
21553                }
21554            }
21555
21556            true
21557        });
21558        self.gutter_highlights
21559            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
21560    }
21561
21562    #[cfg(feature = "test-support")]
21563    pub fn all_text_highlights(
21564        &self,
21565        window: &mut Window,
21566        cx: &mut Context<Self>,
21567    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
21568        let snapshot = self.snapshot(window, cx);
21569        self.display_map.update(cx, |display_map, _| {
21570            display_map
21571                .all_text_highlights()
21572                .map(|highlight| {
21573                    let (style, ranges) = highlight.as_ref();
21574                    (
21575                        *style,
21576                        ranges
21577                            .iter()
21578                            .map(|range| range.clone().to_display_points(&snapshot))
21579                            .collect(),
21580                    )
21581                })
21582                .collect()
21583        })
21584    }
21585
21586    #[cfg(feature = "test-support")]
21587    pub fn all_text_background_highlights(
21588        &self,
21589        window: &mut Window,
21590        cx: &mut Context<Self>,
21591    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21592        let snapshot = self.snapshot(window, cx);
21593        let buffer = &snapshot.buffer_snapshot();
21594        let start = buffer.anchor_before(MultiBufferOffset(0));
21595        let end = buffer.anchor_after(buffer.len());
21596        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
21597    }
21598
21599    #[cfg(any(test, feature = "test-support"))]
21600    pub fn sorted_background_highlights_in_range(
21601        &self,
21602        search_range: Range<Anchor>,
21603        display_snapshot: &DisplaySnapshot,
21604        theme: &Theme,
21605    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21606        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
21607        res.sort_by(|a, b| {
21608            a.0.start
21609                .cmp(&b.0.start)
21610                .then_with(|| a.0.end.cmp(&b.0.end))
21611                .then_with(|| a.1.cmp(&b.1))
21612        });
21613        res
21614    }
21615
21616    #[cfg(feature = "test-support")]
21617    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
21618        let snapshot = self.buffer().read(cx).snapshot(cx);
21619
21620        let highlights = self
21621            .background_highlights
21622            .get(&HighlightKey::Type(TypeId::of::<
21623                items::BufferSearchHighlights,
21624            >()));
21625
21626        if let Some((_color, ranges)) = highlights {
21627            ranges
21628                .iter()
21629                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
21630                .collect_vec()
21631        } else {
21632            vec![]
21633        }
21634    }
21635
21636    fn document_highlights_for_position<'a>(
21637        &'a self,
21638        position: Anchor,
21639        buffer: &'a MultiBufferSnapshot,
21640    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
21641        let read_highlights = self
21642            .background_highlights
21643            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
21644            .map(|h| &h.1);
21645        let write_highlights = self
21646            .background_highlights
21647            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
21648            .map(|h| &h.1);
21649        let left_position = position.bias_left(buffer);
21650        let right_position = position.bias_right(buffer);
21651        read_highlights
21652            .into_iter()
21653            .chain(write_highlights)
21654            .flat_map(move |ranges| {
21655                let start_ix = match ranges.binary_search_by(|probe| {
21656                    let cmp = probe.end.cmp(&left_position, buffer);
21657                    if cmp.is_ge() {
21658                        Ordering::Greater
21659                    } else {
21660                        Ordering::Less
21661                    }
21662                }) {
21663                    Ok(i) | Err(i) => i,
21664                };
21665
21666                ranges[start_ix..]
21667                    .iter()
21668                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
21669            })
21670    }
21671
21672    pub fn has_background_highlights<T: 'static>(&self) -> bool {
21673        self.background_highlights
21674            .get(&HighlightKey::Type(TypeId::of::<T>()))
21675            .is_some_and(|(_, highlights)| !highlights.is_empty())
21676    }
21677
21678    /// Returns all background highlights for a given range.
21679    ///
21680    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
21681    pub fn background_highlights_in_range(
21682        &self,
21683        search_range: Range<Anchor>,
21684        display_snapshot: &DisplaySnapshot,
21685        theme: &Theme,
21686    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21687        let mut results = Vec::new();
21688        for (color_fetcher, ranges) in self.background_highlights.values() {
21689            let start_ix = match ranges.binary_search_by(|probe| {
21690                let cmp = probe
21691                    .end
21692                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21693                if cmp.is_gt() {
21694                    Ordering::Greater
21695                } else {
21696                    Ordering::Less
21697                }
21698            }) {
21699                Ok(i) | Err(i) => i,
21700            };
21701            for (index, range) in ranges[start_ix..].iter().enumerate() {
21702                if range
21703                    .start
21704                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21705                    .is_ge()
21706                {
21707                    break;
21708                }
21709
21710                let color = color_fetcher(&(start_ix + index), theme);
21711                let start = range.start.to_display_point(display_snapshot);
21712                let end = range.end.to_display_point(display_snapshot);
21713                results.push((start..end, color))
21714            }
21715        }
21716        results
21717    }
21718
21719    pub fn gutter_highlights_in_range(
21720        &self,
21721        search_range: Range<Anchor>,
21722        display_snapshot: &DisplaySnapshot,
21723        cx: &App,
21724    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21725        let mut results = Vec::new();
21726        for (color_fetcher, ranges) in self.gutter_highlights.values() {
21727            let color = color_fetcher(cx);
21728            let start_ix = match ranges.binary_search_by(|probe| {
21729                let cmp = probe
21730                    .end
21731                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21732                if cmp.is_gt() {
21733                    Ordering::Greater
21734                } else {
21735                    Ordering::Less
21736                }
21737            }) {
21738                Ok(i) | Err(i) => i,
21739            };
21740            for range in &ranges[start_ix..] {
21741                if range
21742                    .start
21743                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21744                    .is_ge()
21745                {
21746                    break;
21747                }
21748
21749                let start = range.start.to_display_point(display_snapshot);
21750                let end = range.end.to_display_point(display_snapshot);
21751                results.push((start..end, color))
21752            }
21753        }
21754        results
21755    }
21756
21757    /// Get the text ranges corresponding to the redaction query
21758    pub fn redacted_ranges(
21759        &self,
21760        search_range: Range<Anchor>,
21761        display_snapshot: &DisplaySnapshot,
21762        cx: &App,
21763    ) -> Vec<Range<DisplayPoint>> {
21764        display_snapshot
21765            .buffer_snapshot()
21766            .redacted_ranges(search_range, |file| {
21767                if let Some(file) = file {
21768                    file.is_private()
21769                        && EditorSettings::get(
21770                            Some(SettingsLocation {
21771                                worktree_id: file.worktree_id(cx),
21772                                path: file.path().as_ref(),
21773                            }),
21774                            cx,
21775                        )
21776                        .redact_private_values
21777                } else {
21778                    false
21779                }
21780            })
21781            .map(|range| {
21782                range.start.to_display_point(display_snapshot)
21783                    ..range.end.to_display_point(display_snapshot)
21784            })
21785            .collect()
21786    }
21787
21788    pub fn highlight_text_key<T: 'static>(
21789        &mut self,
21790        key: usize,
21791        ranges: Vec<Range<Anchor>>,
21792        style: HighlightStyle,
21793        merge: bool,
21794        cx: &mut Context<Self>,
21795    ) {
21796        self.display_map.update(cx, |map, cx| {
21797            map.highlight_text(
21798                HighlightKey::TypePlus(TypeId::of::<T>(), key),
21799                ranges,
21800                style,
21801                merge,
21802                cx,
21803            );
21804        });
21805        cx.notify();
21806    }
21807
21808    pub fn highlight_text<T: 'static>(
21809        &mut self,
21810        ranges: Vec<Range<Anchor>>,
21811        style: HighlightStyle,
21812        cx: &mut Context<Self>,
21813    ) {
21814        self.display_map.update(cx, |map, cx| {
21815            map.highlight_text(
21816                HighlightKey::Type(TypeId::of::<T>()),
21817                ranges,
21818                style,
21819                false,
21820                cx,
21821            )
21822        });
21823        cx.notify();
21824    }
21825
21826    pub fn text_highlights<'a, T: 'static>(
21827        &'a self,
21828        cx: &'a App,
21829    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
21830        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
21831    }
21832
21833    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
21834        let cleared = self
21835            .display_map
21836            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
21837        if cleared {
21838            cx.notify();
21839        }
21840    }
21841
21842    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
21843        (self.read_only(cx) || self.blink_manager.read(cx).visible())
21844            && self.focus_handle.is_focused(window)
21845    }
21846
21847    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
21848        self.show_cursor_when_unfocused = is_enabled;
21849        cx.notify();
21850    }
21851
21852    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
21853        cx.notify();
21854    }
21855
21856    fn on_debug_session_event(
21857        &mut self,
21858        _session: Entity<Session>,
21859        event: &SessionEvent,
21860        cx: &mut Context<Self>,
21861    ) {
21862        if let SessionEvent::InvalidateInlineValue = event {
21863            self.refresh_inline_values(cx);
21864        }
21865    }
21866
21867    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
21868        let Some(project) = self.project.clone() else {
21869            return;
21870        };
21871
21872        if !self.inline_value_cache.enabled {
21873            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
21874            self.splice_inlays(&inlays, Vec::new(), cx);
21875            return;
21876        }
21877
21878        let current_execution_position = self
21879            .highlighted_rows
21880            .get(&TypeId::of::<ActiveDebugLine>())
21881            .and_then(|lines| lines.last().map(|line| line.range.end));
21882
21883        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
21884            let inline_values = editor
21885                .update(cx, |editor, cx| {
21886                    let Some(current_execution_position) = current_execution_position else {
21887                        return Some(Task::ready(Ok(Vec::new())));
21888                    };
21889
21890                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
21891                        let snapshot = buffer.snapshot(cx);
21892
21893                        let excerpt = snapshot.excerpt_containing(
21894                            current_execution_position..current_execution_position,
21895                        )?;
21896
21897                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
21898                    })?;
21899
21900                    let range =
21901                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
21902
21903                    project.inline_values(buffer, range, cx)
21904                })
21905                .ok()
21906                .flatten()?
21907                .await
21908                .context("refreshing debugger inlays")
21909                .log_err()?;
21910
21911            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
21912
21913            for (buffer_id, inline_value) in inline_values
21914                .into_iter()
21915                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
21916            {
21917                buffer_inline_values
21918                    .entry(buffer_id)
21919                    .or_default()
21920                    .push(inline_value);
21921            }
21922
21923            editor
21924                .update(cx, |editor, cx| {
21925                    let snapshot = editor.buffer.read(cx).snapshot(cx);
21926                    let mut new_inlays = Vec::default();
21927
21928                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
21929                        let buffer_id = buffer_snapshot.remote_id();
21930                        buffer_inline_values
21931                            .get(&buffer_id)
21932                            .into_iter()
21933                            .flatten()
21934                            .for_each(|hint| {
21935                                let inlay = Inlay::debugger(
21936                                    post_inc(&mut editor.next_inlay_id),
21937                                    Anchor::in_buffer(excerpt_id, hint.position),
21938                                    hint.text(),
21939                                );
21940                                if !inlay.text().chars().contains(&'\n') {
21941                                    new_inlays.push(inlay);
21942                                }
21943                            });
21944                    }
21945
21946                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
21947                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
21948
21949                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
21950                })
21951                .ok()?;
21952            Some(())
21953        });
21954    }
21955
21956    fn on_buffer_event(
21957        &mut self,
21958        multibuffer: &Entity<MultiBuffer>,
21959        event: &multi_buffer::Event,
21960        window: &mut Window,
21961        cx: &mut Context<Self>,
21962    ) {
21963        match event {
21964            multi_buffer::Event::Edited { edited_buffer } => {
21965                self.scrollbar_marker_state.dirty = true;
21966                self.active_indent_guides_state.dirty = true;
21967                self.refresh_active_diagnostics(cx);
21968                self.refresh_code_actions(window, cx);
21969                self.refresh_single_line_folds(window, cx);
21970                self.refresh_matching_bracket_highlights(window, cx);
21971                if self.has_active_edit_prediction() {
21972                    self.update_visible_edit_prediction(window, cx);
21973                }
21974
21975                if let Some(buffer) = edited_buffer {
21976                    if buffer.read(cx).file().is_none() {
21977                        cx.emit(EditorEvent::TitleChanged);
21978                    }
21979
21980                    if self.project.is_some() {
21981                        let buffer_id = buffer.read(cx).remote_id();
21982                        self.register_buffer(buffer_id, cx);
21983                        self.update_lsp_data(Some(buffer_id), window, cx);
21984                        self.refresh_inlay_hints(
21985                            InlayHintRefreshReason::BufferEdited(buffer_id),
21986                            cx,
21987                        );
21988                    }
21989                }
21990
21991                cx.emit(EditorEvent::BufferEdited);
21992                cx.emit(SearchEvent::MatchesInvalidated);
21993
21994                let Some(project) = &self.project else { return };
21995                let (telemetry, is_via_ssh) = {
21996                    let project = project.read(cx);
21997                    let telemetry = project.client().telemetry().clone();
21998                    let is_via_ssh = project.is_via_remote_server();
21999                    (telemetry, is_via_ssh)
22000                };
22001                telemetry.log_edit_event("editor", is_via_ssh);
22002            }
22003            multi_buffer::Event::ExcerptsAdded {
22004                buffer,
22005                predecessor,
22006                excerpts,
22007            } => {
22008                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22009                let buffer_id = buffer.read(cx).remote_id();
22010                if self.buffer.read(cx).diff_for(buffer_id).is_none()
22011                    && let Some(project) = &self.project
22012                {
22013                    update_uncommitted_diff_for_buffer(
22014                        cx.entity(),
22015                        project,
22016                        [buffer.clone()],
22017                        self.buffer.clone(),
22018                        cx,
22019                    )
22020                    .detach();
22021                }
22022                self.update_lsp_data(Some(buffer_id), window, cx);
22023                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
22024                self.colorize_brackets(false, cx);
22025                cx.emit(EditorEvent::ExcerptsAdded {
22026                    buffer: buffer.clone(),
22027                    predecessor: *predecessor,
22028                    excerpts: excerpts.clone(),
22029                });
22030            }
22031            multi_buffer::Event::ExcerptsRemoved {
22032                ids,
22033                removed_buffer_ids,
22034            } => {
22035                if let Some(inlay_hints) = &mut self.inlay_hints {
22036                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
22037                }
22038                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
22039                for buffer_id in removed_buffer_ids {
22040                    self.registered_buffers.remove(buffer_id);
22041                }
22042                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22043                cx.emit(EditorEvent::ExcerptsRemoved {
22044                    ids: ids.clone(),
22045                    removed_buffer_ids: removed_buffer_ids.clone(),
22046                });
22047            }
22048            multi_buffer::Event::ExcerptsEdited {
22049                excerpt_ids,
22050                buffer_ids,
22051            } => {
22052                self.display_map.update(cx, |map, cx| {
22053                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
22054                });
22055                cx.emit(EditorEvent::ExcerptsEdited {
22056                    ids: excerpt_ids.clone(),
22057                });
22058            }
22059            multi_buffer::Event::ExcerptsExpanded { ids } => {
22060                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
22061                self.refresh_document_highlights(cx);
22062                for id in ids {
22063                    self.fetched_tree_sitter_chunks.remove(id);
22064                }
22065                self.colorize_brackets(false, cx);
22066                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
22067            }
22068            multi_buffer::Event::Reparsed(buffer_id) => {
22069                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22070                self.refresh_selected_text_highlights(true, window, cx);
22071                self.colorize_brackets(true, cx);
22072                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22073
22074                cx.emit(EditorEvent::Reparsed(*buffer_id));
22075            }
22076            multi_buffer::Event::DiffHunksToggled => {
22077                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22078            }
22079            multi_buffer::Event::LanguageChanged(buffer_id, is_fresh_language) => {
22080                if !is_fresh_language {
22081                    self.registered_buffers.remove(&buffer_id);
22082                }
22083                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22084                cx.emit(EditorEvent::Reparsed(*buffer_id));
22085                cx.notify();
22086            }
22087            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
22088            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
22089            multi_buffer::Event::FileHandleChanged
22090            | multi_buffer::Event::Reloaded
22091            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
22092            multi_buffer::Event::DiagnosticsUpdated => {
22093                self.update_diagnostics_state(window, cx);
22094            }
22095            _ => {}
22096        };
22097    }
22098
22099    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
22100        if !self.diagnostics_enabled() {
22101            return;
22102        }
22103        self.refresh_active_diagnostics(cx);
22104        self.refresh_inline_diagnostics(true, window, cx);
22105        self.scrollbar_marker_state.dirty = true;
22106        cx.notify();
22107    }
22108
22109    pub fn start_temporary_diff_override(&mut self) {
22110        self.load_diff_task.take();
22111        self.temporary_diff_override = true;
22112    }
22113
22114    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
22115        self.temporary_diff_override = false;
22116        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
22117        self.buffer.update(cx, |buffer, cx| {
22118            buffer.set_all_diff_hunks_collapsed(cx);
22119        });
22120
22121        if let Some(project) = self.project.clone() {
22122            self.load_diff_task = Some(
22123                update_uncommitted_diff_for_buffer(
22124                    cx.entity(),
22125                    &project,
22126                    self.buffer.read(cx).all_buffers(),
22127                    self.buffer.clone(),
22128                    cx,
22129                )
22130                .shared(),
22131            );
22132        }
22133    }
22134
22135    fn on_display_map_changed(
22136        &mut self,
22137        _: Entity<DisplayMap>,
22138        _: &mut Window,
22139        cx: &mut Context<Self>,
22140    ) {
22141        cx.notify();
22142    }
22143
22144    fn fetch_accent_data(&self, cx: &App) -> Option<AccentData> {
22145        if !self.mode.is_full() {
22146            return None;
22147        }
22148
22149        let theme_settings = theme::ThemeSettings::get_global(cx);
22150        let theme = cx.theme();
22151        let accent_colors = theme.accents().clone();
22152
22153        let accent_overrides = theme_settings
22154            .theme_overrides
22155            .get(theme.name.as_ref())
22156            .map(|theme_style| &theme_style.accents)
22157            .into_iter()
22158            .flatten()
22159            .chain(
22160                theme_settings
22161                    .experimental_theme_overrides
22162                    .as_ref()
22163                    .map(|overrides| &overrides.accents)
22164                    .into_iter()
22165                    .flatten(),
22166            )
22167            .flat_map(|accent| accent.0.clone())
22168            .collect();
22169
22170        Some(AccentData {
22171            colors: accent_colors,
22172            overrides: accent_overrides,
22173        })
22174    }
22175
22176    fn fetch_applicable_language_settings(
22177        &self,
22178        cx: &App,
22179    ) -> HashMap<Option<LanguageName>, LanguageSettings> {
22180        if !self.mode.is_full() {
22181            return HashMap::default();
22182        }
22183
22184        self.buffer().read(cx).all_buffers().into_iter().fold(
22185            HashMap::default(),
22186            |mut acc, buffer| {
22187                let buffer = buffer.read(cx);
22188                let language = buffer.language().map(|language| language.name());
22189                if let hash_map::Entry::Vacant(v) = acc.entry(language.clone()) {
22190                    let file = buffer.file();
22191                    v.insert(language_settings(language, file, cx).into_owned());
22192                }
22193                acc
22194            },
22195        )
22196    }
22197
22198    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22199        let new_language_settings = self.fetch_applicable_language_settings(cx);
22200        let language_settings_changed = new_language_settings != self.applicable_language_settings;
22201        self.applicable_language_settings = new_language_settings;
22202
22203        let new_accents = self.fetch_accent_data(cx);
22204        let accents_changed = new_accents != self.accent_data;
22205        self.accent_data = new_accents;
22206
22207        if self.diagnostics_enabled() {
22208            let new_severity = EditorSettings::get_global(cx)
22209                .diagnostics_max_severity
22210                .unwrap_or(DiagnosticSeverity::Hint);
22211            self.set_max_diagnostics_severity(new_severity, cx);
22212        }
22213        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22214        self.update_edit_prediction_settings(cx);
22215        self.refresh_edit_prediction(true, false, window, cx);
22216        self.refresh_inline_values(cx);
22217        self.refresh_inlay_hints(
22218            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
22219                self.selections.newest_anchor().head(),
22220                &self.buffer.read(cx).snapshot(cx),
22221                cx,
22222            )),
22223            cx,
22224        );
22225
22226        let old_cursor_shape = self.cursor_shape;
22227        let old_show_breadcrumbs = self.show_breadcrumbs;
22228
22229        {
22230            let editor_settings = EditorSettings::get_global(cx);
22231            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
22232            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
22233            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
22234            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
22235        }
22236
22237        if old_cursor_shape != self.cursor_shape {
22238            cx.emit(EditorEvent::CursorShapeChanged);
22239        }
22240
22241        if old_show_breadcrumbs != self.show_breadcrumbs {
22242            cx.emit(EditorEvent::BreadcrumbsChanged);
22243        }
22244
22245        let project_settings = ProjectSettings::get_global(cx);
22246        self.buffer_serialization = self
22247            .should_serialize_buffer()
22248            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
22249
22250        if self.mode.is_full() {
22251            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
22252            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
22253            if self.show_inline_diagnostics != show_inline_diagnostics {
22254                self.show_inline_diagnostics = show_inline_diagnostics;
22255                self.refresh_inline_diagnostics(false, window, cx);
22256            }
22257
22258            if self.git_blame_inline_enabled != inline_blame_enabled {
22259                self.toggle_git_blame_inline_internal(false, window, cx);
22260            }
22261
22262            let minimap_settings = EditorSettings::get_global(cx).minimap;
22263            if self.minimap_visibility != MinimapVisibility::Disabled {
22264                if self.minimap_visibility.settings_visibility()
22265                    != minimap_settings.minimap_enabled()
22266                {
22267                    self.set_minimap_visibility(
22268                        MinimapVisibility::for_mode(self.mode(), cx),
22269                        window,
22270                        cx,
22271                    );
22272                } else if let Some(minimap_entity) = self.minimap.as_ref() {
22273                    minimap_entity.update(cx, |minimap_editor, cx| {
22274                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
22275                    })
22276                }
22277            }
22278
22279            if language_settings_changed || accents_changed {
22280                self.colorize_brackets(true, cx);
22281            }
22282
22283            if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
22284                colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
22285            }) {
22286                if !inlay_splice.is_empty() {
22287                    self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
22288                }
22289                self.refresh_colors_for_visible_range(None, window, cx);
22290            }
22291        }
22292
22293        cx.notify();
22294    }
22295
22296    pub fn set_searchable(&mut self, searchable: bool) {
22297        self.searchable = searchable;
22298    }
22299
22300    pub fn searchable(&self) -> bool {
22301        self.searchable
22302    }
22303
22304    pub fn open_excerpts_in_split(
22305        &mut self,
22306        _: &OpenExcerptsSplit,
22307        window: &mut Window,
22308        cx: &mut Context<Self>,
22309    ) {
22310        self.open_excerpts_common(None, true, window, cx)
22311    }
22312
22313    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
22314        self.open_excerpts_common(None, false, window, cx)
22315    }
22316
22317    fn open_excerpts_common(
22318        &mut self,
22319        jump_data: Option<JumpData>,
22320        split: bool,
22321        window: &mut Window,
22322        cx: &mut Context<Self>,
22323    ) {
22324        let Some(workspace) = self.workspace() else {
22325            cx.propagate();
22326            return;
22327        };
22328
22329        if self.buffer.read(cx).is_singleton() {
22330            cx.propagate();
22331            return;
22332        }
22333
22334        let mut new_selections_by_buffer = HashMap::default();
22335        match &jump_data {
22336            Some(JumpData::MultiBufferPoint {
22337                excerpt_id,
22338                position,
22339                anchor,
22340                line_offset_from_top,
22341            }) => {
22342                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
22343                if let Some(buffer) = multi_buffer_snapshot
22344                    .buffer_id_for_excerpt(*excerpt_id)
22345                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
22346                {
22347                    let buffer_snapshot = buffer.read(cx).snapshot();
22348                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
22349                        language::ToPoint::to_point(anchor, &buffer_snapshot)
22350                    } else {
22351                        buffer_snapshot.clip_point(*position, Bias::Left)
22352                    };
22353                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
22354                    new_selections_by_buffer.insert(
22355                        buffer,
22356                        (
22357                            vec![BufferOffset(jump_to_offset)..BufferOffset(jump_to_offset)],
22358                            Some(*line_offset_from_top),
22359                        ),
22360                    );
22361                }
22362            }
22363            Some(JumpData::MultiBufferRow {
22364                row,
22365                line_offset_from_top,
22366            }) => {
22367                let point = MultiBufferPoint::new(row.0, 0);
22368                if let Some((buffer, buffer_point, _)) =
22369                    self.buffer.read(cx).point_to_buffer_point(point, cx)
22370                {
22371                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
22372                    new_selections_by_buffer
22373                        .entry(buffer)
22374                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
22375                        .0
22376                        .push(BufferOffset(buffer_offset)..BufferOffset(buffer_offset))
22377                }
22378            }
22379            None => {
22380                let selections = self
22381                    .selections
22382                    .all::<MultiBufferOffset>(&self.display_snapshot(cx));
22383                let multi_buffer = self.buffer.read(cx);
22384                for selection in selections {
22385                    for (snapshot, range, _, anchor) in multi_buffer
22386                        .snapshot(cx)
22387                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
22388                    {
22389                        if let Some(anchor) = anchor {
22390                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
22391                            else {
22392                                continue;
22393                            };
22394                            let offset = text::ToOffset::to_offset(
22395                                &anchor.text_anchor,
22396                                &buffer_handle.read(cx).snapshot(),
22397                            );
22398                            let range = BufferOffset(offset)..BufferOffset(offset);
22399                            new_selections_by_buffer
22400                                .entry(buffer_handle)
22401                                .or_insert((Vec::new(), None))
22402                                .0
22403                                .push(range)
22404                        } else {
22405                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
22406                            else {
22407                                continue;
22408                            };
22409                            new_selections_by_buffer
22410                                .entry(buffer_handle)
22411                                .or_insert((Vec::new(), None))
22412                                .0
22413                                .push(range)
22414                        }
22415                    }
22416                }
22417            }
22418        }
22419
22420        new_selections_by_buffer
22421            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
22422
22423        if new_selections_by_buffer.is_empty() {
22424            return;
22425        }
22426
22427        // We defer the pane interaction because we ourselves are a workspace item
22428        // and activating a new item causes the pane to call a method on us reentrantly,
22429        // which panics if we're on the stack.
22430        window.defer(cx, move |window, cx| {
22431            workspace.update(cx, |workspace, cx| {
22432                let pane = if split {
22433                    workspace.adjacent_pane(window, cx)
22434                } else {
22435                    workspace.active_pane().clone()
22436                };
22437
22438                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
22439                    let buffer_read = buffer.read(cx);
22440                    let (has_file, is_project_file) = if let Some(file) = buffer_read.file() {
22441                        (true, project::File::from_dyn(Some(file)).is_some())
22442                    } else {
22443                        (false, false)
22444                    };
22445
22446                    // If project file is none workspace.open_project_item will fail to open the excerpt
22447                    // in a pre existing workspace item if one exists, because Buffer entity_id will be None
22448                    // so we check if there's a tab match in that case first
22449                    let editor = (!has_file || !is_project_file)
22450                        .then(|| {
22451                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
22452                            // so `workspace.open_project_item` will never find them, always opening a new editor.
22453                            // Instead, we try to activate the existing editor in the pane first.
22454                            let (editor, pane_item_index, pane_item_id) =
22455                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
22456                                    let editor = item.downcast::<Editor>()?;
22457                                    let singleton_buffer =
22458                                        editor.read(cx).buffer().read(cx).as_singleton()?;
22459                                    if singleton_buffer == buffer {
22460                                        Some((editor, i, item.item_id()))
22461                                    } else {
22462                                        None
22463                                    }
22464                                })?;
22465                            pane.update(cx, |pane, cx| {
22466                                pane.activate_item(pane_item_index, true, true, window, cx);
22467                                if !PreviewTabsSettings::get_global(cx)
22468                                    .enable_preview_from_multibuffer
22469                                {
22470                                    pane.unpreview_item_if_preview(pane_item_id);
22471                                }
22472                            });
22473                            Some(editor)
22474                        })
22475                        .flatten()
22476                        .unwrap_or_else(|| {
22477                            let keep_old_preview = PreviewTabsSettings::get_global(cx)
22478                                .enable_keep_preview_on_code_navigation;
22479                            let allow_new_preview =
22480                                PreviewTabsSettings::get_global(cx).enable_preview_from_multibuffer;
22481                            workspace.open_project_item::<Self>(
22482                                pane.clone(),
22483                                buffer,
22484                                true,
22485                                true,
22486                                keep_old_preview,
22487                                allow_new_preview,
22488                                window,
22489                                cx,
22490                            )
22491                        });
22492
22493                    editor.update(cx, |editor, cx| {
22494                        if has_file && !is_project_file {
22495                            editor.set_read_only(true);
22496                        }
22497                        let autoscroll = match scroll_offset {
22498                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
22499                            None => Autoscroll::newest(),
22500                        };
22501                        let nav_history = editor.nav_history.take();
22502                        let multibuffer_snapshot = editor.buffer().read(cx).snapshot(cx);
22503                        let Some((&excerpt_id, _, buffer_snapshot)) =
22504                            multibuffer_snapshot.as_singleton()
22505                        else {
22506                            return;
22507                        };
22508                        editor.change_selections(
22509                            SelectionEffects::scroll(autoscroll),
22510                            window,
22511                            cx,
22512                            |s| {
22513                                s.select_ranges(ranges.into_iter().map(|range| {
22514                                    let range = buffer_snapshot.anchor_before(range.start)
22515                                        ..buffer_snapshot.anchor_after(range.end);
22516                                    multibuffer_snapshot
22517                                        .anchor_range_in_excerpt(excerpt_id, range)
22518                                        .unwrap()
22519                                }));
22520                            },
22521                        );
22522                        editor.nav_history = nav_history;
22523                    });
22524                }
22525            })
22526        });
22527    }
22528
22529    // Allow opening excerpts for buffers that either belong to the current project
22530    // or represent synthetic/non-local files (e.g., git blobs). File-less buffers
22531    // are also supported so tests and other in-memory views keep working.
22532    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
22533        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some() || !file.is_local())
22534    }
22535
22536    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<MultiBufferOffsetUtf16>>> {
22537        let snapshot = self.buffer.read(cx).read(cx);
22538        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
22539        Some(
22540            ranges
22541                .iter()
22542                .map(move |range| {
22543                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
22544                })
22545                .collect(),
22546        )
22547    }
22548
22549    fn selection_replacement_ranges(
22550        &self,
22551        range: Range<MultiBufferOffsetUtf16>,
22552        cx: &mut App,
22553    ) -> Vec<Range<MultiBufferOffsetUtf16>> {
22554        let selections = self
22555            .selections
22556            .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22557        let newest_selection = selections
22558            .iter()
22559            .max_by_key(|selection| selection.id)
22560            .unwrap();
22561        let start_delta = range.start.0.0 as isize - newest_selection.start.0.0 as isize;
22562        let end_delta = range.end.0.0 as isize - newest_selection.end.0.0 as isize;
22563        let snapshot = self.buffer.read(cx).read(cx);
22564        selections
22565            .into_iter()
22566            .map(|mut selection| {
22567                selection.start.0.0 =
22568                    (selection.start.0.0 as isize).saturating_add(start_delta) as usize;
22569                selection.end.0.0 = (selection.end.0.0 as isize).saturating_add(end_delta) as usize;
22570                snapshot.clip_offset_utf16(selection.start, Bias::Left)
22571                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
22572            })
22573            .collect()
22574    }
22575
22576    fn report_editor_event(
22577        &self,
22578        reported_event: ReportEditorEvent,
22579        file_extension: Option<String>,
22580        cx: &App,
22581    ) {
22582        if cfg!(any(test, feature = "test-support")) {
22583            return;
22584        }
22585
22586        let Some(project) = &self.project else { return };
22587
22588        // If None, we are in a file without an extension
22589        let file = self
22590            .buffer
22591            .read(cx)
22592            .as_singleton()
22593            .and_then(|b| b.read(cx).file());
22594        let file_extension = file_extension.or(file
22595            .as_ref()
22596            .and_then(|file| Path::new(file.file_name(cx)).extension())
22597            .and_then(|e| e.to_str())
22598            .map(|a| a.to_string()));
22599
22600        let vim_mode_enabled = self.is_vim_mode_enabled(cx);
22601        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
22602        let copilot_enabled = edit_predictions_provider
22603            == language::language_settings::EditPredictionProvider::Copilot;
22604        let copilot_enabled_for_language = self
22605            .buffer
22606            .read(cx)
22607            .language_settings(cx)
22608            .show_edit_predictions;
22609
22610        let project = project.read(cx);
22611        let event_type = reported_event.event_type();
22612
22613        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
22614            telemetry::event!(
22615                event_type,
22616                type = if auto_saved {"autosave"} else {"manual"},
22617                file_extension,
22618                vim_mode_enabled,
22619                copilot_enabled,
22620                copilot_enabled_for_language,
22621                edit_predictions_provider,
22622                is_via_ssh = project.is_via_remote_server(),
22623            );
22624        } else {
22625            telemetry::event!(
22626                event_type,
22627                file_extension,
22628                vim_mode_enabled,
22629                copilot_enabled,
22630                copilot_enabled_for_language,
22631                edit_predictions_provider,
22632                is_via_ssh = project.is_via_remote_server(),
22633            );
22634        };
22635    }
22636
22637    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
22638    /// with each line being an array of {text, highlight} objects.
22639    fn copy_highlight_json(
22640        &mut self,
22641        _: &CopyHighlightJson,
22642        window: &mut Window,
22643        cx: &mut Context<Self>,
22644    ) {
22645        #[derive(Serialize)]
22646        struct Chunk<'a> {
22647            text: String,
22648            highlight: Option<&'a str>,
22649        }
22650
22651        let snapshot = self.buffer.read(cx).snapshot(cx);
22652        let range = self
22653            .selected_text_range(false, window, cx)
22654            .and_then(|selection| {
22655                if selection.range.is_empty() {
22656                    None
22657                } else {
22658                    Some(
22659                        snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22660                            selection.range.start,
22661                        )))
22662                            ..snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22663                                selection.range.end,
22664                            ))),
22665                    )
22666                }
22667            })
22668            .unwrap_or_else(|| MultiBufferOffset(0)..snapshot.len());
22669
22670        let chunks = snapshot.chunks(range, true);
22671        let mut lines = Vec::new();
22672        let mut line: VecDeque<Chunk> = VecDeque::new();
22673
22674        let Some(style) = self.style.as_ref() else {
22675            return;
22676        };
22677
22678        for chunk in chunks {
22679            let highlight = chunk
22680                .syntax_highlight_id
22681                .and_then(|id| id.name(&style.syntax));
22682            let mut chunk_lines = chunk.text.split('\n').peekable();
22683            while let Some(text) = chunk_lines.next() {
22684                let mut merged_with_last_token = false;
22685                if let Some(last_token) = line.back_mut()
22686                    && last_token.highlight == highlight
22687                {
22688                    last_token.text.push_str(text);
22689                    merged_with_last_token = true;
22690                }
22691
22692                if !merged_with_last_token {
22693                    line.push_back(Chunk {
22694                        text: text.into(),
22695                        highlight,
22696                    });
22697                }
22698
22699                if chunk_lines.peek().is_some() {
22700                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
22701                        line.pop_front();
22702                    }
22703                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
22704                        line.pop_back();
22705                    }
22706
22707                    lines.push(mem::take(&mut line));
22708                }
22709            }
22710        }
22711
22712        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
22713            return;
22714        };
22715        cx.write_to_clipboard(ClipboardItem::new_string(lines));
22716    }
22717
22718    pub fn open_context_menu(
22719        &mut self,
22720        _: &OpenContextMenu,
22721        window: &mut Window,
22722        cx: &mut Context<Self>,
22723    ) {
22724        self.request_autoscroll(Autoscroll::newest(), cx);
22725        let position = self
22726            .selections
22727            .newest_display(&self.display_snapshot(cx))
22728            .start;
22729        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
22730    }
22731
22732    pub fn replay_insert_event(
22733        &mut self,
22734        text: &str,
22735        relative_utf16_range: Option<Range<isize>>,
22736        window: &mut Window,
22737        cx: &mut Context<Self>,
22738    ) {
22739        if !self.input_enabled {
22740            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22741            return;
22742        }
22743        if let Some(relative_utf16_range) = relative_utf16_range {
22744            let selections = self
22745                .selections
22746                .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22747            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22748                let new_ranges = selections.into_iter().map(|range| {
22749                    let start = MultiBufferOffsetUtf16(OffsetUtf16(
22750                        range
22751                            .head()
22752                            .0
22753                            .0
22754                            .saturating_add_signed(relative_utf16_range.start),
22755                    ));
22756                    let end = MultiBufferOffsetUtf16(OffsetUtf16(
22757                        range
22758                            .head()
22759                            .0
22760                            .0
22761                            .saturating_add_signed(relative_utf16_range.end),
22762                    ));
22763                    start..end
22764                });
22765                s.select_ranges(new_ranges);
22766            });
22767        }
22768
22769        self.handle_input(text, window, cx);
22770    }
22771
22772    pub fn is_focused(&self, window: &Window) -> bool {
22773        self.focus_handle.is_focused(window)
22774    }
22775
22776    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22777        cx.emit(EditorEvent::Focused);
22778
22779        if let Some(descendant) = self
22780            .last_focused_descendant
22781            .take()
22782            .and_then(|descendant| descendant.upgrade())
22783        {
22784            window.focus(&descendant);
22785        } else {
22786            if let Some(blame) = self.blame.as_ref() {
22787                blame.update(cx, GitBlame::focus)
22788            }
22789
22790            self.blink_manager.update(cx, BlinkManager::enable);
22791            self.show_cursor_names(window, cx);
22792            self.buffer.update(cx, |buffer, cx| {
22793                buffer.finalize_last_transaction(cx);
22794                if self.leader_id.is_none() {
22795                    buffer.set_active_selections(
22796                        &self.selections.disjoint_anchors_arc(),
22797                        self.selections.line_mode(),
22798                        self.cursor_shape,
22799                        cx,
22800                    );
22801                }
22802            });
22803
22804            if let Some(position_map) = self.last_position_map.clone() {
22805                EditorElement::mouse_moved(
22806                    self,
22807                    &MouseMoveEvent {
22808                        position: window.mouse_position(),
22809                        pressed_button: None,
22810                        modifiers: window.modifiers(),
22811                    },
22812                    &position_map,
22813                    window,
22814                    cx,
22815                );
22816            }
22817        }
22818    }
22819
22820    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22821        cx.emit(EditorEvent::FocusedIn)
22822    }
22823
22824    fn handle_focus_out(
22825        &mut self,
22826        event: FocusOutEvent,
22827        _window: &mut Window,
22828        cx: &mut Context<Self>,
22829    ) {
22830        if event.blurred != self.focus_handle {
22831            self.last_focused_descendant = Some(event.blurred);
22832        }
22833        self.selection_drag_state = SelectionDragState::None;
22834        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
22835    }
22836
22837    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22838        self.blink_manager.update(cx, BlinkManager::disable);
22839        self.buffer
22840            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
22841
22842        if let Some(blame) = self.blame.as_ref() {
22843            blame.update(cx, GitBlame::blur)
22844        }
22845        if !self.hover_state.focused(window, cx) {
22846            hide_hover(self, cx);
22847        }
22848        if !self
22849            .context_menu
22850            .borrow()
22851            .as_ref()
22852            .is_some_and(|context_menu| context_menu.focused(window, cx))
22853        {
22854            self.hide_context_menu(window, cx);
22855        }
22856        self.take_active_edit_prediction(cx);
22857        cx.emit(EditorEvent::Blurred);
22858        cx.notify();
22859    }
22860
22861    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22862        let mut pending: String = window
22863            .pending_input_keystrokes()
22864            .into_iter()
22865            .flatten()
22866            .filter_map(|keystroke| keystroke.key_char.clone())
22867            .collect();
22868
22869        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
22870            pending = "".to_string();
22871        }
22872
22873        let existing_pending = self
22874            .text_highlights::<PendingInput>(cx)
22875            .map(|(_, ranges)| ranges.to_vec());
22876        if existing_pending.is_none() && pending.is_empty() {
22877            return;
22878        }
22879        let transaction =
22880            self.transact(window, cx, |this, window, cx| {
22881                let selections = this
22882                    .selections
22883                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
22884                let edits = selections
22885                    .iter()
22886                    .map(|selection| (selection.end..selection.end, pending.clone()));
22887                this.edit(edits, cx);
22888                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22889                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
22890                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
22891                    }));
22892                });
22893                if let Some(existing_ranges) = existing_pending {
22894                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
22895                    this.edit(edits, cx);
22896                }
22897            });
22898
22899        let snapshot = self.snapshot(window, cx);
22900        let ranges = self
22901            .selections
22902            .all::<MultiBufferOffset>(&snapshot.display_snapshot)
22903            .into_iter()
22904            .map(|selection| {
22905                snapshot.buffer_snapshot().anchor_after(selection.end)
22906                    ..snapshot
22907                        .buffer_snapshot()
22908                        .anchor_before(selection.end + pending.len())
22909            })
22910            .collect();
22911
22912        if pending.is_empty() {
22913            self.clear_highlights::<PendingInput>(cx);
22914        } else {
22915            self.highlight_text::<PendingInput>(
22916                ranges,
22917                HighlightStyle {
22918                    underline: Some(UnderlineStyle {
22919                        thickness: px(1.),
22920                        color: None,
22921                        wavy: false,
22922                    }),
22923                    ..Default::default()
22924                },
22925                cx,
22926            );
22927        }
22928
22929        self.ime_transaction = self.ime_transaction.or(transaction);
22930        if let Some(transaction) = self.ime_transaction {
22931            self.buffer.update(cx, |buffer, cx| {
22932                buffer.group_until_transaction(transaction, cx);
22933            });
22934        }
22935
22936        if self.text_highlights::<PendingInput>(cx).is_none() {
22937            self.ime_transaction.take();
22938        }
22939    }
22940
22941    pub fn register_action_renderer(
22942        &mut self,
22943        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
22944    ) -> Subscription {
22945        let id = self.next_editor_action_id.post_inc();
22946        self.editor_actions
22947            .borrow_mut()
22948            .insert(id, Box::new(listener));
22949
22950        let editor_actions = self.editor_actions.clone();
22951        Subscription::new(move || {
22952            editor_actions.borrow_mut().remove(&id);
22953        })
22954    }
22955
22956    pub fn register_action<A: Action>(
22957        &mut self,
22958        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
22959    ) -> Subscription {
22960        let id = self.next_editor_action_id.post_inc();
22961        let listener = Arc::new(listener);
22962        self.editor_actions.borrow_mut().insert(
22963            id,
22964            Box::new(move |_, window, _| {
22965                let listener = listener.clone();
22966                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
22967                    let action = action.downcast_ref().unwrap();
22968                    if phase == DispatchPhase::Bubble {
22969                        listener(action, window, cx)
22970                    }
22971                })
22972            }),
22973        );
22974
22975        let editor_actions = self.editor_actions.clone();
22976        Subscription::new(move || {
22977            editor_actions.borrow_mut().remove(&id);
22978        })
22979    }
22980
22981    pub fn file_header_size(&self) -> u32 {
22982        FILE_HEADER_HEIGHT
22983    }
22984
22985    pub fn restore(
22986        &mut self,
22987        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
22988        window: &mut Window,
22989        cx: &mut Context<Self>,
22990    ) {
22991        self.buffer().update(cx, |multi_buffer, cx| {
22992            for (buffer_id, changes) in revert_changes {
22993                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
22994                    buffer.update(cx, |buffer, cx| {
22995                        buffer.edit(
22996                            changes
22997                                .into_iter()
22998                                .map(|(range, text)| (range, text.to_string())),
22999                            None,
23000                            cx,
23001                        );
23002                    });
23003                }
23004            }
23005        });
23006        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23007            selections.refresh()
23008        });
23009    }
23010
23011    pub fn to_pixel_point(
23012        &mut self,
23013        source: multi_buffer::Anchor,
23014        editor_snapshot: &EditorSnapshot,
23015        window: &mut Window,
23016        cx: &App,
23017    ) -> Option<gpui::Point<Pixels>> {
23018        let source_point = source.to_display_point(editor_snapshot);
23019        self.display_to_pixel_point(source_point, editor_snapshot, window, cx)
23020    }
23021
23022    pub fn display_to_pixel_point(
23023        &mut self,
23024        source: DisplayPoint,
23025        editor_snapshot: &EditorSnapshot,
23026        window: &mut Window,
23027        cx: &App,
23028    ) -> Option<gpui::Point<Pixels>> {
23029        let line_height = self.style(cx).text.line_height_in_pixels(window.rem_size());
23030        let text_layout_details = self.text_layout_details(window);
23031        let scroll_top = text_layout_details
23032            .scroll_anchor
23033            .scroll_position(editor_snapshot)
23034            .y;
23035
23036        if source.row().as_f64() < scroll_top.floor() {
23037            return None;
23038        }
23039        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
23040        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
23041        Some(gpui::Point::new(source_x, source_y))
23042    }
23043
23044    pub fn has_visible_completions_menu(&self) -> bool {
23045        !self.edit_prediction_preview_is_active()
23046            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
23047                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
23048            })
23049    }
23050
23051    pub fn register_addon<T: Addon>(&mut self, instance: T) {
23052        if self.mode.is_minimap() {
23053            return;
23054        }
23055        self.addons
23056            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
23057    }
23058
23059    pub fn unregister_addon<T: Addon>(&mut self) {
23060        self.addons.remove(&std::any::TypeId::of::<T>());
23061    }
23062
23063    pub fn addon<T: Addon>(&self) -> Option<&T> {
23064        let type_id = std::any::TypeId::of::<T>();
23065        self.addons
23066            .get(&type_id)
23067            .and_then(|item| item.to_any().downcast_ref::<T>())
23068    }
23069
23070    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
23071        let type_id = std::any::TypeId::of::<T>();
23072        self.addons
23073            .get_mut(&type_id)
23074            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
23075    }
23076
23077    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
23078        let text_layout_details = self.text_layout_details(window);
23079        let style = &text_layout_details.editor_style;
23080        let font_id = window.text_system().resolve_font(&style.text.font());
23081        let font_size = style.text.font_size.to_pixels(window.rem_size());
23082        let line_height = style.text.line_height_in_pixels(window.rem_size());
23083        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
23084        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
23085
23086        CharacterDimensions {
23087            em_width,
23088            em_advance,
23089            line_height,
23090        }
23091    }
23092
23093    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
23094        self.load_diff_task.clone()
23095    }
23096
23097    fn read_metadata_from_db(
23098        &mut self,
23099        item_id: u64,
23100        workspace_id: WorkspaceId,
23101        window: &mut Window,
23102        cx: &mut Context<Editor>,
23103    ) {
23104        if self.buffer_kind(cx) == ItemBufferKind::Singleton
23105            && !self.mode.is_minimap()
23106            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
23107        {
23108            let buffer_snapshot = OnceCell::new();
23109
23110            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
23111                && !folds.is_empty()
23112            {
23113                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
23114                self.fold_ranges(
23115                    folds
23116                        .into_iter()
23117                        .map(|(start, end)| {
23118                            snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
23119                                ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
23120                        })
23121                        .collect(),
23122                    false,
23123                    window,
23124                    cx,
23125                );
23126            }
23127
23128            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
23129                && !selections.is_empty()
23130            {
23131                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
23132                // skip adding the initial selection to selection history
23133                self.selection_history.mode = SelectionHistoryMode::Skipping;
23134                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23135                    s.select_ranges(selections.into_iter().map(|(start, end)| {
23136                        snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
23137                            ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
23138                    }));
23139                });
23140                self.selection_history.mode = SelectionHistoryMode::Normal;
23141            };
23142        }
23143
23144        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
23145    }
23146
23147    fn update_lsp_data(
23148        &mut self,
23149        for_buffer: Option<BufferId>,
23150        window: &mut Window,
23151        cx: &mut Context<'_, Self>,
23152    ) {
23153        self.pull_diagnostics(for_buffer, window, cx);
23154        self.refresh_colors_for_visible_range(for_buffer, window, cx);
23155    }
23156
23157    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
23158        if self.ignore_lsp_data() {
23159            return;
23160        }
23161        for (_, (visible_buffer, _, _)) in self.visible_excerpts(true, cx) {
23162            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
23163        }
23164    }
23165
23166    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
23167        if self.ignore_lsp_data() {
23168            return;
23169        }
23170
23171        if !self.registered_buffers.contains_key(&buffer_id)
23172            && let Some(project) = self.project.as_ref()
23173        {
23174            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
23175                project.update(cx, |project, cx| {
23176                    self.registered_buffers.insert(
23177                        buffer_id,
23178                        project.register_buffer_with_language_servers(&buffer, cx),
23179                    );
23180                });
23181            } else {
23182                self.registered_buffers.remove(&buffer_id);
23183            }
23184        }
23185    }
23186
23187    fn ignore_lsp_data(&self) -> bool {
23188        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
23189        // skip any LSP updates for it.
23190        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
23191    }
23192
23193    fn create_style(&self, cx: &App) -> EditorStyle {
23194        let settings = ThemeSettings::get_global(cx);
23195
23196        let mut text_style = match self.mode {
23197            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23198                color: cx.theme().colors().editor_foreground,
23199                font_family: settings.ui_font.family.clone(),
23200                font_features: settings.ui_font.features.clone(),
23201                font_fallbacks: settings.ui_font.fallbacks.clone(),
23202                font_size: rems(0.875).into(),
23203                font_weight: settings.ui_font.weight,
23204                line_height: relative(settings.buffer_line_height.value()),
23205                ..Default::default()
23206            },
23207            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23208                color: cx.theme().colors().editor_foreground,
23209                font_family: settings.buffer_font.family.clone(),
23210                font_features: settings.buffer_font.features.clone(),
23211                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23212                font_size: settings.buffer_font_size(cx).into(),
23213                font_weight: settings.buffer_font.weight,
23214                line_height: relative(settings.buffer_line_height.value()),
23215                ..Default::default()
23216            },
23217        };
23218        if let Some(text_style_refinement) = &self.text_style_refinement {
23219            text_style.refine(text_style_refinement)
23220        }
23221
23222        let background = match self.mode {
23223            EditorMode::SingleLine => cx.theme().system().transparent,
23224            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23225            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23226            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23227        };
23228
23229        EditorStyle {
23230            background,
23231            border: cx.theme().colors().border,
23232            local_player: cx.theme().players().local(),
23233            text: text_style,
23234            scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23235            syntax: cx.theme().syntax().clone(),
23236            status: cx.theme().status().clone(),
23237            inlay_hints_style: make_inlay_hints_style(cx),
23238            edit_prediction_styles: make_suggestion_styles(cx),
23239            unnecessary_code_fade: settings.unnecessary_code_fade,
23240            show_underlines: self.diagnostics_enabled(),
23241        }
23242    }
23243
23244    /// Returns the value of the `vim_mode` setting, defaulting `false` if the
23245    /// setting is not set.
23246    pub(crate) fn is_vim_mode_enabled(&self, cx: &App) -> bool {
23247        VimModeSetting::try_get(cx)
23248            .map(|vim_mode| vim_mode.0)
23249            .unwrap_or(false)
23250    }
23251}
23252
23253fn edit_for_markdown_paste<'a>(
23254    buffer: &MultiBufferSnapshot,
23255    range: Range<MultiBufferOffset>,
23256    to_insert: &'a str,
23257    url: Option<url::Url>,
23258) -> (Range<MultiBufferOffset>, Cow<'a, str>) {
23259    if url.is_none() {
23260        return (range, Cow::Borrowed(to_insert));
23261    };
23262
23263    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
23264
23265    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
23266        Cow::Borrowed(to_insert)
23267    } else {
23268        Cow::Owned(format!("[{old_text}]({to_insert})"))
23269    };
23270    (range, new_text)
23271}
23272
23273fn process_completion_for_edit(
23274    completion: &Completion,
23275    intent: CompletionIntent,
23276    buffer: &Entity<Buffer>,
23277    cursor_position: &text::Anchor,
23278    cx: &mut Context<Editor>,
23279) -> CompletionEdit {
23280    let buffer = buffer.read(cx);
23281    let buffer_snapshot = buffer.snapshot();
23282    let (snippet, new_text) = if completion.is_snippet() {
23283        let mut snippet_source = completion.new_text.clone();
23284        // Workaround for typescript language server issues so that methods don't expand within
23285        // strings and functions with type expressions. The previous point is used because the query
23286        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
23287        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
23288        let previous_point = if previous_point.column > 0 {
23289            cursor_position.to_previous_offset(&buffer_snapshot)
23290        } else {
23291            cursor_position.to_offset(&buffer_snapshot)
23292        };
23293        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
23294            && scope.prefers_label_for_snippet_in_completion()
23295            && let Some(label) = completion.label()
23296            && matches!(
23297                completion.kind(),
23298                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
23299            )
23300        {
23301            snippet_source = label;
23302        }
23303        match Snippet::parse(&snippet_source).log_err() {
23304            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
23305            None => (None, completion.new_text.clone()),
23306        }
23307    } else {
23308        (None, completion.new_text.clone())
23309    };
23310
23311    let mut range_to_replace = {
23312        let replace_range = &completion.replace_range;
23313        if let CompletionSource::Lsp {
23314            insert_range: Some(insert_range),
23315            ..
23316        } = &completion.source
23317        {
23318            debug_assert_eq!(
23319                insert_range.start, replace_range.start,
23320                "insert_range and replace_range should start at the same position"
23321            );
23322            debug_assert!(
23323                insert_range
23324                    .start
23325                    .cmp(cursor_position, &buffer_snapshot)
23326                    .is_le(),
23327                "insert_range should start before or at cursor position"
23328            );
23329            debug_assert!(
23330                replace_range
23331                    .start
23332                    .cmp(cursor_position, &buffer_snapshot)
23333                    .is_le(),
23334                "replace_range should start before or at cursor position"
23335            );
23336
23337            let should_replace = match intent {
23338                CompletionIntent::CompleteWithInsert => false,
23339                CompletionIntent::CompleteWithReplace => true,
23340                CompletionIntent::Complete | CompletionIntent::Compose => {
23341                    let insert_mode =
23342                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
23343                            .completions
23344                            .lsp_insert_mode;
23345                    match insert_mode {
23346                        LspInsertMode::Insert => false,
23347                        LspInsertMode::Replace => true,
23348                        LspInsertMode::ReplaceSubsequence => {
23349                            let mut text_to_replace = buffer.chars_for_range(
23350                                buffer.anchor_before(replace_range.start)
23351                                    ..buffer.anchor_after(replace_range.end),
23352                            );
23353                            let mut current_needle = text_to_replace.next();
23354                            for haystack_ch in completion.label.text.chars() {
23355                                if let Some(needle_ch) = current_needle
23356                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
23357                                {
23358                                    current_needle = text_to_replace.next();
23359                                }
23360                            }
23361                            current_needle.is_none()
23362                        }
23363                        LspInsertMode::ReplaceSuffix => {
23364                            if replace_range
23365                                .end
23366                                .cmp(cursor_position, &buffer_snapshot)
23367                                .is_gt()
23368                            {
23369                                let range_after_cursor = *cursor_position..replace_range.end;
23370                                let text_after_cursor = buffer
23371                                    .text_for_range(
23372                                        buffer.anchor_before(range_after_cursor.start)
23373                                            ..buffer.anchor_after(range_after_cursor.end),
23374                                    )
23375                                    .collect::<String>()
23376                                    .to_ascii_lowercase();
23377                                completion
23378                                    .label
23379                                    .text
23380                                    .to_ascii_lowercase()
23381                                    .ends_with(&text_after_cursor)
23382                            } else {
23383                                true
23384                            }
23385                        }
23386                    }
23387                }
23388            };
23389
23390            if should_replace {
23391                replace_range.clone()
23392            } else {
23393                insert_range.clone()
23394            }
23395        } else {
23396            replace_range.clone()
23397        }
23398    };
23399
23400    if range_to_replace
23401        .end
23402        .cmp(cursor_position, &buffer_snapshot)
23403        .is_lt()
23404    {
23405        range_to_replace.end = *cursor_position;
23406    }
23407
23408    let replace_range = range_to_replace.to_offset(buffer);
23409    CompletionEdit {
23410        new_text,
23411        replace_range: BufferOffset(replace_range.start)..BufferOffset(replace_range.end),
23412        snippet,
23413    }
23414}
23415
23416struct CompletionEdit {
23417    new_text: String,
23418    replace_range: Range<BufferOffset>,
23419    snippet: Option<Snippet>,
23420}
23421
23422fn insert_extra_newline_brackets(
23423    buffer: &MultiBufferSnapshot,
23424    range: Range<MultiBufferOffset>,
23425    language: &language::LanguageScope,
23426) -> bool {
23427    let leading_whitespace_len = buffer
23428        .reversed_chars_at(range.start)
23429        .take_while(|c| c.is_whitespace() && *c != '\n')
23430        .map(|c| c.len_utf8())
23431        .sum::<usize>();
23432    let trailing_whitespace_len = buffer
23433        .chars_at(range.end)
23434        .take_while(|c| c.is_whitespace() && *c != '\n')
23435        .map(|c| c.len_utf8())
23436        .sum::<usize>();
23437    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
23438
23439    language.brackets().any(|(pair, enabled)| {
23440        let pair_start = pair.start.trim_end();
23441        let pair_end = pair.end.trim_start();
23442
23443        enabled
23444            && pair.newline
23445            && buffer.contains_str_at(range.end, pair_end)
23446            && buffer.contains_str_at(
23447                range.start.saturating_sub_usize(pair_start.len()),
23448                pair_start,
23449            )
23450    })
23451}
23452
23453fn insert_extra_newline_tree_sitter(
23454    buffer: &MultiBufferSnapshot,
23455    range: Range<MultiBufferOffset>,
23456) -> bool {
23457    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
23458        [(buffer, range, _)] => (*buffer, range.clone()),
23459        _ => return false,
23460    };
23461    let pair = {
23462        let mut result: Option<BracketMatch<usize>> = None;
23463
23464        for pair in buffer
23465            .all_bracket_ranges(range.start.0..range.end.0)
23466            .filter(move |pair| {
23467                pair.open_range.start <= range.start.0 && pair.close_range.end >= range.end.0
23468            })
23469        {
23470            let len = pair.close_range.end - pair.open_range.start;
23471
23472            if let Some(existing) = &result {
23473                let existing_len = existing.close_range.end - existing.open_range.start;
23474                if len > existing_len {
23475                    continue;
23476                }
23477            }
23478
23479            result = Some(pair);
23480        }
23481
23482        result
23483    };
23484    let Some(pair) = pair else {
23485        return false;
23486    };
23487    pair.newline_only
23488        && buffer
23489            .chars_for_range(pair.open_range.end..range.start.0)
23490            .chain(buffer.chars_for_range(range.end.0..pair.close_range.start))
23491            .all(|c| c.is_whitespace() && c != '\n')
23492}
23493
23494fn update_uncommitted_diff_for_buffer(
23495    editor: Entity<Editor>,
23496    project: &Entity<Project>,
23497    buffers: impl IntoIterator<Item = Entity<Buffer>>,
23498    buffer: Entity<MultiBuffer>,
23499    cx: &mut App,
23500) -> Task<()> {
23501    let mut tasks = Vec::new();
23502    project.update(cx, |project, cx| {
23503        for buffer in buffers {
23504            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
23505                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
23506            }
23507        }
23508    });
23509    cx.spawn(async move |cx| {
23510        let diffs = future::join_all(tasks).await;
23511        if editor
23512            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
23513            .unwrap_or(false)
23514        {
23515            return;
23516        }
23517
23518        buffer
23519            .update(cx, |buffer, cx| {
23520                for diff in diffs.into_iter().flatten() {
23521                    buffer.add_diff(diff, cx);
23522                }
23523            })
23524            .ok();
23525    })
23526}
23527
23528fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
23529    let tab_size = tab_size.get() as usize;
23530    let mut width = offset;
23531
23532    for ch in text.chars() {
23533        width += if ch == '\t' {
23534            tab_size - (width % tab_size)
23535        } else {
23536            1
23537        };
23538    }
23539
23540    width - offset
23541}
23542
23543#[cfg(test)]
23544mod tests {
23545    use super::*;
23546
23547    #[test]
23548    fn test_string_size_with_expanded_tabs() {
23549        let nz = |val| NonZeroU32::new(val).unwrap();
23550        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
23551        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
23552        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
23553        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
23554        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
23555        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
23556        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
23557        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
23558    }
23559}
23560
23561/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
23562struct WordBreakingTokenizer<'a> {
23563    input: &'a str,
23564}
23565
23566impl<'a> WordBreakingTokenizer<'a> {
23567    fn new(input: &'a str) -> Self {
23568        Self { input }
23569    }
23570}
23571
23572fn is_char_ideographic(ch: char) -> bool {
23573    use unicode_script::Script::*;
23574    use unicode_script::UnicodeScript;
23575    matches!(ch.script(), Han | Tangut | Yi)
23576}
23577
23578fn is_grapheme_ideographic(text: &str) -> bool {
23579    text.chars().any(is_char_ideographic)
23580}
23581
23582fn is_grapheme_whitespace(text: &str) -> bool {
23583    text.chars().any(|x| x.is_whitespace())
23584}
23585
23586fn should_stay_with_preceding_ideograph(text: &str) -> bool {
23587    text.chars()
23588        .next()
23589        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
23590}
23591
23592#[derive(PartialEq, Eq, Debug, Clone, Copy)]
23593enum WordBreakToken<'a> {
23594    Word { token: &'a str, grapheme_len: usize },
23595    InlineWhitespace { token: &'a str, grapheme_len: usize },
23596    Newline,
23597}
23598
23599impl<'a> Iterator for WordBreakingTokenizer<'a> {
23600    /// Yields a span, the count of graphemes in the token, and whether it was
23601    /// whitespace. Note that it also breaks at word boundaries.
23602    type Item = WordBreakToken<'a>;
23603
23604    fn next(&mut self) -> Option<Self::Item> {
23605        use unicode_segmentation::UnicodeSegmentation;
23606        if self.input.is_empty() {
23607            return None;
23608        }
23609
23610        let mut iter = self.input.graphemes(true).peekable();
23611        let mut offset = 0;
23612        let mut grapheme_len = 0;
23613        if let Some(first_grapheme) = iter.next() {
23614            let is_newline = first_grapheme == "\n";
23615            let is_whitespace = is_grapheme_whitespace(first_grapheme);
23616            offset += first_grapheme.len();
23617            grapheme_len += 1;
23618            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
23619                if let Some(grapheme) = iter.peek().copied()
23620                    && should_stay_with_preceding_ideograph(grapheme)
23621                {
23622                    offset += grapheme.len();
23623                    grapheme_len += 1;
23624                }
23625            } else {
23626                let mut words = self.input[offset..].split_word_bound_indices().peekable();
23627                let mut next_word_bound = words.peek().copied();
23628                if next_word_bound.is_some_and(|(i, _)| i == 0) {
23629                    next_word_bound = words.next();
23630                }
23631                while let Some(grapheme) = iter.peek().copied() {
23632                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
23633                        break;
23634                    };
23635                    if is_grapheme_whitespace(grapheme) != is_whitespace
23636                        || (grapheme == "\n") != is_newline
23637                    {
23638                        break;
23639                    };
23640                    offset += grapheme.len();
23641                    grapheme_len += 1;
23642                    iter.next();
23643                }
23644            }
23645            let token = &self.input[..offset];
23646            self.input = &self.input[offset..];
23647            if token == "\n" {
23648                Some(WordBreakToken::Newline)
23649            } else if is_whitespace {
23650                Some(WordBreakToken::InlineWhitespace {
23651                    token,
23652                    grapheme_len,
23653                })
23654            } else {
23655                Some(WordBreakToken::Word {
23656                    token,
23657                    grapheme_len,
23658                })
23659            }
23660        } else {
23661            None
23662        }
23663    }
23664}
23665
23666#[test]
23667fn test_word_breaking_tokenizer() {
23668    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
23669        ("", &[]),
23670        ("  ", &[whitespace("  ", 2)]),
23671        ("Ʒ", &[word("Ʒ", 1)]),
23672        ("Ǽ", &[word("Ǽ", 1)]),
23673        ("", &[word("", 1)]),
23674        ("⋑⋑", &[word("⋑⋑", 2)]),
23675        (
23676            "原理,进而",
23677            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
23678        ),
23679        (
23680            "hello world",
23681            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
23682        ),
23683        (
23684            "hello, world",
23685            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
23686        ),
23687        (
23688            "  hello world",
23689            &[
23690                whitespace("  ", 2),
23691                word("hello", 5),
23692                whitespace(" ", 1),
23693                word("world", 5),
23694            ],
23695        ),
23696        (
23697            "这是什么 \n 钢笔",
23698            &[
23699                word("", 1),
23700                word("", 1),
23701                word("", 1),
23702                word("", 1),
23703                whitespace(" ", 1),
23704                newline(),
23705                whitespace(" ", 1),
23706                word("", 1),
23707                word("", 1),
23708            ],
23709        ),
23710        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
23711    ];
23712
23713    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
23714        WordBreakToken::Word {
23715            token,
23716            grapheme_len,
23717        }
23718    }
23719
23720    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
23721        WordBreakToken::InlineWhitespace {
23722            token,
23723            grapheme_len,
23724        }
23725    }
23726
23727    fn newline() -> WordBreakToken<'static> {
23728        WordBreakToken::Newline
23729    }
23730
23731    for (input, result) in tests {
23732        assert_eq!(
23733            WordBreakingTokenizer::new(input)
23734                .collect::<Vec<_>>()
23735                .as_slice(),
23736            *result,
23737        );
23738    }
23739}
23740
23741fn wrap_with_prefix(
23742    first_line_prefix: String,
23743    subsequent_lines_prefix: String,
23744    unwrapped_text: String,
23745    wrap_column: usize,
23746    tab_size: NonZeroU32,
23747    preserve_existing_whitespace: bool,
23748) -> String {
23749    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
23750    let subsequent_lines_prefix_len =
23751        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
23752    let mut wrapped_text = String::new();
23753    let mut current_line = first_line_prefix;
23754    let mut is_first_line = true;
23755
23756    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
23757    let mut current_line_len = first_line_prefix_len;
23758    let mut in_whitespace = false;
23759    for token in tokenizer {
23760        let have_preceding_whitespace = in_whitespace;
23761        match token {
23762            WordBreakToken::Word {
23763                token,
23764                grapheme_len,
23765            } => {
23766                in_whitespace = false;
23767                let current_prefix_len = if is_first_line {
23768                    first_line_prefix_len
23769                } else {
23770                    subsequent_lines_prefix_len
23771                };
23772                if current_line_len + grapheme_len > wrap_column
23773                    && current_line_len != current_prefix_len
23774                {
23775                    wrapped_text.push_str(current_line.trim_end());
23776                    wrapped_text.push('\n');
23777                    is_first_line = false;
23778                    current_line = subsequent_lines_prefix.clone();
23779                    current_line_len = subsequent_lines_prefix_len;
23780                }
23781                current_line.push_str(token);
23782                current_line_len += grapheme_len;
23783            }
23784            WordBreakToken::InlineWhitespace {
23785                mut token,
23786                mut grapheme_len,
23787            } => {
23788                in_whitespace = true;
23789                if have_preceding_whitespace && !preserve_existing_whitespace {
23790                    continue;
23791                }
23792                if !preserve_existing_whitespace {
23793                    // Keep a single whitespace grapheme as-is
23794                    if let Some(first) =
23795                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
23796                    {
23797                        token = first;
23798                    } else {
23799                        token = " ";
23800                    }
23801                    grapheme_len = 1;
23802                }
23803                let current_prefix_len = if is_first_line {
23804                    first_line_prefix_len
23805                } else {
23806                    subsequent_lines_prefix_len
23807                };
23808                if current_line_len + grapheme_len > wrap_column {
23809                    wrapped_text.push_str(current_line.trim_end());
23810                    wrapped_text.push('\n');
23811                    is_first_line = false;
23812                    current_line = subsequent_lines_prefix.clone();
23813                    current_line_len = subsequent_lines_prefix_len;
23814                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
23815                    current_line.push_str(token);
23816                    current_line_len += grapheme_len;
23817                }
23818            }
23819            WordBreakToken::Newline => {
23820                in_whitespace = true;
23821                let current_prefix_len = if is_first_line {
23822                    first_line_prefix_len
23823                } else {
23824                    subsequent_lines_prefix_len
23825                };
23826                if preserve_existing_whitespace {
23827                    wrapped_text.push_str(current_line.trim_end());
23828                    wrapped_text.push('\n');
23829                    is_first_line = false;
23830                    current_line = subsequent_lines_prefix.clone();
23831                    current_line_len = subsequent_lines_prefix_len;
23832                } else if have_preceding_whitespace {
23833                    continue;
23834                } else if current_line_len + 1 > wrap_column
23835                    && current_line_len != current_prefix_len
23836                {
23837                    wrapped_text.push_str(current_line.trim_end());
23838                    wrapped_text.push('\n');
23839                    is_first_line = false;
23840                    current_line = subsequent_lines_prefix.clone();
23841                    current_line_len = subsequent_lines_prefix_len;
23842                } else if current_line_len != current_prefix_len {
23843                    current_line.push(' ');
23844                    current_line_len += 1;
23845                }
23846            }
23847        }
23848    }
23849
23850    if !current_line.is_empty() {
23851        wrapped_text.push_str(&current_line);
23852    }
23853    wrapped_text
23854}
23855
23856#[test]
23857fn test_wrap_with_prefix() {
23858    assert_eq!(
23859        wrap_with_prefix(
23860            "# ".to_string(),
23861            "# ".to_string(),
23862            "abcdefg".to_string(),
23863            4,
23864            NonZeroU32::new(4).unwrap(),
23865            false,
23866        ),
23867        "# abcdefg"
23868    );
23869    assert_eq!(
23870        wrap_with_prefix(
23871            "".to_string(),
23872            "".to_string(),
23873            "\thello world".to_string(),
23874            8,
23875            NonZeroU32::new(4).unwrap(),
23876            false,
23877        ),
23878        "hello\nworld"
23879    );
23880    assert_eq!(
23881        wrap_with_prefix(
23882            "// ".to_string(),
23883            "// ".to_string(),
23884            "xx \nyy zz aa bb cc".to_string(),
23885            12,
23886            NonZeroU32::new(4).unwrap(),
23887            false,
23888        ),
23889        "// xx yy zz\n// aa bb cc"
23890    );
23891    assert_eq!(
23892        wrap_with_prefix(
23893            String::new(),
23894            String::new(),
23895            "这是什么 \n 钢笔".to_string(),
23896            3,
23897            NonZeroU32::new(4).unwrap(),
23898            false,
23899        ),
23900        "这是什\n么 钢\n"
23901    );
23902    assert_eq!(
23903        wrap_with_prefix(
23904            String::new(),
23905            String::new(),
23906            format!("foo{}bar", '\u{2009}'), // thin space
23907            80,
23908            NonZeroU32::new(4).unwrap(),
23909            false,
23910        ),
23911        format!("foo{}bar", '\u{2009}')
23912    );
23913}
23914
23915pub trait CollaborationHub {
23916    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
23917    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
23918    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
23919}
23920
23921impl CollaborationHub for Entity<Project> {
23922    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
23923        self.read(cx).collaborators()
23924    }
23925
23926    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
23927        self.read(cx).user_store().read(cx).participant_indices()
23928    }
23929
23930    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
23931        let this = self.read(cx);
23932        let user_ids = this.collaborators().values().map(|c| c.user_id);
23933        this.user_store().read(cx).participant_names(user_ids, cx)
23934    }
23935}
23936
23937pub trait SemanticsProvider {
23938    fn hover(
23939        &self,
23940        buffer: &Entity<Buffer>,
23941        position: text::Anchor,
23942        cx: &mut App,
23943    ) -> Option<Task<Option<Vec<project::Hover>>>>;
23944
23945    fn inline_values(
23946        &self,
23947        buffer_handle: Entity<Buffer>,
23948        range: Range<text::Anchor>,
23949        cx: &mut App,
23950    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
23951
23952    fn applicable_inlay_chunks(
23953        &self,
23954        buffer: &Entity<Buffer>,
23955        ranges: &[Range<text::Anchor>],
23956        cx: &mut App,
23957    ) -> Vec<Range<BufferRow>>;
23958
23959    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
23960
23961    fn inlay_hints(
23962        &self,
23963        invalidate: InvalidationStrategy,
23964        buffer: Entity<Buffer>,
23965        ranges: Vec<Range<text::Anchor>>,
23966        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
23967        cx: &mut App,
23968    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
23969
23970    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
23971
23972    fn document_highlights(
23973        &self,
23974        buffer: &Entity<Buffer>,
23975        position: text::Anchor,
23976        cx: &mut App,
23977    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
23978
23979    fn definitions(
23980        &self,
23981        buffer: &Entity<Buffer>,
23982        position: text::Anchor,
23983        kind: GotoDefinitionKind,
23984        cx: &mut App,
23985    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
23986
23987    fn range_for_rename(
23988        &self,
23989        buffer: &Entity<Buffer>,
23990        position: text::Anchor,
23991        cx: &mut App,
23992    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
23993
23994    fn perform_rename(
23995        &self,
23996        buffer: &Entity<Buffer>,
23997        position: text::Anchor,
23998        new_name: String,
23999        cx: &mut App,
24000    ) -> Option<Task<Result<ProjectTransaction>>>;
24001}
24002
24003pub trait CompletionProvider {
24004    fn completions(
24005        &self,
24006        excerpt_id: ExcerptId,
24007        buffer: &Entity<Buffer>,
24008        buffer_position: text::Anchor,
24009        trigger: CompletionContext,
24010        window: &mut Window,
24011        cx: &mut Context<Editor>,
24012    ) -> Task<Result<Vec<CompletionResponse>>>;
24013
24014    fn resolve_completions(
24015        &self,
24016        _buffer: Entity<Buffer>,
24017        _completion_indices: Vec<usize>,
24018        _completions: Rc<RefCell<Box<[Completion]>>>,
24019        _cx: &mut Context<Editor>,
24020    ) -> Task<Result<bool>> {
24021        Task::ready(Ok(false))
24022    }
24023
24024    fn apply_additional_edits_for_completion(
24025        &self,
24026        _buffer: Entity<Buffer>,
24027        _completions: Rc<RefCell<Box<[Completion]>>>,
24028        _completion_index: usize,
24029        _push_to_history: bool,
24030        _cx: &mut Context<Editor>,
24031    ) -> Task<Result<Option<language::Transaction>>> {
24032        Task::ready(Ok(None))
24033    }
24034
24035    fn is_completion_trigger(
24036        &self,
24037        buffer: &Entity<Buffer>,
24038        position: language::Anchor,
24039        text: &str,
24040        trigger_in_words: bool,
24041        cx: &mut Context<Editor>,
24042    ) -> bool;
24043
24044    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
24045
24046    fn sort_completions(&self) -> bool {
24047        true
24048    }
24049
24050    fn filter_completions(&self) -> bool {
24051        true
24052    }
24053
24054    fn show_snippets(&self) -> bool {
24055        false
24056    }
24057}
24058
24059pub trait CodeActionProvider {
24060    fn id(&self) -> Arc<str>;
24061
24062    fn code_actions(
24063        &self,
24064        buffer: &Entity<Buffer>,
24065        range: Range<text::Anchor>,
24066        window: &mut Window,
24067        cx: &mut App,
24068    ) -> Task<Result<Vec<CodeAction>>>;
24069
24070    fn apply_code_action(
24071        &self,
24072        buffer_handle: Entity<Buffer>,
24073        action: CodeAction,
24074        excerpt_id: ExcerptId,
24075        push_to_history: bool,
24076        window: &mut Window,
24077        cx: &mut App,
24078    ) -> Task<Result<ProjectTransaction>>;
24079}
24080
24081impl CodeActionProvider for Entity<Project> {
24082    fn id(&self) -> Arc<str> {
24083        "project".into()
24084    }
24085
24086    fn code_actions(
24087        &self,
24088        buffer: &Entity<Buffer>,
24089        range: Range<text::Anchor>,
24090        _window: &mut Window,
24091        cx: &mut App,
24092    ) -> Task<Result<Vec<CodeAction>>> {
24093        self.update(cx, |project, cx| {
24094            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
24095            let code_actions = project.code_actions(buffer, range, None, cx);
24096            cx.background_spawn(async move {
24097                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
24098                Ok(code_lens_actions
24099                    .context("code lens fetch")?
24100                    .into_iter()
24101                    .flatten()
24102                    .chain(
24103                        code_actions
24104                            .context("code action fetch")?
24105                            .into_iter()
24106                            .flatten(),
24107                    )
24108                    .collect())
24109            })
24110        })
24111    }
24112
24113    fn apply_code_action(
24114        &self,
24115        buffer_handle: Entity<Buffer>,
24116        action: CodeAction,
24117        _excerpt_id: ExcerptId,
24118        push_to_history: bool,
24119        _window: &mut Window,
24120        cx: &mut App,
24121    ) -> Task<Result<ProjectTransaction>> {
24122        self.update(cx, |project, cx| {
24123            project.apply_code_action(buffer_handle, action, push_to_history, cx)
24124        })
24125    }
24126}
24127
24128fn snippet_completions(
24129    project: &Project,
24130    buffer: &Entity<Buffer>,
24131    buffer_anchor: text::Anchor,
24132    classifier: CharClassifier,
24133    cx: &mut App,
24134) -> Task<Result<CompletionResponse>> {
24135    let languages = buffer.read(cx).languages_at(buffer_anchor);
24136    let snippet_store = project.snippets().read(cx);
24137
24138    let scopes: Vec<_> = languages
24139        .iter()
24140        .filter_map(|language| {
24141            let language_name = language.lsp_id();
24142            let snippets = snippet_store.snippets_for(Some(language_name), cx);
24143
24144            if snippets.is_empty() {
24145                None
24146            } else {
24147                Some((language.default_scope(), snippets))
24148            }
24149        })
24150        .collect();
24151
24152    if scopes.is_empty() {
24153        return Task::ready(Ok(CompletionResponse {
24154            completions: vec![],
24155            display_options: CompletionDisplayOptions::default(),
24156            is_incomplete: false,
24157        }));
24158    }
24159
24160    let snapshot = buffer.read(cx).text_snapshot();
24161    let executor = cx.background_executor().clone();
24162
24163    cx.background_spawn(async move {
24164        let is_word_char = |c| classifier.is_word(c);
24165
24166        let mut is_incomplete = false;
24167        let mut completions: Vec<Completion> = Vec::new();
24168
24169        const MAX_PREFIX_LEN: usize = 128;
24170        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
24171        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
24172        let window_start = snapshot.clip_offset(window_start, Bias::Left);
24173
24174        let max_buffer_window: String = snapshot
24175            .text_for_range(window_start..buffer_offset)
24176            .collect();
24177
24178        if max_buffer_window.is_empty() {
24179            return Ok(CompletionResponse {
24180                completions: vec![],
24181                display_options: CompletionDisplayOptions::default(),
24182                is_incomplete: true,
24183            });
24184        }
24185
24186        for (_scope, snippets) in scopes.into_iter() {
24187            // Sort snippets by word count to match longer snippet prefixes first.
24188            let mut sorted_snippet_candidates = snippets
24189                .iter()
24190                .enumerate()
24191                .flat_map(|(snippet_ix, snippet)| {
24192                    snippet
24193                        .prefix
24194                        .iter()
24195                        .enumerate()
24196                        .map(move |(prefix_ix, prefix)| {
24197                            let word_count =
24198                                snippet_candidate_suffixes(prefix, is_word_char).count();
24199                            ((snippet_ix, prefix_ix), prefix, word_count)
24200                        })
24201                })
24202                .collect_vec();
24203            sorted_snippet_candidates
24204                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
24205
24206            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
24207
24208            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, is_word_char)
24209                .take(
24210                    sorted_snippet_candidates
24211                        .first()
24212                        .map(|(_, _, word_count)| *word_count)
24213                        .unwrap_or_default(),
24214                )
24215                .collect_vec();
24216
24217            const MAX_RESULTS: usize = 100;
24218            // Each match also remembers how many characters from the buffer it consumed
24219            let mut matches: Vec<(StringMatch, usize)> = vec![];
24220
24221            let mut snippet_list_cutoff_index = 0;
24222            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
24223                let word_count = buffer_index + 1;
24224                // Increase `snippet_list_cutoff_index` until we have all of the
24225                // snippets with sufficiently many words.
24226                while sorted_snippet_candidates
24227                    .get(snippet_list_cutoff_index)
24228                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
24229                        *snippet_word_count >= word_count
24230                    })
24231                {
24232                    snippet_list_cutoff_index += 1;
24233                }
24234
24235                // Take only the candidates with at least `word_count` many words
24236                let snippet_candidates_at_word_len =
24237                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
24238
24239                let candidates = snippet_candidates_at_word_len
24240                    .iter()
24241                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
24242                    .enumerate() // index in `sorted_snippet_candidates`
24243                    // First char must match
24244                    .filter(|(_ix, prefix)| {
24245                        itertools::equal(
24246                            prefix
24247                                .chars()
24248                                .next()
24249                                .into_iter()
24250                                .flat_map(|c| c.to_lowercase()),
24251                            buffer_window
24252                                .chars()
24253                                .next()
24254                                .into_iter()
24255                                .flat_map(|c| c.to_lowercase()),
24256                        )
24257                    })
24258                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
24259                    .collect::<Vec<StringMatchCandidate>>();
24260
24261                matches.extend(
24262                    fuzzy::match_strings(
24263                        &candidates,
24264                        &buffer_window,
24265                        buffer_window.chars().any(|c| c.is_uppercase()),
24266                        true,
24267                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
24268                        &Default::default(),
24269                        executor.clone(),
24270                    )
24271                    .await
24272                    .into_iter()
24273                    .map(|string_match| (string_match, buffer_window.len())),
24274                );
24275
24276                if matches.len() >= MAX_RESULTS {
24277                    break;
24278                }
24279            }
24280
24281            let to_lsp = |point: &text::Anchor| {
24282                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
24283                point_to_lsp(end)
24284            };
24285            let lsp_end = to_lsp(&buffer_anchor);
24286
24287            if matches.len() >= MAX_RESULTS {
24288                is_incomplete = true;
24289            }
24290
24291            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
24292                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
24293                    sorted_snippet_candidates[string_match.candidate_id];
24294                let snippet = &snippets[snippet_index];
24295                let start = buffer_offset - buffer_window_len;
24296                let start = snapshot.anchor_before(start);
24297                let range = start..buffer_anchor;
24298                let lsp_start = to_lsp(&start);
24299                let lsp_range = lsp::Range {
24300                    start: lsp_start,
24301                    end: lsp_end,
24302                };
24303                Completion {
24304                    replace_range: range,
24305                    new_text: snippet.body.clone(),
24306                    source: CompletionSource::Lsp {
24307                        insert_range: None,
24308                        server_id: LanguageServerId(usize::MAX),
24309                        resolved: true,
24310                        lsp_completion: Box::new(lsp::CompletionItem {
24311                            label: snippet.prefix.first().unwrap().clone(),
24312                            kind: Some(CompletionItemKind::SNIPPET),
24313                            label_details: snippet.description.as_ref().map(|description| {
24314                                lsp::CompletionItemLabelDetails {
24315                                    detail: Some(description.clone()),
24316                                    description: None,
24317                                }
24318                            }),
24319                            insert_text_format: Some(InsertTextFormat::SNIPPET),
24320                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
24321                                lsp::InsertReplaceEdit {
24322                                    new_text: snippet.body.clone(),
24323                                    insert: lsp_range,
24324                                    replace: lsp_range,
24325                                },
24326                            )),
24327                            filter_text: Some(snippet.body.clone()),
24328                            sort_text: Some(char::MAX.to_string()),
24329                            ..lsp::CompletionItem::default()
24330                        }),
24331                        lsp_defaults: None,
24332                    },
24333                    label: CodeLabel {
24334                        text: matching_prefix.clone(),
24335                        runs: Vec::new(),
24336                        filter_range: 0..matching_prefix.len(),
24337                    },
24338                    icon_path: None,
24339                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
24340                        single_line: snippet.name.clone().into(),
24341                        plain_text: snippet
24342                            .description
24343                            .clone()
24344                            .map(|description| description.into()),
24345                    }),
24346                    insert_text_mode: None,
24347                    confirm: None,
24348                    match_start: Some(start),
24349                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
24350                }
24351            }));
24352        }
24353
24354        Ok(CompletionResponse {
24355            completions,
24356            display_options: CompletionDisplayOptions::default(),
24357            is_incomplete,
24358        })
24359    })
24360}
24361
24362impl CompletionProvider for Entity<Project> {
24363    fn completions(
24364        &self,
24365        _excerpt_id: ExcerptId,
24366        buffer: &Entity<Buffer>,
24367        buffer_position: text::Anchor,
24368        options: CompletionContext,
24369        _window: &mut Window,
24370        cx: &mut Context<Editor>,
24371    ) -> Task<Result<Vec<CompletionResponse>>> {
24372        self.update(cx, |project, cx| {
24373            let task = project.completions(buffer, buffer_position, options, cx);
24374            cx.background_spawn(task)
24375        })
24376    }
24377
24378    fn resolve_completions(
24379        &self,
24380        buffer: Entity<Buffer>,
24381        completion_indices: Vec<usize>,
24382        completions: Rc<RefCell<Box<[Completion]>>>,
24383        cx: &mut Context<Editor>,
24384    ) -> Task<Result<bool>> {
24385        self.update(cx, |project, cx| {
24386            project.lsp_store().update(cx, |lsp_store, cx| {
24387                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
24388            })
24389        })
24390    }
24391
24392    fn apply_additional_edits_for_completion(
24393        &self,
24394        buffer: Entity<Buffer>,
24395        completions: Rc<RefCell<Box<[Completion]>>>,
24396        completion_index: usize,
24397        push_to_history: bool,
24398        cx: &mut Context<Editor>,
24399    ) -> Task<Result<Option<language::Transaction>>> {
24400        self.update(cx, |project, cx| {
24401            project.lsp_store().update(cx, |lsp_store, cx| {
24402                lsp_store.apply_additional_edits_for_completion(
24403                    buffer,
24404                    completions,
24405                    completion_index,
24406                    push_to_history,
24407                    cx,
24408                )
24409            })
24410        })
24411    }
24412
24413    fn is_completion_trigger(
24414        &self,
24415        buffer: &Entity<Buffer>,
24416        position: language::Anchor,
24417        text: &str,
24418        trigger_in_words: bool,
24419        cx: &mut Context<Editor>,
24420    ) -> bool {
24421        let mut chars = text.chars();
24422        let char = if let Some(char) = chars.next() {
24423            char
24424        } else {
24425            return false;
24426        };
24427        if chars.next().is_some() {
24428            return false;
24429        }
24430
24431        let buffer = buffer.read(cx);
24432        let snapshot = buffer.snapshot();
24433        let classifier = snapshot
24434            .char_classifier_at(position)
24435            .scope_context(Some(CharScopeContext::Completion));
24436        if trigger_in_words && classifier.is_word(char) {
24437            return true;
24438        }
24439
24440        buffer.completion_triggers().contains(text)
24441    }
24442
24443    fn show_snippets(&self) -> bool {
24444        true
24445    }
24446}
24447
24448impl SemanticsProvider for Entity<Project> {
24449    fn hover(
24450        &self,
24451        buffer: &Entity<Buffer>,
24452        position: text::Anchor,
24453        cx: &mut App,
24454    ) -> Option<Task<Option<Vec<project::Hover>>>> {
24455        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
24456    }
24457
24458    fn document_highlights(
24459        &self,
24460        buffer: &Entity<Buffer>,
24461        position: text::Anchor,
24462        cx: &mut App,
24463    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
24464        Some(self.update(cx, |project, cx| {
24465            project.document_highlights(buffer, position, cx)
24466        }))
24467    }
24468
24469    fn definitions(
24470        &self,
24471        buffer: &Entity<Buffer>,
24472        position: text::Anchor,
24473        kind: GotoDefinitionKind,
24474        cx: &mut App,
24475    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
24476        Some(self.update(cx, |project, cx| match kind {
24477            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
24478            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
24479            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
24480            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
24481        }))
24482    }
24483
24484    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
24485        self.update(cx, |project, cx| {
24486            if project
24487                .active_debug_session(cx)
24488                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
24489            {
24490                return true;
24491            }
24492
24493            buffer.update(cx, |buffer, cx| {
24494                project.any_language_server_supports_inlay_hints(buffer, cx)
24495            })
24496        })
24497    }
24498
24499    fn inline_values(
24500        &self,
24501        buffer_handle: Entity<Buffer>,
24502        range: Range<text::Anchor>,
24503        cx: &mut App,
24504    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
24505        self.update(cx, |project, cx| {
24506            let (session, active_stack_frame) = project.active_debug_session(cx)?;
24507
24508            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
24509        })
24510    }
24511
24512    fn applicable_inlay_chunks(
24513        &self,
24514        buffer: &Entity<Buffer>,
24515        ranges: &[Range<text::Anchor>],
24516        cx: &mut App,
24517    ) -> Vec<Range<BufferRow>> {
24518        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
24519            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
24520        })
24521    }
24522
24523    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
24524        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
24525            lsp_store.invalidate_inlay_hints(for_buffers)
24526        });
24527    }
24528
24529    fn inlay_hints(
24530        &self,
24531        invalidate: InvalidationStrategy,
24532        buffer: Entity<Buffer>,
24533        ranges: Vec<Range<text::Anchor>>,
24534        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
24535        cx: &mut App,
24536    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
24537        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
24538            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
24539        }))
24540    }
24541
24542    fn range_for_rename(
24543        &self,
24544        buffer: &Entity<Buffer>,
24545        position: text::Anchor,
24546        cx: &mut App,
24547    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
24548        Some(self.update(cx, |project, cx| {
24549            let buffer = buffer.clone();
24550            let task = project.prepare_rename(buffer.clone(), position, cx);
24551            cx.spawn(async move |_, cx| {
24552                Ok(match task.await? {
24553                    PrepareRenameResponse::Success(range) => Some(range),
24554                    PrepareRenameResponse::InvalidPosition => None,
24555                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
24556                        // Fallback on using TreeSitter info to determine identifier range
24557                        buffer.read_with(cx, |buffer, _| {
24558                            let snapshot = buffer.snapshot();
24559                            let (range, kind) = snapshot.surrounding_word(position, None);
24560                            if kind != Some(CharKind::Word) {
24561                                return None;
24562                            }
24563                            Some(
24564                                snapshot.anchor_before(range.start)
24565                                    ..snapshot.anchor_after(range.end),
24566                            )
24567                        })?
24568                    }
24569                })
24570            })
24571        }))
24572    }
24573
24574    fn perform_rename(
24575        &self,
24576        buffer: &Entity<Buffer>,
24577        position: text::Anchor,
24578        new_name: String,
24579        cx: &mut App,
24580    ) -> Option<Task<Result<ProjectTransaction>>> {
24581        Some(self.update(cx, |project, cx| {
24582            project.perform_rename(buffer.clone(), position, new_name, cx)
24583        }))
24584    }
24585}
24586
24587fn consume_contiguous_rows(
24588    contiguous_row_selections: &mut Vec<Selection<Point>>,
24589    selection: &Selection<Point>,
24590    display_map: &DisplaySnapshot,
24591    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
24592) -> (MultiBufferRow, MultiBufferRow) {
24593    contiguous_row_selections.push(selection.clone());
24594    let start_row = starting_row(selection, display_map);
24595    let mut end_row = ending_row(selection, display_map);
24596
24597    while let Some(next_selection) = selections.peek() {
24598        if next_selection.start.row <= end_row.0 {
24599            end_row = ending_row(next_selection, display_map);
24600            contiguous_row_selections.push(selections.next().unwrap().clone());
24601        } else {
24602            break;
24603        }
24604    }
24605    (start_row, end_row)
24606}
24607
24608fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
24609    if selection.start.column > 0 {
24610        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
24611    } else {
24612        MultiBufferRow(selection.start.row)
24613    }
24614}
24615
24616fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
24617    if next_selection.end.column > 0 || next_selection.is_empty() {
24618        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
24619    } else {
24620        MultiBufferRow(next_selection.end.row)
24621    }
24622}
24623
24624impl EditorSnapshot {
24625    pub fn remote_selections_in_range<'a>(
24626        &'a self,
24627        range: &'a Range<Anchor>,
24628        collaboration_hub: &dyn CollaborationHub,
24629        cx: &'a App,
24630    ) -> impl 'a + Iterator<Item = RemoteSelection> {
24631        let participant_names = collaboration_hub.user_names(cx);
24632        let participant_indices = collaboration_hub.user_participant_indices(cx);
24633        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
24634        let collaborators_by_replica_id = collaborators_by_peer_id
24635            .values()
24636            .map(|collaborator| (collaborator.replica_id, collaborator))
24637            .collect::<HashMap<_, _>>();
24638        self.buffer_snapshot()
24639            .selections_in_range(range, false)
24640            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
24641                if replica_id == ReplicaId::AGENT {
24642                    Some(RemoteSelection {
24643                        replica_id,
24644                        selection,
24645                        cursor_shape,
24646                        line_mode,
24647                        collaborator_id: CollaboratorId::Agent,
24648                        user_name: Some("Agent".into()),
24649                        color: cx.theme().players().agent(),
24650                    })
24651                } else {
24652                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
24653                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
24654                    let user_name = participant_names.get(&collaborator.user_id).cloned();
24655                    Some(RemoteSelection {
24656                        replica_id,
24657                        selection,
24658                        cursor_shape,
24659                        line_mode,
24660                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
24661                        user_name,
24662                        color: if let Some(index) = participant_index {
24663                            cx.theme().players().color_for_participant(index.0)
24664                        } else {
24665                            cx.theme().players().absent()
24666                        },
24667                    })
24668                }
24669            })
24670    }
24671
24672    pub fn hunks_for_ranges(
24673        &self,
24674        ranges: impl IntoIterator<Item = Range<Point>>,
24675    ) -> Vec<MultiBufferDiffHunk> {
24676        let mut hunks = Vec::new();
24677        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
24678            HashMap::default();
24679        for query_range in ranges {
24680            let query_rows =
24681                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
24682            for hunk in self.buffer_snapshot().diff_hunks_in_range(
24683                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
24684            ) {
24685                // Include deleted hunks that are adjacent to the query range, because
24686                // otherwise they would be missed.
24687                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
24688                if hunk.status().is_deleted() {
24689                    intersects_range |= hunk.row_range.start == query_rows.end;
24690                    intersects_range |= hunk.row_range.end == query_rows.start;
24691                }
24692                if intersects_range {
24693                    if !processed_buffer_rows
24694                        .entry(hunk.buffer_id)
24695                        .or_default()
24696                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
24697                    {
24698                        continue;
24699                    }
24700                    hunks.push(hunk);
24701                }
24702            }
24703        }
24704
24705        hunks
24706    }
24707
24708    fn display_diff_hunks_for_rows<'a>(
24709        &'a self,
24710        display_rows: Range<DisplayRow>,
24711        folded_buffers: &'a HashSet<BufferId>,
24712    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
24713        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
24714        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
24715
24716        self.buffer_snapshot()
24717            .diff_hunks_in_range(buffer_start..buffer_end)
24718            .filter_map(|hunk| {
24719                if folded_buffers.contains(&hunk.buffer_id) {
24720                    return None;
24721                }
24722
24723                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
24724                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
24725
24726                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
24727                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
24728
24729                let display_hunk = if hunk_display_start.column() != 0 {
24730                    DisplayDiffHunk::Folded {
24731                        display_row: hunk_display_start.row(),
24732                    }
24733                } else {
24734                    let mut end_row = hunk_display_end.row();
24735                    if hunk_display_end.column() > 0 {
24736                        end_row.0 += 1;
24737                    }
24738                    let is_created_file = hunk.is_created_file();
24739
24740                    DisplayDiffHunk::Unfolded {
24741                        status: hunk.status(),
24742                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
24743                            ..hunk.diff_base_byte_range.end.0,
24744                        word_diffs: hunk.word_diffs,
24745                        display_row_range: hunk_display_start.row()..end_row,
24746                        multi_buffer_range: Anchor::range_in_buffer(
24747                            hunk.excerpt_id,
24748                            hunk.buffer_range,
24749                        ),
24750                        is_created_file,
24751                    }
24752                };
24753
24754                Some(display_hunk)
24755            })
24756    }
24757
24758    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
24759        self.display_snapshot
24760            .buffer_snapshot()
24761            .language_at(position)
24762    }
24763
24764    pub fn is_focused(&self) -> bool {
24765        self.is_focused
24766    }
24767
24768    pub fn placeholder_text(&self) -> Option<String> {
24769        self.placeholder_display_snapshot
24770            .as_ref()
24771            .map(|display_map| display_map.text())
24772    }
24773
24774    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
24775        self.scroll_anchor.scroll_position(&self.display_snapshot)
24776    }
24777
24778    pub fn gutter_dimensions(
24779        &self,
24780        font_id: FontId,
24781        font_size: Pixels,
24782        style: &EditorStyle,
24783        window: &mut Window,
24784        cx: &App,
24785    ) -> GutterDimensions {
24786        if self.show_gutter
24787            && let Some(ch_width) = cx.text_system().ch_width(font_id, font_size).log_err()
24788            && let Some(ch_advance) = cx.text_system().ch_advance(font_id, font_size).log_err()
24789        {
24790            let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
24791                matches!(
24792                    ProjectSettings::get_global(cx).git.git_gutter,
24793                    GitGutterSetting::TrackedFiles
24794                )
24795            });
24796            let gutter_settings = EditorSettings::get_global(cx).gutter;
24797            let show_line_numbers = self
24798                .show_line_numbers
24799                .unwrap_or(gutter_settings.line_numbers);
24800            let line_gutter_width = if show_line_numbers {
24801                // Avoid flicker-like gutter resizes when the line number gains another digit by
24802                // only resizing the gutter on files with > 10**min_line_number_digits lines.
24803                let min_width_for_number_on_gutter =
24804                    ch_advance * gutter_settings.min_line_number_digits as f32;
24805                self.max_line_number_width(style, window)
24806                    .max(min_width_for_number_on_gutter)
24807            } else {
24808                0.0.into()
24809            };
24810
24811            let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
24812            let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
24813
24814            let git_blame_entries_width =
24815                self.git_blame_gutter_max_author_length
24816                    .map(|max_author_length| {
24817                        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
24818                        const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
24819
24820                        /// The number of characters to dedicate to gaps and margins.
24821                        const SPACING_WIDTH: usize = 4;
24822
24823                        let max_char_count = max_author_length.min(renderer.max_author_length())
24824                            + ::git::SHORT_SHA_LENGTH
24825                            + MAX_RELATIVE_TIMESTAMP.len()
24826                            + SPACING_WIDTH;
24827
24828                        ch_advance * max_char_count
24829                    });
24830
24831            let is_singleton = self.buffer_snapshot().is_singleton();
24832
24833            let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
24834            left_padding += if !is_singleton {
24835                ch_width * 4.0
24836            } else if show_runnables || show_breakpoints {
24837                ch_width * 3.0
24838            } else if show_git_gutter && show_line_numbers {
24839                ch_width * 2.0
24840            } else if show_git_gutter || show_line_numbers {
24841                ch_width
24842            } else {
24843                px(0.)
24844            };
24845
24846            let shows_folds = is_singleton && gutter_settings.folds;
24847
24848            let right_padding = if shows_folds && show_line_numbers {
24849                ch_width * 4.0
24850            } else if shows_folds || (!is_singleton && show_line_numbers) {
24851                ch_width * 3.0
24852            } else if show_line_numbers {
24853                ch_width
24854            } else {
24855                px(0.)
24856            };
24857
24858            GutterDimensions {
24859                left_padding,
24860                right_padding,
24861                width: line_gutter_width + left_padding + right_padding,
24862                margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
24863                git_blame_entries_width,
24864            }
24865        } else if self.offset_content {
24866            GutterDimensions::default_with_margin(font_id, font_size, cx)
24867        } else {
24868            GutterDimensions::default()
24869        }
24870    }
24871
24872    pub fn render_crease_toggle(
24873        &self,
24874        buffer_row: MultiBufferRow,
24875        row_contains_cursor: bool,
24876        editor: Entity<Editor>,
24877        window: &mut Window,
24878        cx: &mut App,
24879    ) -> Option<AnyElement> {
24880        let folded = self.is_line_folded(buffer_row);
24881        let mut is_foldable = false;
24882
24883        if let Some(crease) = self
24884            .crease_snapshot
24885            .query_row(buffer_row, self.buffer_snapshot())
24886        {
24887            is_foldable = true;
24888            match crease {
24889                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
24890                    if let Some(render_toggle) = render_toggle {
24891                        let toggle_callback =
24892                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
24893                                if folded {
24894                                    editor.update(cx, |editor, cx| {
24895                                        editor.fold_at(buffer_row, window, cx)
24896                                    });
24897                                } else {
24898                                    editor.update(cx, |editor, cx| {
24899                                        editor.unfold_at(buffer_row, window, cx)
24900                                    });
24901                                }
24902                            });
24903                        return Some((render_toggle)(
24904                            buffer_row,
24905                            folded,
24906                            toggle_callback,
24907                            window,
24908                            cx,
24909                        ));
24910                    }
24911                }
24912            }
24913        }
24914
24915        is_foldable |= self.starts_indent(buffer_row);
24916
24917        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
24918            Some(
24919                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
24920                    .toggle_state(folded)
24921                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
24922                        if folded {
24923                            this.unfold_at(buffer_row, window, cx);
24924                        } else {
24925                            this.fold_at(buffer_row, window, cx);
24926                        }
24927                    }))
24928                    .into_any_element(),
24929            )
24930        } else {
24931            None
24932        }
24933    }
24934
24935    pub fn render_crease_trailer(
24936        &self,
24937        buffer_row: MultiBufferRow,
24938        window: &mut Window,
24939        cx: &mut App,
24940    ) -> Option<AnyElement> {
24941        let folded = self.is_line_folded(buffer_row);
24942        if let Crease::Inline { render_trailer, .. } = self
24943            .crease_snapshot
24944            .query_row(buffer_row, self.buffer_snapshot())?
24945        {
24946            let render_trailer = render_trailer.as_ref()?;
24947            Some(render_trailer(buffer_row, folded, window, cx))
24948        } else {
24949            None
24950        }
24951    }
24952
24953    pub fn max_line_number_width(&self, style: &EditorStyle, window: &mut Window) -> Pixels {
24954        let digit_count = self.widest_line_number().ilog10() + 1;
24955        column_pixels(style, digit_count as usize, window)
24956    }
24957}
24958
24959pub fn column_pixels(style: &EditorStyle, column: usize, window: &Window) -> Pixels {
24960    let font_size = style.text.font_size.to_pixels(window.rem_size());
24961    let layout = window.text_system().shape_line(
24962        SharedString::from(" ".repeat(column)),
24963        font_size,
24964        &[TextRun {
24965            len: column,
24966            font: style.text.font(),
24967            color: Hsla::default(),
24968            ..Default::default()
24969        }],
24970        None,
24971    );
24972
24973    layout.width
24974}
24975
24976impl Deref for EditorSnapshot {
24977    type Target = DisplaySnapshot;
24978
24979    fn deref(&self) -> &Self::Target {
24980        &self.display_snapshot
24981    }
24982}
24983
24984#[derive(Clone, Debug, PartialEq, Eq)]
24985pub enum EditorEvent {
24986    InputIgnored {
24987        text: Arc<str>,
24988    },
24989    InputHandled {
24990        utf16_range_to_replace: Option<Range<isize>>,
24991        text: Arc<str>,
24992    },
24993    ExcerptsAdded {
24994        buffer: Entity<Buffer>,
24995        predecessor: ExcerptId,
24996        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
24997    },
24998    ExcerptsRemoved {
24999        ids: Vec<ExcerptId>,
25000        removed_buffer_ids: Vec<BufferId>,
25001    },
25002    BufferFoldToggled {
25003        ids: Vec<ExcerptId>,
25004        folded: bool,
25005    },
25006    ExcerptsEdited {
25007        ids: Vec<ExcerptId>,
25008    },
25009    ExcerptsExpanded {
25010        ids: Vec<ExcerptId>,
25011    },
25012    BufferEdited,
25013    Edited {
25014        transaction_id: clock::Lamport,
25015    },
25016    Reparsed(BufferId),
25017    Focused,
25018    FocusedIn,
25019    Blurred,
25020    DirtyChanged,
25021    Saved,
25022    TitleChanged,
25023    SelectionsChanged {
25024        local: bool,
25025    },
25026    ScrollPositionChanged {
25027        local: bool,
25028        autoscroll: bool,
25029    },
25030    TransactionUndone {
25031        transaction_id: clock::Lamport,
25032    },
25033    TransactionBegun {
25034        transaction_id: clock::Lamport,
25035    },
25036    CursorShapeChanged,
25037    BreadcrumbsChanged,
25038    PushedToNavHistory {
25039        anchor: Anchor,
25040        is_deactivate: bool,
25041    },
25042}
25043
25044impl EventEmitter<EditorEvent> for Editor {}
25045
25046impl Focusable for Editor {
25047    fn focus_handle(&self, _cx: &App) -> FocusHandle {
25048        self.focus_handle.clone()
25049    }
25050}
25051
25052impl Render for Editor {
25053    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25054        EditorElement::new(&cx.entity(), self.create_style(cx))
25055    }
25056}
25057
25058impl EntityInputHandler for Editor {
25059    fn text_for_range(
25060        &mut self,
25061        range_utf16: Range<usize>,
25062        adjusted_range: &mut Option<Range<usize>>,
25063        _: &mut Window,
25064        cx: &mut Context<Self>,
25065    ) -> Option<String> {
25066        let snapshot = self.buffer.read(cx).read(cx);
25067        let start = snapshot.clip_offset_utf16(
25068            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)),
25069            Bias::Left,
25070        );
25071        let end = snapshot.clip_offset_utf16(
25072            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end)),
25073            Bias::Right,
25074        );
25075        if (start.0.0..end.0.0) != range_utf16 {
25076            adjusted_range.replace(start.0.0..end.0.0);
25077        }
25078        Some(snapshot.text_for_range(start..end).collect())
25079    }
25080
25081    fn selected_text_range(
25082        &mut self,
25083        ignore_disabled_input: bool,
25084        _: &mut Window,
25085        cx: &mut Context<Self>,
25086    ) -> Option<UTF16Selection> {
25087        // Prevent the IME menu from appearing when holding down an alphabetic key
25088        // while input is disabled.
25089        if !ignore_disabled_input && !self.input_enabled {
25090            return None;
25091        }
25092
25093        let selection = self
25094            .selections
25095            .newest::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
25096        let range = selection.range();
25097
25098        Some(UTF16Selection {
25099            range: range.start.0.0..range.end.0.0,
25100            reversed: selection.reversed,
25101        })
25102    }
25103
25104    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
25105        let snapshot = self.buffer.read(cx).read(cx);
25106        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
25107        Some(range.start.to_offset_utf16(&snapshot).0.0..range.end.to_offset_utf16(&snapshot).0.0)
25108    }
25109
25110    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
25111        self.clear_highlights::<InputComposition>(cx);
25112        self.ime_transaction.take();
25113    }
25114
25115    fn replace_text_in_range(
25116        &mut self,
25117        range_utf16: Option<Range<usize>>,
25118        text: &str,
25119        window: &mut Window,
25120        cx: &mut Context<Self>,
25121    ) {
25122        if !self.input_enabled {
25123            cx.emit(EditorEvent::InputIgnored { text: text.into() });
25124            return;
25125        }
25126
25127        self.transact(window, cx, |this, window, cx| {
25128            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
25129                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
25130                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
25131                Some(this.selection_replacement_ranges(range_utf16, cx))
25132            } else {
25133                this.marked_text_ranges(cx)
25134            };
25135
25136            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
25137                let newest_selection_id = this.selections.newest_anchor().id;
25138                this.selections
25139                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
25140                    .iter()
25141                    .zip(ranges_to_replace.iter())
25142                    .find_map(|(selection, range)| {
25143                        if selection.id == newest_selection_id {
25144                            Some(
25145                                (range.start.0.0 as isize - selection.head().0.0 as isize)
25146                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
25147                            )
25148                        } else {
25149                            None
25150                        }
25151                    })
25152            });
25153
25154            cx.emit(EditorEvent::InputHandled {
25155                utf16_range_to_replace: range_to_replace,
25156                text: text.into(),
25157            });
25158
25159            if let Some(new_selected_ranges) = new_selected_ranges {
25160                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
25161                    selections.select_ranges(new_selected_ranges)
25162                });
25163                this.backspace(&Default::default(), window, cx);
25164            }
25165
25166            this.handle_input(text, window, cx);
25167        });
25168
25169        if let Some(transaction) = self.ime_transaction {
25170            self.buffer.update(cx, |buffer, cx| {
25171                buffer.group_until_transaction(transaction, cx);
25172            });
25173        }
25174
25175        self.unmark_text(window, cx);
25176    }
25177
25178    fn replace_and_mark_text_in_range(
25179        &mut self,
25180        range_utf16: Option<Range<usize>>,
25181        text: &str,
25182        new_selected_range_utf16: Option<Range<usize>>,
25183        window: &mut Window,
25184        cx: &mut Context<Self>,
25185    ) {
25186        if !self.input_enabled {
25187            return;
25188        }
25189
25190        let transaction = self.transact(window, cx, |this, window, cx| {
25191            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
25192                let snapshot = this.buffer.read(cx).read(cx);
25193                if let Some(relative_range_utf16) = range_utf16.as_ref() {
25194                    for marked_range in &mut marked_ranges {
25195                        marked_range.end = marked_range.start + relative_range_utf16.end;
25196                        marked_range.start += relative_range_utf16.start;
25197                        marked_range.start =
25198                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
25199                        marked_range.end =
25200                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
25201                    }
25202                }
25203                Some(marked_ranges)
25204            } else if let Some(range_utf16) = range_utf16 {
25205                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
25206                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
25207                Some(this.selection_replacement_ranges(range_utf16, cx))
25208            } else {
25209                None
25210            };
25211
25212            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
25213                let newest_selection_id = this.selections.newest_anchor().id;
25214                this.selections
25215                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
25216                    .iter()
25217                    .zip(ranges_to_replace.iter())
25218                    .find_map(|(selection, range)| {
25219                        if selection.id == newest_selection_id {
25220                            Some(
25221                                (range.start.0.0 as isize - selection.head().0.0 as isize)
25222                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
25223                            )
25224                        } else {
25225                            None
25226                        }
25227                    })
25228            });
25229
25230            cx.emit(EditorEvent::InputHandled {
25231                utf16_range_to_replace: range_to_replace,
25232                text: text.into(),
25233            });
25234
25235            if let Some(ranges) = ranges_to_replace {
25236                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
25237                    s.select_ranges(ranges)
25238                });
25239            }
25240
25241            let marked_ranges = {
25242                let snapshot = this.buffer.read(cx).read(cx);
25243                this.selections
25244                    .disjoint_anchors_arc()
25245                    .iter()
25246                    .map(|selection| {
25247                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
25248                    })
25249                    .collect::<Vec<_>>()
25250            };
25251
25252            if text.is_empty() {
25253                this.unmark_text(window, cx);
25254            } else {
25255                this.highlight_text::<InputComposition>(
25256                    marked_ranges.clone(),
25257                    HighlightStyle {
25258                        underline: Some(UnderlineStyle {
25259                            thickness: px(1.),
25260                            color: None,
25261                            wavy: false,
25262                        }),
25263                        ..Default::default()
25264                    },
25265                    cx,
25266                );
25267            }
25268
25269            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
25270            let use_autoclose = this.use_autoclose;
25271            let use_auto_surround = this.use_auto_surround;
25272            this.set_use_autoclose(false);
25273            this.set_use_auto_surround(false);
25274            this.handle_input(text, window, cx);
25275            this.set_use_autoclose(use_autoclose);
25276            this.set_use_auto_surround(use_auto_surround);
25277
25278            if let Some(new_selected_range) = new_selected_range_utf16 {
25279                let snapshot = this.buffer.read(cx).read(cx);
25280                let new_selected_ranges = marked_ranges
25281                    .into_iter()
25282                    .map(|marked_range| {
25283                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
25284                        let new_start = MultiBufferOffsetUtf16(OffsetUtf16(
25285                            insertion_start.0 + new_selected_range.start,
25286                        ));
25287                        let new_end = MultiBufferOffsetUtf16(OffsetUtf16(
25288                            insertion_start.0 + new_selected_range.end,
25289                        ));
25290                        snapshot.clip_offset_utf16(new_start, Bias::Left)
25291                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
25292                    })
25293                    .collect::<Vec<_>>();
25294
25295                drop(snapshot);
25296                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
25297                    selections.select_ranges(new_selected_ranges)
25298                });
25299            }
25300        });
25301
25302        self.ime_transaction = self.ime_transaction.or(transaction);
25303        if let Some(transaction) = self.ime_transaction {
25304            self.buffer.update(cx, |buffer, cx| {
25305                buffer.group_until_transaction(transaction, cx);
25306            });
25307        }
25308
25309        if self.text_highlights::<InputComposition>(cx).is_none() {
25310            self.ime_transaction.take();
25311        }
25312    }
25313
25314    fn bounds_for_range(
25315        &mut self,
25316        range_utf16: Range<usize>,
25317        element_bounds: gpui::Bounds<Pixels>,
25318        window: &mut Window,
25319        cx: &mut Context<Self>,
25320    ) -> Option<gpui::Bounds<Pixels>> {
25321        let text_layout_details = self.text_layout_details(window);
25322        let CharacterDimensions {
25323            em_width,
25324            em_advance,
25325            line_height,
25326        } = self.character_dimensions(window);
25327
25328        let snapshot = self.snapshot(window, cx);
25329        let scroll_position = snapshot.scroll_position();
25330        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
25331
25332        let start =
25333            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)).to_display_point(&snapshot);
25334        let x = Pixels::from(
25335            ScrollOffset::from(
25336                snapshot.x_for_display_point(start, &text_layout_details)
25337                    + self.gutter_dimensions.full_width(),
25338            ) - scroll_left,
25339        );
25340        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
25341
25342        Some(Bounds {
25343            origin: element_bounds.origin + point(x, y),
25344            size: size(em_width, line_height),
25345        })
25346    }
25347
25348    fn character_index_for_point(
25349        &mut self,
25350        point: gpui::Point<Pixels>,
25351        _window: &mut Window,
25352        _cx: &mut Context<Self>,
25353    ) -> Option<usize> {
25354        let position_map = self.last_position_map.as_ref()?;
25355        if !position_map.text_hitbox.contains(&point) {
25356            return None;
25357        }
25358        let display_point = position_map.point_for_position(point).previous_valid;
25359        let anchor = position_map
25360            .snapshot
25361            .display_point_to_anchor(display_point, Bias::Left);
25362        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
25363        Some(utf16_offset.0.0)
25364    }
25365
25366    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
25367        self.input_enabled
25368    }
25369}
25370
25371trait SelectionExt {
25372    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
25373    fn spanned_rows(
25374        &self,
25375        include_end_if_at_line_start: bool,
25376        map: &DisplaySnapshot,
25377    ) -> Range<MultiBufferRow>;
25378}
25379
25380impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
25381    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
25382        let start = self
25383            .start
25384            .to_point(map.buffer_snapshot())
25385            .to_display_point(map);
25386        let end = self
25387            .end
25388            .to_point(map.buffer_snapshot())
25389            .to_display_point(map);
25390        if self.reversed {
25391            end..start
25392        } else {
25393            start..end
25394        }
25395    }
25396
25397    fn spanned_rows(
25398        &self,
25399        include_end_if_at_line_start: bool,
25400        map: &DisplaySnapshot,
25401    ) -> Range<MultiBufferRow> {
25402        let start = self.start.to_point(map.buffer_snapshot());
25403        let mut end = self.end.to_point(map.buffer_snapshot());
25404        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
25405            end.row -= 1;
25406        }
25407
25408        let buffer_start = map.prev_line_boundary(start).0;
25409        let buffer_end = map.next_line_boundary(end).0;
25410        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
25411    }
25412}
25413
25414impl<T: InvalidationRegion> InvalidationStack<T> {
25415    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
25416    where
25417        S: Clone + ToOffset,
25418    {
25419        while let Some(region) = self.last() {
25420            let all_selections_inside_invalidation_ranges =
25421                if selections.len() == region.ranges().len() {
25422                    selections
25423                        .iter()
25424                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
25425                        .all(|(selection, invalidation_range)| {
25426                            let head = selection.head().to_offset(buffer);
25427                            invalidation_range.start <= head && invalidation_range.end >= head
25428                        })
25429                } else {
25430                    false
25431                };
25432
25433            if all_selections_inside_invalidation_ranges {
25434                break;
25435            } else {
25436                self.pop();
25437            }
25438        }
25439    }
25440}
25441
25442impl<T> Default for InvalidationStack<T> {
25443    fn default() -> Self {
25444        Self(Default::default())
25445    }
25446}
25447
25448impl<T> Deref for InvalidationStack<T> {
25449    type Target = Vec<T>;
25450
25451    fn deref(&self) -> &Self::Target {
25452        &self.0
25453    }
25454}
25455
25456impl<T> DerefMut for InvalidationStack<T> {
25457    fn deref_mut(&mut self) -> &mut Self::Target {
25458        &mut self.0
25459    }
25460}
25461
25462impl InvalidationRegion for SnippetState {
25463    fn ranges(&self) -> &[Range<Anchor>] {
25464        &self.ranges[self.active_index]
25465    }
25466}
25467
25468fn edit_prediction_edit_text(
25469    current_snapshot: &BufferSnapshot,
25470    edits: &[(Range<Anchor>, impl AsRef<str>)],
25471    edit_preview: &EditPreview,
25472    include_deletions: bool,
25473    cx: &App,
25474) -> HighlightedText {
25475    let edits = edits
25476        .iter()
25477        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
25478        .collect::<Vec<_>>();
25479
25480    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
25481}
25482
25483fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
25484    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
25485    // Just show the raw edit text with basic styling
25486    let mut text = String::new();
25487    let mut highlights = Vec::new();
25488
25489    let insertion_highlight_style = HighlightStyle {
25490        color: Some(cx.theme().colors().text),
25491        ..Default::default()
25492    };
25493
25494    for (_, edit_text) in edits {
25495        let start_offset = text.len();
25496        text.push_str(edit_text);
25497        let end_offset = text.len();
25498
25499        if start_offset < end_offset {
25500            highlights.push((start_offset..end_offset, insertion_highlight_style));
25501        }
25502    }
25503
25504    HighlightedText {
25505        text: text.into(),
25506        highlights,
25507    }
25508}
25509
25510pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
25511    match severity {
25512        lsp::DiagnosticSeverity::ERROR => colors.error,
25513        lsp::DiagnosticSeverity::WARNING => colors.warning,
25514        lsp::DiagnosticSeverity::INFORMATION => colors.info,
25515        lsp::DiagnosticSeverity::HINT => colors.info,
25516        _ => colors.ignored,
25517    }
25518}
25519
25520pub fn styled_runs_for_code_label<'a>(
25521    label: &'a CodeLabel,
25522    syntax_theme: &'a theme::SyntaxTheme,
25523    local_player: &'a theme::PlayerColor,
25524) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
25525    let fade_out = HighlightStyle {
25526        fade_out: Some(0.35),
25527        ..Default::default()
25528    };
25529
25530    let mut prev_end = label.filter_range.end;
25531    label
25532        .runs
25533        .iter()
25534        .enumerate()
25535        .flat_map(move |(ix, (range, highlight_id))| {
25536            let style = if *highlight_id == language::HighlightId::TABSTOP_INSERT_ID {
25537                HighlightStyle {
25538                    color: Some(local_player.cursor),
25539                    ..Default::default()
25540                }
25541            } else if *highlight_id == language::HighlightId::TABSTOP_REPLACE_ID {
25542                HighlightStyle {
25543                    background_color: Some(local_player.selection),
25544                    ..Default::default()
25545                }
25546            } else if let Some(style) = highlight_id.style(syntax_theme) {
25547                style
25548            } else {
25549                return Default::default();
25550            };
25551            let muted_style = style.highlight(fade_out);
25552
25553            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
25554            if range.start >= label.filter_range.end {
25555                if range.start > prev_end {
25556                    runs.push((prev_end..range.start, fade_out));
25557                }
25558                runs.push((range.clone(), muted_style));
25559            } else if range.end <= label.filter_range.end {
25560                runs.push((range.clone(), style));
25561            } else {
25562                runs.push((range.start..label.filter_range.end, style));
25563                runs.push((label.filter_range.end..range.end, muted_style));
25564            }
25565            prev_end = cmp::max(prev_end, range.end);
25566
25567            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
25568                runs.push((prev_end..label.text.len(), fade_out));
25569            }
25570
25571            runs
25572        })
25573}
25574
25575pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
25576    let mut prev_index = 0;
25577    let mut prev_codepoint: Option<char> = None;
25578    text.char_indices()
25579        .chain([(text.len(), '\0')])
25580        .filter_map(move |(index, codepoint)| {
25581            let prev_codepoint = prev_codepoint.replace(codepoint)?;
25582            let is_boundary = index == text.len()
25583                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
25584                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
25585            if is_boundary {
25586                let chunk = &text[prev_index..index];
25587                prev_index = index;
25588                Some(chunk)
25589            } else {
25590                None
25591            }
25592        })
25593}
25594
25595/// Given a string of text immediately before the cursor, iterates over possible
25596/// strings a snippet could match to. More precisely: returns an iterator over
25597/// suffixes of `text` created by splitting at word boundaries (before & after
25598/// every non-word character).
25599///
25600/// Shorter suffixes are returned first.
25601pub(crate) fn snippet_candidate_suffixes(
25602    text: &str,
25603    is_word_char: impl Fn(char) -> bool,
25604) -> impl std::iter::Iterator<Item = &str> {
25605    let mut prev_index = text.len();
25606    let mut prev_codepoint = None;
25607    text.char_indices()
25608        .rev()
25609        .chain([(0, '\0')])
25610        .filter_map(move |(index, codepoint)| {
25611            let prev_index = std::mem::replace(&mut prev_index, index);
25612            let prev_codepoint = prev_codepoint.replace(codepoint)?;
25613            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
25614                None
25615            } else {
25616                let chunk = &text[prev_index..]; // go to end of string
25617                Some(chunk)
25618            }
25619        })
25620}
25621
25622pub trait RangeToAnchorExt: Sized {
25623    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
25624
25625    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
25626        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
25627        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
25628    }
25629}
25630
25631impl<T: ToOffset> RangeToAnchorExt for Range<T> {
25632    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
25633        let start_offset = self.start.to_offset(snapshot);
25634        let end_offset = self.end.to_offset(snapshot);
25635        if start_offset == end_offset {
25636            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
25637        } else {
25638            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
25639        }
25640    }
25641}
25642
25643pub trait RowExt {
25644    fn as_f64(&self) -> f64;
25645
25646    fn next_row(&self) -> Self;
25647
25648    fn previous_row(&self) -> Self;
25649
25650    fn minus(&self, other: Self) -> u32;
25651}
25652
25653impl RowExt for DisplayRow {
25654    fn as_f64(&self) -> f64 {
25655        self.0 as _
25656    }
25657
25658    fn next_row(&self) -> Self {
25659        Self(self.0 + 1)
25660    }
25661
25662    fn previous_row(&self) -> Self {
25663        Self(self.0.saturating_sub(1))
25664    }
25665
25666    fn minus(&self, other: Self) -> u32 {
25667        self.0 - other.0
25668    }
25669}
25670
25671impl RowExt for MultiBufferRow {
25672    fn as_f64(&self) -> f64 {
25673        self.0 as _
25674    }
25675
25676    fn next_row(&self) -> Self {
25677        Self(self.0 + 1)
25678    }
25679
25680    fn previous_row(&self) -> Self {
25681        Self(self.0.saturating_sub(1))
25682    }
25683
25684    fn minus(&self, other: Self) -> u32 {
25685        self.0 - other.0
25686    }
25687}
25688
25689trait RowRangeExt {
25690    type Row;
25691
25692    fn len(&self) -> usize;
25693
25694    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
25695}
25696
25697impl RowRangeExt for Range<MultiBufferRow> {
25698    type Row = MultiBufferRow;
25699
25700    fn len(&self) -> usize {
25701        (self.end.0 - self.start.0) as usize
25702    }
25703
25704    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
25705        (self.start.0..self.end.0).map(MultiBufferRow)
25706    }
25707}
25708
25709impl RowRangeExt for Range<DisplayRow> {
25710    type Row = DisplayRow;
25711
25712    fn len(&self) -> usize {
25713        (self.end.0 - self.start.0) as usize
25714    }
25715
25716    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
25717        (self.start.0..self.end.0).map(DisplayRow)
25718    }
25719}
25720
25721/// If select range has more than one line, we
25722/// just point the cursor to range.start.
25723fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
25724    if range.start.row == range.end.row {
25725        range
25726    } else {
25727        range.start..range.start
25728    }
25729}
25730pub struct KillRing(ClipboardItem);
25731impl Global for KillRing {}
25732
25733const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
25734
25735enum BreakpointPromptEditAction {
25736    Log,
25737    Condition,
25738    HitCondition,
25739}
25740
25741struct BreakpointPromptEditor {
25742    pub(crate) prompt: Entity<Editor>,
25743    editor: WeakEntity<Editor>,
25744    breakpoint_anchor: Anchor,
25745    breakpoint: Breakpoint,
25746    edit_action: BreakpointPromptEditAction,
25747    block_ids: HashSet<CustomBlockId>,
25748    editor_margins: Arc<Mutex<EditorMargins>>,
25749    _subscriptions: Vec<Subscription>,
25750}
25751
25752impl BreakpointPromptEditor {
25753    const MAX_LINES: u8 = 4;
25754
25755    fn new(
25756        editor: WeakEntity<Editor>,
25757        breakpoint_anchor: Anchor,
25758        breakpoint: Breakpoint,
25759        edit_action: BreakpointPromptEditAction,
25760        window: &mut Window,
25761        cx: &mut Context<Self>,
25762    ) -> Self {
25763        let base_text = match edit_action {
25764            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
25765            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
25766            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
25767        }
25768        .map(|msg| msg.to_string())
25769        .unwrap_or_default();
25770
25771        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
25772        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
25773
25774        let prompt = cx.new(|cx| {
25775            let mut prompt = Editor::new(
25776                EditorMode::AutoHeight {
25777                    min_lines: 1,
25778                    max_lines: Some(Self::MAX_LINES as usize),
25779                },
25780                buffer,
25781                None,
25782                window,
25783                cx,
25784            );
25785            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
25786            prompt.set_show_cursor_when_unfocused(false, cx);
25787            prompt.set_placeholder_text(
25788                match edit_action {
25789                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
25790                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
25791                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
25792                },
25793                window,
25794                cx,
25795            );
25796
25797            prompt
25798        });
25799
25800        Self {
25801            prompt,
25802            editor,
25803            breakpoint_anchor,
25804            breakpoint,
25805            edit_action,
25806            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
25807            block_ids: Default::default(),
25808            _subscriptions: vec![],
25809        }
25810    }
25811
25812    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
25813        self.block_ids.extend(block_ids)
25814    }
25815
25816    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
25817        if let Some(editor) = self.editor.upgrade() {
25818            let message = self
25819                .prompt
25820                .read(cx)
25821                .buffer
25822                .read(cx)
25823                .as_singleton()
25824                .expect("A multi buffer in breakpoint prompt isn't possible")
25825                .read(cx)
25826                .as_rope()
25827                .to_string();
25828
25829            editor.update(cx, |editor, cx| {
25830                editor.edit_breakpoint_at_anchor(
25831                    self.breakpoint_anchor,
25832                    self.breakpoint.clone(),
25833                    match self.edit_action {
25834                        BreakpointPromptEditAction::Log => {
25835                            BreakpointEditAction::EditLogMessage(message.into())
25836                        }
25837                        BreakpointPromptEditAction::Condition => {
25838                            BreakpointEditAction::EditCondition(message.into())
25839                        }
25840                        BreakpointPromptEditAction::HitCondition => {
25841                            BreakpointEditAction::EditHitCondition(message.into())
25842                        }
25843                    },
25844                    cx,
25845                );
25846
25847                editor.remove_blocks(self.block_ids.clone(), None, cx);
25848                cx.focus_self(window);
25849            });
25850        }
25851    }
25852
25853    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
25854        self.editor
25855            .update(cx, |editor, cx| {
25856                editor.remove_blocks(self.block_ids.clone(), None, cx);
25857                window.focus(&editor.focus_handle);
25858            })
25859            .log_err();
25860    }
25861
25862    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
25863        let settings = ThemeSettings::get_global(cx);
25864        let text_style = TextStyle {
25865            color: if self.prompt.read(cx).read_only(cx) {
25866                cx.theme().colors().text_disabled
25867            } else {
25868                cx.theme().colors().text
25869            },
25870            font_family: settings.buffer_font.family.clone(),
25871            font_fallbacks: settings.buffer_font.fallbacks.clone(),
25872            font_size: settings.buffer_font_size(cx).into(),
25873            font_weight: settings.buffer_font.weight,
25874            line_height: relative(settings.buffer_line_height.value()),
25875            ..Default::default()
25876        };
25877        EditorElement::new(
25878            &self.prompt,
25879            EditorStyle {
25880                background: cx.theme().colors().editor_background,
25881                local_player: cx.theme().players().local(),
25882                text: text_style,
25883                ..Default::default()
25884            },
25885        )
25886    }
25887}
25888
25889impl Render for BreakpointPromptEditor {
25890    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25891        let editor_margins = *self.editor_margins.lock();
25892        let gutter_dimensions = editor_margins.gutter;
25893        h_flex()
25894            .key_context("Editor")
25895            .bg(cx.theme().colors().editor_background)
25896            .border_y_1()
25897            .border_color(cx.theme().status().info_border)
25898            .size_full()
25899            .py(window.line_height() / 2.5)
25900            .on_action(cx.listener(Self::confirm))
25901            .on_action(cx.listener(Self::cancel))
25902            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
25903            .child(div().flex_1().child(self.render_prompt_editor(cx)))
25904    }
25905}
25906
25907impl Focusable for BreakpointPromptEditor {
25908    fn focus_handle(&self, cx: &App) -> FocusHandle {
25909        self.prompt.focus_handle(cx)
25910    }
25911}
25912
25913fn all_edits_insertions_or_deletions(
25914    edits: &Vec<(Range<Anchor>, Arc<str>)>,
25915    snapshot: &MultiBufferSnapshot,
25916) -> bool {
25917    let mut all_insertions = true;
25918    let mut all_deletions = true;
25919
25920    for (range, new_text) in edits.iter() {
25921        let range_is_empty = range.to_offset(snapshot).is_empty();
25922        let text_is_empty = new_text.is_empty();
25923
25924        if range_is_empty != text_is_empty {
25925            if range_is_empty {
25926                all_deletions = false;
25927            } else {
25928                all_insertions = false;
25929            }
25930        } else {
25931            return false;
25932        }
25933
25934        if !all_insertions && !all_deletions {
25935            return false;
25936        }
25937    }
25938    all_insertions || all_deletions
25939}
25940
25941struct MissingEditPredictionKeybindingTooltip;
25942
25943impl Render for MissingEditPredictionKeybindingTooltip {
25944    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25945        ui::tooltip_container(cx, |container, cx| {
25946            container
25947                .flex_shrink_0()
25948                .max_w_80()
25949                .min_h(rems_from_px(124.))
25950                .justify_between()
25951                .child(
25952                    v_flex()
25953                        .flex_1()
25954                        .text_ui_sm(cx)
25955                        .child(Label::new("Conflict with Accept Keybinding"))
25956                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
25957                )
25958                .child(
25959                    h_flex()
25960                        .pb_1()
25961                        .gap_1()
25962                        .items_end()
25963                        .w_full()
25964                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
25965                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
25966                        }))
25967                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
25968                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
25969                        })),
25970                )
25971        })
25972    }
25973}
25974
25975#[derive(Debug, Clone, Copy, PartialEq)]
25976pub struct LineHighlight {
25977    pub background: Background,
25978    pub border: Option<gpui::Hsla>,
25979    pub include_gutter: bool,
25980    pub type_id: Option<TypeId>,
25981}
25982
25983struct LineManipulationResult {
25984    pub new_text: String,
25985    pub line_count_before: usize,
25986    pub line_count_after: usize,
25987}
25988
25989fn render_diff_hunk_controls(
25990    row: u32,
25991    status: &DiffHunkStatus,
25992    hunk_range: Range<Anchor>,
25993    is_created_file: bool,
25994    line_height: Pixels,
25995    editor: &Entity<Editor>,
25996    _window: &mut Window,
25997    cx: &mut App,
25998) -> AnyElement {
25999    h_flex()
26000        .h(line_height)
26001        .mr_1()
26002        .gap_1()
26003        .px_0p5()
26004        .pb_1()
26005        .border_x_1()
26006        .border_b_1()
26007        .border_color(cx.theme().colors().border_variant)
26008        .rounded_b_lg()
26009        .bg(cx.theme().colors().editor_background)
26010        .gap_1()
26011        .block_mouse_except_scroll()
26012        .shadow_md()
26013        .child(if status.has_secondary_hunk() {
26014            Button::new(("stage", row as u64), "Stage")
26015                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
26016                .tooltip({
26017                    let focus_handle = editor.focus_handle(cx);
26018                    move |_window, cx| {
26019                        Tooltip::for_action_in(
26020                            "Stage Hunk",
26021                            &::git::ToggleStaged,
26022                            &focus_handle,
26023                            cx,
26024                        )
26025                    }
26026                })
26027                .on_click({
26028                    let editor = editor.clone();
26029                    move |_event, _window, cx| {
26030                        editor.update(cx, |editor, cx| {
26031                            editor.stage_or_unstage_diff_hunks(
26032                                true,
26033                                vec![hunk_range.start..hunk_range.start],
26034                                cx,
26035                            );
26036                        });
26037                    }
26038                })
26039        } else {
26040            Button::new(("unstage", row as u64), "Unstage")
26041                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
26042                .tooltip({
26043                    let focus_handle = editor.focus_handle(cx);
26044                    move |_window, cx| {
26045                        Tooltip::for_action_in(
26046                            "Unstage Hunk",
26047                            &::git::ToggleStaged,
26048                            &focus_handle,
26049                            cx,
26050                        )
26051                    }
26052                })
26053                .on_click({
26054                    let editor = editor.clone();
26055                    move |_event, _window, cx| {
26056                        editor.update(cx, |editor, cx| {
26057                            editor.stage_or_unstage_diff_hunks(
26058                                false,
26059                                vec![hunk_range.start..hunk_range.start],
26060                                cx,
26061                            );
26062                        });
26063                    }
26064                })
26065        })
26066        .child(
26067            Button::new(("restore", row as u64), "Restore")
26068                .tooltip({
26069                    let focus_handle = editor.focus_handle(cx);
26070                    move |_window, cx| {
26071                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
26072                    }
26073                })
26074                .on_click({
26075                    let editor = editor.clone();
26076                    move |_event, window, cx| {
26077                        editor.update(cx, |editor, cx| {
26078                            let snapshot = editor.snapshot(window, cx);
26079                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
26080                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
26081                        });
26082                    }
26083                })
26084                .disabled(is_created_file),
26085        )
26086        .when(
26087            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
26088            |el| {
26089                el.child(
26090                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
26091                        .shape(IconButtonShape::Square)
26092                        .icon_size(IconSize::Small)
26093                        // .disabled(!has_multiple_hunks)
26094                        .tooltip({
26095                            let focus_handle = editor.focus_handle(cx);
26096                            move |_window, cx| {
26097                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
26098                            }
26099                        })
26100                        .on_click({
26101                            let editor = editor.clone();
26102                            move |_event, window, cx| {
26103                                editor.update(cx, |editor, cx| {
26104                                    let snapshot = editor.snapshot(window, cx);
26105                                    let position =
26106                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
26107                                    editor.go_to_hunk_before_or_after_position(
26108                                        &snapshot,
26109                                        position,
26110                                        Direction::Next,
26111                                        window,
26112                                        cx,
26113                                    );
26114                                    editor.expand_selected_diff_hunks(cx);
26115                                });
26116                            }
26117                        }),
26118                )
26119                .child(
26120                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
26121                        .shape(IconButtonShape::Square)
26122                        .icon_size(IconSize::Small)
26123                        // .disabled(!has_multiple_hunks)
26124                        .tooltip({
26125                            let focus_handle = editor.focus_handle(cx);
26126                            move |_window, cx| {
26127                                Tooltip::for_action_in(
26128                                    "Previous Hunk",
26129                                    &GoToPreviousHunk,
26130                                    &focus_handle,
26131                                    cx,
26132                                )
26133                            }
26134                        })
26135                        .on_click({
26136                            let editor = editor.clone();
26137                            move |_event, window, cx| {
26138                                editor.update(cx, |editor, cx| {
26139                                    let snapshot = editor.snapshot(window, cx);
26140                                    let point =
26141                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
26142                                    editor.go_to_hunk_before_or_after_position(
26143                                        &snapshot,
26144                                        point,
26145                                        Direction::Prev,
26146                                        window,
26147                                        cx,
26148                                    );
26149                                    editor.expand_selected_diff_hunks(cx);
26150                                });
26151                            }
26152                        }),
26153                )
26154            },
26155        )
26156        .into_any_element()
26157}
26158
26159pub fn multibuffer_context_lines(cx: &App) -> u32 {
26160    EditorSettings::try_get(cx)
26161        .map(|settings| settings.excerpt_context_lines)
26162        .unwrap_or(2)
26163        .min(32)
26164}