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 mut byte_offset = 0u32;
 4398                                let current_line_count = snapshot
 4399                                    .reversed_chars_at(selection.start)
 4400                                    .take_while(|&c| c != '\n')
 4401                                    .filter(|c| {
 4402                                        byte_offset += c.len_utf8() as u32;
 4403                                        if *c != target {
 4404                                            return false;
 4405                                        }
 4406
 4407                                        let point = Point::new(
 4408                                            selection.start.row,
 4409                                            selection.start.column.saturating_sub(byte_offset),
 4410                                        );
 4411
 4412                                        let is_enabled = snapshot
 4413                                            .language_scope_at(point)
 4414                                            .and_then(|scope| {
 4415                                                scope
 4416                                                    .brackets()
 4417                                                    .find(|(pair, _)| {
 4418                                                        pair.start == bracket_pair.start
 4419                                                    })
 4420                                                    .map(|(_, enabled)| enabled)
 4421                                            })
 4422                                            .unwrap_or(true);
 4423
 4424                                        let is_delimiter = snapshot
 4425                                            .language_scope_at(Point::new(
 4426                                                point.row,
 4427                                                point.column + 1,
 4428                                            ))
 4429                                            .and_then(|scope| {
 4430                                                scope
 4431                                                    .brackets()
 4432                                                    .find(|(pair, _)| {
 4433                                                        pair.start == bracket_pair.start
 4434                                                    })
 4435                                                    .map(|(_, enabled)| !enabled)
 4436                                            })
 4437                                            .unwrap_or(false);
 4438
 4439                                        is_enabled && !is_delimiter
 4440                                    })
 4441                                    .count();
 4442                                current_line_count % 2 == 1
 4443                            } else {
 4444                                false
 4445                            };
 4446
 4447                            if autoclose
 4448                                && bracket_pair.close
 4449                                && following_text_allows_autoclose
 4450                                && preceding_text_allows_autoclose
 4451                                && !is_closing_quote
 4452                            {
 4453                                let anchor = snapshot.anchor_before(selection.end);
 4454                                new_selections.push((selection.map(|_| anchor), text.len()));
 4455                                new_autoclose_regions.push((
 4456                                    anchor,
 4457                                    text.len(),
 4458                                    selection.id,
 4459                                    bracket_pair.clone(),
 4460                                ));
 4461                                edits.push((
 4462                                    selection.range(),
 4463                                    format!("{}{}", text, bracket_pair.end).into(),
 4464                                ));
 4465                                bracket_inserted = true;
 4466                                continue;
 4467                            }
 4468                        }
 4469
 4470                        if let Some(region) = autoclose_region {
 4471                            // If the selection is followed by an auto-inserted closing bracket,
 4472                            // then don't insert that closing bracket again; just move the selection
 4473                            // past the closing bracket.
 4474                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4475                                && text.as_ref() == region.pair.end.as_str()
 4476                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4477                            if should_skip {
 4478                                let anchor = snapshot.anchor_after(selection.end);
 4479                                new_selections
 4480                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4481                                continue;
 4482                            }
 4483                        }
 4484
 4485                        let always_treat_brackets_as_autoclosed = snapshot
 4486                            .language_settings_at(selection.start, cx)
 4487                            .always_treat_brackets_as_autoclosed;
 4488                        if always_treat_brackets_as_autoclosed
 4489                            && is_bracket_pair_end
 4490                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4491                        {
 4492                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4493                            // and the inserted text is a closing bracket and the selection is followed
 4494                            // by the closing bracket then move the selection past the closing bracket.
 4495                            let anchor = snapshot.anchor_after(selection.end);
 4496                            new_selections.push((selection.map(|_| anchor), text.len()));
 4497                            continue;
 4498                        }
 4499                    }
 4500                    // If an opening bracket is 1 character long and is typed while
 4501                    // text is selected, then surround that text with the bracket pair.
 4502                    else if auto_surround
 4503                        && bracket_pair.surround
 4504                        && is_bracket_pair_start
 4505                        && bracket_pair.start.chars().count() == 1
 4506                    {
 4507                        edits.push((selection.start..selection.start, text.clone()));
 4508                        edits.push((
 4509                            selection.end..selection.end,
 4510                            bracket_pair.end.as_str().into(),
 4511                        ));
 4512                        bracket_inserted = true;
 4513                        new_selections.push((
 4514                            Selection {
 4515                                id: selection.id,
 4516                                start: snapshot.anchor_after(selection.start),
 4517                                end: snapshot.anchor_before(selection.end),
 4518                                reversed: selection.reversed,
 4519                                goal: selection.goal,
 4520                            },
 4521                            0,
 4522                        ));
 4523                        continue;
 4524                    }
 4525                }
 4526            }
 4527
 4528            if self.auto_replace_emoji_shortcode
 4529                && selection.is_empty()
 4530                && text.as_ref().ends_with(':')
 4531                && let Some(possible_emoji_short_code) =
 4532                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4533                && !possible_emoji_short_code.is_empty()
 4534                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4535            {
 4536                let emoji_shortcode_start = Point::new(
 4537                    selection.start.row,
 4538                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4539                );
 4540
 4541                // Remove shortcode from buffer
 4542                edits.push((
 4543                    emoji_shortcode_start..selection.start,
 4544                    "".to_string().into(),
 4545                ));
 4546                new_selections.push((
 4547                    Selection {
 4548                        id: selection.id,
 4549                        start: snapshot.anchor_after(emoji_shortcode_start),
 4550                        end: snapshot.anchor_before(selection.start),
 4551                        reversed: selection.reversed,
 4552                        goal: selection.goal,
 4553                    },
 4554                    0,
 4555                ));
 4556
 4557                // Insert emoji
 4558                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4559                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4560                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4561
 4562                continue;
 4563            }
 4564
 4565            // If not handling any auto-close operation, then just replace the selected
 4566            // text with the given input and move the selection to the end of the
 4567            // newly inserted text.
 4568            let anchor = snapshot.anchor_after(selection.end);
 4569            if !self.linked_edit_ranges.is_empty() {
 4570                let start_anchor = snapshot.anchor_before(selection.start);
 4571
 4572                let is_word_char = text.chars().next().is_none_or(|char| {
 4573                    let classifier = snapshot
 4574                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4575                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4576                    classifier.is_word(char)
 4577                });
 4578
 4579                if is_word_char {
 4580                    if let Some(ranges) = self
 4581                        .linked_editing_ranges_for(start_anchor.text_anchor..anchor.text_anchor, cx)
 4582                    {
 4583                        for (buffer, edits) in ranges {
 4584                            linked_edits
 4585                                .entry(buffer.clone())
 4586                                .or_default()
 4587                                .extend(edits.into_iter().map(|range| (range, text.clone())));
 4588                        }
 4589                    }
 4590                } else {
 4591                    clear_linked_edit_ranges = true;
 4592                }
 4593            }
 4594
 4595            new_selections.push((selection.map(|_| anchor), 0));
 4596            edits.push((selection.start..selection.end, text.clone()));
 4597        }
 4598
 4599        drop(snapshot);
 4600
 4601        self.transact(window, cx, |this, window, cx| {
 4602            if clear_linked_edit_ranges {
 4603                this.linked_edit_ranges.clear();
 4604            }
 4605            let initial_buffer_versions =
 4606                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4607
 4608            this.buffer.update(cx, |buffer, cx| {
 4609                buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4610            });
 4611            for (buffer, edits) in linked_edits {
 4612                buffer.update(cx, |buffer, cx| {
 4613                    let snapshot = buffer.snapshot();
 4614                    let edits = edits
 4615                        .into_iter()
 4616                        .map(|(range, text)| {
 4617                            use text::ToPoint as TP;
 4618                            let end_point = TP::to_point(&range.end, &snapshot);
 4619                            let start_point = TP::to_point(&range.start, &snapshot);
 4620                            (start_point..end_point, text)
 4621                        })
 4622                        .sorted_by_key(|(range, _)| range.start);
 4623                    buffer.edit(edits, None, cx);
 4624                })
 4625            }
 4626            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4627            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4628            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4629            let new_selections = resolve_selections_wrapping_blocks::<MultiBufferOffset, _>(
 4630                new_anchor_selections,
 4631                &map,
 4632            )
 4633            .zip(new_selection_deltas)
 4634            .map(|(selection, delta)| Selection {
 4635                id: selection.id,
 4636                start: selection.start + delta,
 4637                end: selection.end + delta,
 4638                reversed: selection.reversed,
 4639                goal: SelectionGoal::None,
 4640            })
 4641            .collect::<Vec<_>>();
 4642
 4643            let mut i = 0;
 4644            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4645                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4646                let start = map.buffer_snapshot().anchor_before(position);
 4647                let end = map.buffer_snapshot().anchor_after(position);
 4648                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4649                    match existing_state
 4650                        .range
 4651                        .start
 4652                        .cmp(&start, map.buffer_snapshot())
 4653                    {
 4654                        Ordering::Less => i += 1,
 4655                        Ordering::Greater => break,
 4656                        Ordering::Equal => {
 4657                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4658                                Ordering::Less => i += 1,
 4659                                Ordering::Equal => break,
 4660                                Ordering::Greater => break,
 4661                            }
 4662                        }
 4663                    }
 4664                }
 4665                this.autoclose_regions.insert(
 4666                    i,
 4667                    AutocloseRegion {
 4668                        selection_id,
 4669                        range: start..end,
 4670                        pair,
 4671                    },
 4672                );
 4673            }
 4674
 4675            let had_active_edit_prediction = this.has_active_edit_prediction();
 4676            this.change_selections(
 4677                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4678                window,
 4679                cx,
 4680                |s| s.select(new_selections),
 4681            );
 4682
 4683            if !bracket_inserted
 4684                && let Some(on_type_format_task) =
 4685                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4686            {
 4687                on_type_format_task.detach_and_log_err(cx);
 4688            }
 4689
 4690            let editor_settings = EditorSettings::get_global(cx);
 4691            if bracket_inserted
 4692                && (editor_settings.auto_signature_help
 4693                    || editor_settings.show_signature_help_after_edits)
 4694            {
 4695                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4696            }
 4697
 4698            let trigger_in_words =
 4699                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4700            if this.hard_wrap.is_some() {
 4701                let latest: Range<Point> = this.selections.newest(&map).range();
 4702                if latest.is_empty()
 4703                    && this
 4704                        .buffer()
 4705                        .read(cx)
 4706                        .snapshot(cx)
 4707                        .line_len(MultiBufferRow(latest.start.row))
 4708                        == latest.start.column
 4709                {
 4710                    this.rewrap_impl(
 4711                        RewrapOptions {
 4712                            override_language_settings: true,
 4713                            preserve_existing_whitespace: true,
 4714                        },
 4715                        cx,
 4716                    )
 4717                }
 4718            }
 4719            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4720            refresh_linked_ranges(this, window, cx);
 4721            this.refresh_edit_prediction(true, false, window, cx);
 4722            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 4723        });
 4724    }
 4725
 4726    fn find_possible_emoji_shortcode_at_position(
 4727        snapshot: &MultiBufferSnapshot,
 4728        position: Point,
 4729    ) -> Option<String> {
 4730        let mut chars = Vec::new();
 4731        let mut found_colon = false;
 4732        for char in snapshot.reversed_chars_at(position).take(100) {
 4733            // Found a possible emoji shortcode in the middle of the buffer
 4734            if found_colon {
 4735                if char.is_whitespace() {
 4736                    chars.reverse();
 4737                    return Some(chars.iter().collect());
 4738                }
 4739                // If the previous character is not a whitespace, we are in the middle of a word
 4740                // and we only want to complete the shortcode if the word is made up of other emojis
 4741                let mut containing_word = String::new();
 4742                for ch in snapshot
 4743                    .reversed_chars_at(position)
 4744                    .skip(chars.len() + 1)
 4745                    .take(100)
 4746                {
 4747                    if ch.is_whitespace() {
 4748                        break;
 4749                    }
 4750                    containing_word.push(ch);
 4751                }
 4752                let containing_word = containing_word.chars().rev().collect::<String>();
 4753                if util::word_consists_of_emojis(containing_word.as_str()) {
 4754                    chars.reverse();
 4755                    return Some(chars.iter().collect());
 4756                }
 4757            }
 4758
 4759            if char.is_whitespace() || !char.is_ascii() {
 4760                return None;
 4761            }
 4762            if char == ':' {
 4763                found_colon = true;
 4764            } else {
 4765                chars.push(char);
 4766            }
 4767        }
 4768        // Found a possible emoji shortcode at the beginning of the buffer
 4769        chars.reverse();
 4770        Some(chars.iter().collect())
 4771    }
 4772
 4773    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 4774        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4775        self.transact(window, cx, |this, window, cx| {
 4776            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 4777                let selections = this
 4778                    .selections
 4779                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
 4780                let multi_buffer = this.buffer.read(cx);
 4781                let buffer = multi_buffer.snapshot(cx);
 4782                selections
 4783                    .iter()
 4784                    .map(|selection| {
 4785                        let start_point = selection.start.to_point(&buffer);
 4786                        let mut existing_indent =
 4787                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 4788                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 4789                        let start = selection.start;
 4790                        let end = selection.end;
 4791                        let selection_is_empty = start == end;
 4792                        let language_scope = buffer.language_scope_at(start);
 4793                        let (
 4794                            comment_delimiter,
 4795                            doc_delimiter,
 4796                            insert_extra_newline,
 4797                            indent_on_newline,
 4798                            indent_on_extra_newline,
 4799                        ) = if let Some(language) = &language_scope {
 4800                            let mut insert_extra_newline =
 4801                                insert_extra_newline_brackets(&buffer, start..end, language)
 4802                                    || insert_extra_newline_tree_sitter(&buffer, start..end);
 4803
 4804                            // Comment extension on newline is allowed only for cursor selections
 4805                            let comment_delimiter = maybe!({
 4806                                if !selection_is_empty {
 4807                                    return None;
 4808                                }
 4809
 4810                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4811                                    return None;
 4812                                }
 4813
 4814                                let delimiters = language.line_comment_prefixes();
 4815                                let max_len_of_delimiter =
 4816                                    delimiters.iter().map(|delimiter| delimiter.len()).max()?;
 4817                                let (snapshot, range) =
 4818                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4819
 4820                                let num_of_whitespaces = snapshot
 4821                                    .chars_for_range(range.clone())
 4822                                    .take_while(|c| c.is_whitespace())
 4823                                    .count();
 4824                                let comment_candidate = snapshot
 4825                                    .chars_for_range(range.clone())
 4826                                    .skip(num_of_whitespaces)
 4827                                    .take(max_len_of_delimiter)
 4828                                    .collect::<String>();
 4829                                let (delimiter, trimmed_len) = delimiters
 4830                                    .iter()
 4831                                    .filter_map(|delimiter| {
 4832                                        let prefix = delimiter.trim_end();
 4833                                        if comment_candidate.starts_with(prefix) {
 4834                                            Some((delimiter, prefix.len()))
 4835                                        } else {
 4836                                            None
 4837                                        }
 4838                                    })
 4839                                    .max_by_key(|(_, len)| *len)?;
 4840
 4841                                if let Some(BlockCommentConfig {
 4842                                    start: block_start, ..
 4843                                }) = language.block_comment()
 4844                                {
 4845                                    let block_start_trimmed = block_start.trim_end();
 4846                                    if block_start_trimmed.starts_with(delimiter.trim_end()) {
 4847                                        let line_content = snapshot
 4848                                            .chars_for_range(range)
 4849                                            .skip(num_of_whitespaces)
 4850                                            .take(block_start_trimmed.len())
 4851                                            .collect::<String>();
 4852
 4853                                        if line_content.starts_with(block_start_trimmed) {
 4854                                            return None;
 4855                                        }
 4856                                    }
 4857                                }
 4858
 4859                                let cursor_is_placed_after_comment_marker =
 4860                                    num_of_whitespaces + trimmed_len <= start_point.column as usize;
 4861                                if cursor_is_placed_after_comment_marker {
 4862                                    Some(delimiter.clone())
 4863                                } else {
 4864                                    None
 4865                                }
 4866                            });
 4867
 4868                            let mut indent_on_newline = IndentSize::spaces(0);
 4869                            let mut indent_on_extra_newline = IndentSize::spaces(0);
 4870
 4871                            let doc_delimiter = maybe!({
 4872                                if !selection_is_empty {
 4873                                    return None;
 4874                                }
 4875
 4876                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 4877                                    return None;
 4878                                }
 4879
 4880                                let BlockCommentConfig {
 4881                                    start: start_tag,
 4882                                    end: end_tag,
 4883                                    prefix: delimiter,
 4884                                    tab_size: len,
 4885                                } = language.documentation_comment()?;
 4886                                let is_within_block_comment = buffer
 4887                                    .language_scope_at(start_point)
 4888                                    .is_some_and(|scope| scope.override_name() == Some("comment"));
 4889                                if !is_within_block_comment {
 4890                                    return None;
 4891                                }
 4892
 4893                                let (snapshot, range) =
 4894                                    buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
 4895
 4896                                let num_of_whitespaces = snapshot
 4897                                    .chars_for_range(range.clone())
 4898                                    .take_while(|c| c.is_whitespace())
 4899                                    .count();
 4900
 4901                                // 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.
 4902                                let column = start_point.column;
 4903                                let cursor_is_after_start_tag = {
 4904                                    let start_tag_len = start_tag.len();
 4905                                    let start_tag_line = snapshot
 4906                                        .chars_for_range(range.clone())
 4907                                        .skip(num_of_whitespaces)
 4908                                        .take(start_tag_len)
 4909                                        .collect::<String>();
 4910                                    if start_tag_line.starts_with(start_tag.as_ref()) {
 4911                                        num_of_whitespaces + start_tag_len <= column as usize
 4912                                    } else {
 4913                                        false
 4914                                    }
 4915                                };
 4916
 4917                                let cursor_is_after_delimiter = {
 4918                                    let delimiter_trim = delimiter.trim_end();
 4919                                    let delimiter_line = snapshot
 4920                                        .chars_for_range(range.clone())
 4921                                        .skip(num_of_whitespaces)
 4922                                        .take(delimiter_trim.len())
 4923                                        .collect::<String>();
 4924                                    if delimiter_line.starts_with(delimiter_trim) {
 4925                                        num_of_whitespaces + delimiter_trim.len() <= column as usize
 4926                                    } else {
 4927                                        false
 4928                                    }
 4929                                };
 4930
 4931                                let cursor_is_before_end_tag_if_exists = {
 4932                                    let mut char_position = 0u32;
 4933                                    let mut end_tag_offset = None;
 4934
 4935                                    'outer: for chunk in snapshot.text_for_range(range) {
 4936                                        if let Some(byte_pos) = chunk.find(&**end_tag) {
 4937                                            let chars_before_match =
 4938                                                chunk[..byte_pos].chars().count() as u32;
 4939                                            end_tag_offset =
 4940                                                Some(char_position + chars_before_match);
 4941                                            break 'outer;
 4942                                        }
 4943                                        char_position += chunk.chars().count() as u32;
 4944                                    }
 4945
 4946                                    if let Some(end_tag_offset) = end_tag_offset {
 4947                                        let cursor_is_before_end_tag = column <= end_tag_offset;
 4948                                        if cursor_is_after_start_tag {
 4949                                            if cursor_is_before_end_tag {
 4950                                                insert_extra_newline = true;
 4951                                            }
 4952                                            let cursor_is_at_start_of_end_tag =
 4953                                                column == end_tag_offset;
 4954                                            if cursor_is_at_start_of_end_tag {
 4955                                                indent_on_extra_newline.len = *len;
 4956                                            }
 4957                                        }
 4958                                        cursor_is_before_end_tag
 4959                                    } else {
 4960                                        true
 4961                                    }
 4962                                };
 4963
 4964                                if (cursor_is_after_start_tag || cursor_is_after_delimiter)
 4965                                    && cursor_is_before_end_tag_if_exists
 4966                                {
 4967                                    if cursor_is_after_start_tag {
 4968                                        indent_on_newline.len = *len;
 4969                                    }
 4970                                    Some(delimiter.clone())
 4971                                } else {
 4972                                    None
 4973                                }
 4974                            });
 4975
 4976                            (
 4977                                comment_delimiter,
 4978                                doc_delimiter,
 4979                                insert_extra_newline,
 4980                                indent_on_newline,
 4981                                indent_on_extra_newline,
 4982                            )
 4983                        } else {
 4984                            (
 4985                                None,
 4986                                None,
 4987                                false,
 4988                                IndentSize::default(),
 4989                                IndentSize::default(),
 4990                            )
 4991                        };
 4992
 4993                        let prevent_auto_indent = doc_delimiter.is_some();
 4994                        let delimiter = comment_delimiter.or(doc_delimiter);
 4995
 4996                        let capacity_for_delimiter =
 4997                            delimiter.as_deref().map(str::len).unwrap_or_default();
 4998                        let mut new_text = String::with_capacity(
 4999                            1 + capacity_for_delimiter
 5000                                + existing_indent.len as usize
 5001                                + indent_on_newline.len as usize
 5002                                + indent_on_extra_newline.len as usize,
 5003                        );
 5004                        new_text.push('\n');
 5005                        new_text.extend(existing_indent.chars());
 5006                        new_text.extend(indent_on_newline.chars());
 5007
 5008                        if let Some(delimiter) = &delimiter {
 5009                            new_text.push_str(delimiter);
 5010                        }
 5011
 5012                        if insert_extra_newline {
 5013                            new_text.push('\n');
 5014                            new_text.extend(existing_indent.chars());
 5015                            new_text.extend(indent_on_extra_newline.chars());
 5016                        }
 5017
 5018                        let anchor = buffer.anchor_after(end);
 5019                        let new_selection = selection.map(|_| anchor);
 5020                        (
 5021                            ((start..end, new_text), prevent_auto_indent),
 5022                            (insert_extra_newline, new_selection),
 5023                        )
 5024                    })
 5025                    .unzip()
 5026            };
 5027
 5028            let mut auto_indent_edits = Vec::new();
 5029            let mut edits = Vec::new();
 5030            for (edit, prevent_auto_indent) in edits_with_flags {
 5031                if prevent_auto_indent {
 5032                    edits.push(edit);
 5033                } else {
 5034                    auto_indent_edits.push(edit);
 5035                }
 5036            }
 5037            if !edits.is_empty() {
 5038                this.edit(edits, cx);
 5039            }
 5040            if !auto_indent_edits.is_empty() {
 5041                this.edit_with_autoindent(auto_indent_edits, cx);
 5042            }
 5043
 5044            let buffer = this.buffer.read(cx).snapshot(cx);
 5045            let new_selections = selection_info
 5046                .into_iter()
 5047                .map(|(extra_newline_inserted, new_selection)| {
 5048                    let mut cursor = new_selection.end.to_point(&buffer);
 5049                    if extra_newline_inserted {
 5050                        cursor.row -= 1;
 5051                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 5052                    }
 5053                    new_selection.map(|_| cursor)
 5054                })
 5055                .collect();
 5056
 5057            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 5058            this.refresh_edit_prediction(true, false, window, cx);
 5059            if let Some(task) = this.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5060                task.detach_and_log_err(cx);
 5061            }
 5062        });
 5063    }
 5064
 5065    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 5066        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5067
 5068        let buffer = self.buffer.read(cx);
 5069        let snapshot = buffer.snapshot(cx);
 5070
 5071        let mut edits = Vec::new();
 5072        let mut rows = Vec::new();
 5073
 5074        for (rows_inserted, selection) in self
 5075            .selections
 5076            .all_adjusted(&self.display_snapshot(cx))
 5077            .into_iter()
 5078            .enumerate()
 5079        {
 5080            let cursor = selection.head();
 5081            let row = cursor.row;
 5082
 5083            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 5084
 5085            let newline = "\n".to_string();
 5086            edits.push((start_of_line..start_of_line, newline));
 5087
 5088            rows.push(row + rows_inserted as u32);
 5089        }
 5090
 5091        self.transact(window, cx, |editor, window, cx| {
 5092            editor.edit(edits, cx);
 5093
 5094            editor.change_selections(Default::default(), window, cx, |s| {
 5095                let mut index = 0;
 5096                s.move_cursors_with(|map, _, _| {
 5097                    let row = rows[index];
 5098                    index += 1;
 5099
 5100                    let point = Point::new(row, 0);
 5101                    let boundary = map.next_line_boundary(point).1;
 5102                    let clipped = map.clip_point(boundary, Bias::Left);
 5103
 5104                    (clipped, SelectionGoal::None)
 5105                });
 5106            });
 5107
 5108            let mut indent_edits = Vec::new();
 5109            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5110            for row in rows {
 5111                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5112                for (row, indent) in indents {
 5113                    if indent.len == 0 {
 5114                        continue;
 5115                    }
 5116
 5117                    let text = match indent.kind {
 5118                        IndentKind::Space => " ".repeat(indent.len as usize),
 5119                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5120                    };
 5121                    let point = Point::new(row.0, 0);
 5122                    indent_edits.push((point..point, text));
 5123                }
 5124            }
 5125            editor.edit(indent_edits, cx);
 5126            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5127                format.detach_and_log_err(cx);
 5128            }
 5129        });
 5130    }
 5131
 5132    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 5133        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5134
 5135        let buffer = self.buffer.read(cx);
 5136        let snapshot = buffer.snapshot(cx);
 5137
 5138        let mut edits = Vec::new();
 5139        let mut rows = Vec::new();
 5140        let mut rows_inserted = 0;
 5141
 5142        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 5143            let cursor = selection.head();
 5144            let row = cursor.row;
 5145
 5146            let point = Point::new(row + 1, 0);
 5147            let start_of_line = snapshot.clip_point(point, Bias::Left);
 5148
 5149            let newline = "\n".to_string();
 5150            edits.push((start_of_line..start_of_line, newline));
 5151
 5152            rows_inserted += 1;
 5153            rows.push(row + rows_inserted);
 5154        }
 5155
 5156        self.transact(window, cx, |editor, window, cx| {
 5157            editor.edit(edits, cx);
 5158
 5159            editor.change_selections(Default::default(), window, cx, |s| {
 5160                let mut index = 0;
 5161                s.move_cursors_with(|map, _, _| {
 5162                    let row = rows[index];
 5163                    index += 1;
 5164
 5165                    let point = Point::new(row, 0);
 5166                    let boundary = map.next_line_boundary(point).1;
 5167                    let clipped = map.clip_point(boundary, Bias::Left);
 5168
 5169                    (clipped, SelectionGoal::None)
 5170                });
 5171            });
 5172
 5173            let mut indent_edits = Vec::new();
 5174            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5175            for row in rows {
 5176                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5177                for (row, indent) in indents {
 5178                    if indent.len == 0 {
 5179                        continue;
 5180                    }
 5181
 5182                    let text = match indent.kind {
 5183                        IndentKind::Space => " ".repeat(indent.len as usize),
 5184                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5185                    };
 5186                    let point = Point::new(row.0, 0);
 5187                    indent_edits.push((point..point, text));
 5188                }
 5189            }
 5190            editor.edit(indent_edits, cx);
 5191            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5192                format.detach_and_log_err(cx);
 5193            }
 5194        });
 5195    }
 5196
 5197    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5198        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5199            original_indent_columns: Vec::new(),
 5200        });
 5201        self.insert_with_autoindent_mode(text, autoindent, window, cx);
 5202    }
 5203
 5204    fn insert_with_autoindent_mode(
 5205        &mut self,
 5206        text: &str,
 5207        autoindent_mode: Option<AutoindentMode>,
 5208        window: &mut Window,
 5209        cx: &mut Context<Self>,
 5210    ) {
 5211        if self.read_only(cx) {
 5212            return;
 5213        }
 5214
 5215        let text: Arc<str> = text.into();
 5216        self.transact(window, cx, |this, window, cx| {
 5217            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5218            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5219                let anchors = {
 5220                    let snapshot = buffer.read(cx);
 5221                    old_selections
 5222                        .iter()
 5223                        .map(|s| {
 5224                            let anchor = snapshot.anchor_after(s.head());
 5225                            s.map(|_| anchor)
 5226                        })
 5227                        .collect::<Vec<_>>()
 5228                };
 5229                buffer.edit(
 5230                    old_selections
 5231                        .iter()
 5232                        .map(|s| (s.start..s.end, text.clone())),
 5233                    autoindent_mode,
 5234                    cx,
 5235                );
 5236                anchors
 5237            });
 5238
 5239            this.change_selections(Default::default(), window, cx, |s| {
 5240                s.select_anchors(selection_anchors);
 5241            });
 5242
 5243            cx.notify();
 5244        });
 5245    }
 5246
 5247    fn trigger_completion_on_input(
 5248        &mut self,
 5249        text: &str,
 5250        trigger_in_words: bool,
 5251        window: &mut Window,
 5252        cx: &mut Context<Self>,
 5253    ) {
 5254        let completions_source = self
 5255            .context_menu
 5256            .borrow()
 5257            .as_ref()
 5258            .and_then(|menu| match menu {
 5259                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5260                CodeContextMenu::CodeActions(_) => None,
 5261            });
 5262
 5263        match completions_source {
 5264            Some(CompletionsMenuSource::Words { .. }) => {
 5265                self.open_or_update_completions_menu(
 5266                    Some(CompletionsMenuSource::Words {
 5267                        ignore_threshold: false,
 5268                    }),
 5269                    None,
 5270                    trigger_in_words,
 5271                    window,
 5272                    cx,
 5273                );
 5274            }
 5275            _ => self.open_or_update_completions_menu(
 5276                None,
 5277                Some(text.to_owned()).filter(|x| !x.is_empty()),
 5278                true,
 5279                window,
 5280                cx,
 5281            ),
 5282        }
 5283    }
 5284
 5285    /// If any empty selections is touching the start of its innermost containing autoclose
 5286    /// region, expand it to select the brackets.
 5287    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5288        let selections = self
 5289            .selections
 5290            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 5291        let buffer = self.buffer.read(cx).read(cx);
 5292        let new_selections = self
 5293            .selections_with_autoclose_regions(selections, &buffer)
 5294            .map(|(mut selection, region)| {
 5295                if !selection.is_empty() {
 5296                    return selection;
 5297                }
 5298
 5299                if let Some(region) = region {
 5300                    let mut range = region.range.to_offset(&buffer);
 5301                    if selection.start == range.start && range.start.0 >= region.pair.start.len() {
 5302                        range.start -= region.pair.start.len();
 5303                        if buffer.contains_str_at(range.start, &region.pair.start)
 5304                            && buffer.contains_str_at(range.end, &region.pair.end)
 5305                        {
 5306                            range.end += region.pair.end.len();
 5307                            selection.start = range.start;
 5308                            selection.end = range.end;
 5309
 5310                            return selection;
 5311                        }
 5312                    }
 5313                }
 5314
 5315                let always_treat_brackets_as_autoclosed = buffer
 5316                    .language_settings_at(selection.start, cx)
 5317                    .always_treat_brackets_as_autoclosed;
 5318
 5319                if !always_treat_brackets_as_autoclosed {
 5320                    return selection;
 5321                }
 5322
 5323                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5324                    for (pair, enabled) in scope.brackets() {
 5325                        if !enabled || !pair.close {
 5326                            continue;
 5327                        }
 5328
 5329                        if buffer.contains_str_at(selection.start, &pair.end) {
 5330                            let pair_start_len = pair.start.len();
 5331                            if buffer.contains_str_at(
 5332                                selection.start.saturating_sub_usize(pair_start_len),
 5333                                &pair.start,
 5334                            ) {
 5335                                selection.start -= pair_start_len;
 5336                                selection.end += pair.end.len();
 5337
 5338                                return selection;
 5339                            }
 5340                        }
 5341                    }
 5342                }
 5343
 5344                selection
 5345            })
 5346            .collect();
 5347
 5348        drop(buffer);
 5349        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5350            selections.select(new_selections)
 5351        });
 5352    }
 5353
 5354    /// Iterate the given selections, and for each one, find the smallest surrounding
 5355    /// autoclose region. This uses the ordering of the selections and the autoclose
 5356    /// regions to avoid repeated comparisons.
 5357    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5358        &'a self,
 5359        selections: impl IntoIterator<Item = Selection<D>>,
 5360        buffer: &'a MultiBufferSnapshot,
 5361    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5362        let mut i = 0;
 5363        let mut regions = self.autoclose_regions.as_slice();
 5364        selections.into_iter().map(move |selection| {
 5365            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5366
 5367            let mut enclosing = None;
 5368            while let Some(pair_state) = regions.get(i) {
 5369                if pair_state.range.end.to_offset(buffer) < range.start {
 5370                    regions = &regions[i + 1..];
 5371                    i = 0;
 5372                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5373                    break;
 5374                } else {
 5375                    if pair_state.selection_id == selection.id {
 5376                        enclosing = Some(pair_state);
 5377                    }
 5378                    i += 1;
 5379                }
 5380            }
 5381
 5382            (selection, enclosing)
 5383        })
 5384    }
 5385
 5386    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5387    fn invalidate_autoclose_regions(
 5388        &mut self,
 5389        mut selections: &[Selection<Anchor>],
 5390        buffer: &MultiBufferSnapshot,
 5391    ) {
 5392        self.autoclose_regions.retain(|state| {
 5393            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5394                return false;
 5395            }
 5396
 5397            let mut i = 0;
 5398            while let Some(selection) = selections.get(i) {
 5399                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5400                    selections = &selections[1..];
 5401                    continue;
 5402                }
 5403                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5404                    break;
 5405                }
 5406                if selection.id == state.selection_id {
 5407                    return true;
 5408                } else {
 5409                    i += 1;
 5410                }
 5411            }
 5412            false
 5413        });
 5414    }
 5415
 5416    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5417        let offset = position.to_offset(buffer);
 5418        let (word_range, kind) =
 5419            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5420        if offset > word_range.start && kind == Some(CharKind::Word) {
 5421            Some(
 5422                buffer
 5423                    .text_for_range(word_range.start..offset)
 5424                    .collect::<String>(),
 5425            )
 5426        } else {
 5427            None
 5428        }
 5429    }
 5430
 5431    pub fn visible_excerpts(
 5432        &self,
 5433        lsp_related_only: bool,
 5434        cx: &mut Context<Editor>,
 5435    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5436        let project = self.project().cloned();
 5437        let multi_buffer = self.buffer().read(cx);
 5438        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5439        let multi_buffer_visible_start = self
 5440            .scroll_manager
 5441            .anchor()
 5442            .anchor
 5443            .to_point(&multi_buffer_snapshot);
 5444        let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 5445            multi_buffer_visible_start
 5446                + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 5447            Bias::Left,
 5448        );
 5449        multi_buffer_snapshot
 5450            .range_to_buffer_ranges(multi_buffer_visible_start..multi_buffer_visible_end)
 5451            .into_iter()
 5452            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5453            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5454                if !lsp_related_only {
 5455                    return Some((
 5456                        excerpt_id,
 5457                        (
 5458                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5459                            buffer.version().clone(),
 5460                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5461                        ),
 5462                    ));
 5463                }
 5464
 5465                let project = project.as_ref()?.read(cx);
 5466                let buffer_file = project::File::from_dyn(buffer.file())?;
 5467                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5468                let worktree_entry = buffer_worktree
 5469                    .read(cx)
 5470                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5471                if worktree_entry.is_ignored {
 5472                    None
 5473                } else {
 5474                    Some((
 5475                        excerpt_id,
 5476                        (
 5477                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5478                            buffer.version().clone(),
 5479                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5480                        ),
 5481                    ))
 5482                }
 5483            })
 5484            .collect()
 5485    }
 5486
 5487    pub fn text_layout_details(&self, window: &mut Window) -> TextLayoutDetails {
 5488        TextLayoutDetails {
 5489            text_system: window.text_system().clone(),
 5490            editor_style: self.style.clone().unwrap(),
 5491            rem_size: window.rem_size(),
 5492            scroll_anchor: self.scroll_manager.anchor(),
 5493            visible_rows: self.visible_line_count(),
 5494            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5495        }
 5496    }
 5497
 5498    fn trigger_on_type_formatting(
 5499        &self,
 5500        input: String,
 5501        window: &mut Window,
 5502        cx: &mut Context<Self>,
 5503    ) -> Option<Task<Result<()>>> {
 5504        if input.chars().count() != 1 {
 5505            return None;
 5506        }
 5507
 5508        let project = self.project()?;
 5509        let position = self.selections.newest_anchor().head();
 5510        let (buffer, buffer_position) = self
 5511            .buffer
 5512            .read(cx)
 5513            .text_anchor_for_position(position, cx)?;
 5514
 5515        let settings = language_settings::language_settings(
 5516            buffer
 5517                .read(cx)
 5518                .language_at(buffer_position)
 5519                .map(|l| l.name()),
 5520            buffer.read(cx).file(),
 5521            cx,
 5522        );
 5523        if !settings.use_on_type_format {
 5524            return None;
 5525        }
 5526
 5527        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5528        // hence we do LSP request & edit on host side only — add formats to host's history.
 5529        let push_to_lsp_host_history = true;
 5530        // If this is not the host, append its history with new edits.
 5531        let push_to_client_history = project.read(cx).is_via_collab();
 5532
 5533        let on_type_formatting = project.update(cx, |project, cx| {
 5534            project.on_type_format(
 5535                buffer.clone(),
 5536                buffer_position,
 5537                input,
 5538                push_to_lsp_host_history,
 5539                cx,
 5540            )
 5541        });
 5542        Some(cx.spawn_in(window, async move |editor, cx| {
 5543            if let Some(transaction) = on_type_formatting.await? {
 5544                if push_to_client_history {
 5545                    buffer
 5546                        .update(cx, |buffer, _| {
 5547                            buffer.push_transaction(transaction, Instant::now());
 5548                            buffer.finalize_last_transaction();
 5549                        })
 5550                        .ok();
 5551                }
 5552                editor.update(cx, |editor, cx| {
 5553                    editor.refresh_document_highlights(cx);
 5554                })?;
 5555            }
 5556            Ok(())
 5557        }))
 5558    }
 5559
 5560    pub fn show_word_completions(
 5561        &mut self,
 5562        _: &ShowWordCompletions,
 5563        window: &mut Window,
 5564        cx: &mut Context<Self>,
 5565    ) {
 5566        self.open_or_update_completions_menu(
 5567            Some(CompletionsMenuSource::Words {
 5568                ignore_threshold: true,
 5569            }),
 5570            None,
 5571            false,
 5572            window,
 5573            cx,
 5574        );
 5575    }
 5576
 5577    pub fn show_completions(
 5578        &mut self,
 5579        _: &ShowCompletions,
 5580        window: &mut Window,
 5581        cx: &mut Context<Self>,
 5582    ) {
 5583        self.open_or_update_completions_menu(None, None, false, window, cx);
 5584    }
 5585
 5586    fn open_or_update_completions_menu(
 5587        &mut self,
 5588        requested_source: Option<CompletionsMenuSource>,
 5589        trigger: Option<String>,
 5590        trigger_in_words: bool,
 5591        window: &mut Window,
 5592        cx: &mut Context<Self>,
 5593    ) {
 5594        if self.pending_rename.is_some() {
 5595            return;
 5596        }
 5597
 5598        let completions_source = self
 5599            .context_menu
 5600            .borrow()
 5601            .as_ref()
 5602            .and_then(|menu| match menu {
 5603                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5604                CodeContextMenu::CodeActions(_) => None,
 5605            });
 5606
 5607        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5608
 5609        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5610        // inserted and selected. To handle that case, the start of the selection is used so that
 5611        // the menu starts with all choices.
 5612        let position = self
 5613            .selections
 5614            .newest_anchor()
 5615            .start
 5616            .bias_right(&multibuffer_snapshot);
 5617        if position.diff_base_anchor.is_some() {
 5618            return;
 5619        }
 5620        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5621        let Some(buffer) = buffer_position
 5622            .text_anchor
 5623            .buffer_id
 5624            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5625        else {
 5626            return;
 5627        };
 5628        let buffer_snapshot = buffer.read(cx).snapshot();
 5629
 5630        let menu_is_open = matches!(
 5631            self.context_menu.borrow().as_ref(),
 5632            Some(CodeContextMenu::Completions(_))
 5633        );
 5634
 5635        let language = buffer_snapshot
 5636            .language_at(buffer_position.text_anchor)
 5637            .map(|language| language.name());
 5638
 5639        let language_settings = language_settings(language.clone(), buffer_snapshot.file(), cx);
 5640        let completion_settings = language_settings.completions.clone();
 5641
 5642        let show_completions_on_input = self
 5643            .show_completions_on_input_override
 5644            .unwrap_or(language_settings.show_completions_on_input);
 5645        if !menu_is_open && trigger.is_some() && !show_completions_on_input {
 5646            return;
 5647        }
 5648
 5649        let query: Option<Arc<String>> =
 5650            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5651                .map(|query| query.into());
 5652
 5653        drop(multibuffer_snapshot);
 5654
 5655        // Hide the current completions menu when query is empty. Without this, cached
 5656        // completions from before the trigger char may be reused (#32774).
 5657        if query.is_none() && menu_is_open {
 5658            self.hide_context_menu(window, cx);
 5659        }
 5660
 5661        let mut ignore_word_threshold = false;
 5662        let provider = match requested_source {
 5663            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5664            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5665                ignore_word_threshold = ignore_threshold;
 5666                None
 5667            }
 5668            Some(CompletionsMenuSource::SnippetChoices)
 5669            | Some(CompletionsMenuSource::SnippetsOnly) => {
 5670                log::error!("bug: SnippetChoices requested_source is not handled");
 5671                None
 5672            }
 5673        };
 5674
 5675        let sort_completions = provider
 5676            .as_ref()
 5677            .is_some_and(|provider| provider.sort_completions());
 5678
 5679        let filter_completions = provider
 5680            .as_ref()
 5681            .is_none_or(|provider| provider.filter_completions());
 5682
 5683        let was_snippets_only = matches!(
 5684            completions_source,
 5685            Some(CompletionsMenuSource::SnippetsOnly)
 5686        );
 5687
 5688        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5689            if filter_completions {
 5690                menu.filter(
 5691                    query.clone().unwrap_or_default(),
 5692                    buffer_position.text_anchor,
 5693                    &buffer,
 5694                    provider.clone(),
 5695                    window,
 5696                    cx,
 5697                );
 5698            }
 5699            // When `is_incomplete` is false, no need to re-query completions when the current query
 5700            // is a suffix of the initial query.
 5701            let was_complete = !menu.is_incomplete;
 5702            if was_complete && !was_snippets_only {
 5703                // If the new query is a suffix of the old query (typing more characters) and
 5704                // the previous result was complete, the existing completions can be filtered.
 5705                //
 5706                // Note that snippet completions are always complete.
 5707                let query_matches = match (&menu.initial_query, &query) {
 5708                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 5709                    (None, _) => true,
 5710                    _ => false,
 5711                };
 5712                if query_matches {
 5713                    let position_matches = if menu.initial_position == position {
 5714                        true
 5715                    } else {
 5716                        let snapshot = self.buffer.read(cx).read(cx);
 5717                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 5718                    };
 5719                    if position_matches {
 5720                        return;
 5721                    }
 5722                }
 5723            }
 5724        };
 5725
 5726        let Anchor {
 5727            excerpt_id: buffer_excerpt_id,
 5728            text_anchor: buffer_position,
 5729            ..
 5730        } = buffer_position;
 5731
 5732        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 5733            buffer_snapshot.surrounding_word(buffer_position, None)
 5734        {
 5735            let word_to_exclude = buffer_snapshot
 5736                .text_for_range(word_range.clone())
 5737                .collect::<String>();
 5738            (
 5739                buffer_snapshot.anchor_before(word_range.start)
 5740                    ..buffer_snapshot.anchor_after(buffer_position),
 5741                Some(word_to_exclude),
 5742            )
 5743        } else {
 5744            (buffer_position..buffer_position, None)
 5745        };
 5746
 5747        let show_completion_documentation = buffer_snapshot
 5748            .settings_at(buffer_position, cx)
 5749            .show_completion_documentation;
 5750
 5751        // The document can be large, so stay in reasonable bounds when searching for words,
 5752        // otherwise completion pop-up might be slow to appear.
 5753        const WORD_LOOKUP_ROWS: u32 = 5_000;
 5754        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 5755        let min_word_search = buffer_snapshot.clip_point(
 5756            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 5757            Bias::Left,
 5758        );
 5759        let max_word_search = buffer_snapshot.clip_point(
 5760            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 5761            Bias::Right,
 5762        );
 5763        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 5764            ..buffer_snapshot.point_to_offset(max_word_search);
 5765
 5766        let skip_digits = query
 5767            .as_ref()
 5768            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 5769
 5770        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 5771            trigger.as_ref().is_none_or(|trigger| {
 5772                provider.is_completion_trigger(
 5773                    &buffer,
 5774                    position.text_anchor,
 5775                    trigger,
 5776                    trigger_in_words,
 5777                    cx,
 5778                )
 5779            })
 5780        });
 5781
 5782        let provider_responses = if let Some(provider) = &provider
 5783            && load_provider_completions
 5784        {
 5785            let trigger_character =
 5786                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 5787            let completion_context = CompletionContext {
 5788                trigger_kind: match &trigger_character {
 5789                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 5790                    None => CompletionTriggerKind::INVOKED,
 5791                },
 5792                trigger_character,
 5793            };
 5794
 5795            provider.completions(
 5796                buffer_excerpt_id,
 5797                &buffer,
 5798                buffer_position,
 5799                completion_context,
 5800                window,
 5801                cx,
 5802            )
 5803        } else {
 5804            Task::ready(Ok(Vec::new()))
 5805        };
 5806
 5807        let load_word_completions = if !self.word_completions_enabled {
 5808            false
 5809        } else if requested_source
 5810            == Some(CompletionsMenuSource::Words {
 5811                ignore_threshold: true,
 5812            })
 5813        {
 5814            true
 5815        } else {
 5816            load_provider_completions
 5817                && completion_settings.words != WordsCompletionMode::Disabled
 5818                && (ignore_word_threshold || {
 5819                    let words_min_length = completion_settings.words_min_length;
 5820                    // check whether word has at least `words_min_length` characters
 5821                    let query_chars = query.iter().flat_map(|q| q.chars());
 5822                    query_chars.take(words_min_length).count() == words_min_length
 5823                })
 5824        };
 5825
 5826        let mut words = if load_word_completions {
 5827            cx.background_spawn({
 5828                let buffer_snapshot = buffer_snapshot.clone();
 5829                async move {
 5830                    buffer_snapshot.words_in_range(WordsQuery {
 5831                        fuzzy_contents: None,
 5832                        range: word_search_range,
 5833                        skip_digits,
 5834                    })
 5835                }
 5836            })
 5837        } else {
 5838            Task::ready(BTreeMap::default())
 5839        };
 5840
 5841        let snippets = if let Some(provider) = &provider
 5842            && provider.show_snippets()
 5843            && let Some(project) = self.project()
 5844        {
 5845            let char_classifier = buffer_snapshot
 5846                .char_classifier_at(buffer_position)
 5847                .scope_context(Some(CharScopeContext::Completion));
 5848            project.update(cx, |project, cx| {
 5849                snippet_completions(project, &buffer, buffer_position, char_classifier, cx)
 5850            })
 5851        } else {
 5852            Task::ready(Ok(CompletionResponse {
 5853                completions: Vec::new(),
 5854                display_options: Default::default(),
 5855                is_incomplete: false,
 5856            }))
 5857        };
 5858
 5859        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 5860
 5861        let id = post_inc(&mut self.next_completion_id);
 5862        let task = cx.spawn_in(window, async move |editor, cx| {
 5863            let Ok(()) = editor.update(cx, |this, _| {
 5864                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 5865            }) else {
 5866                return;
 5867            };
 5868
 5869            // TODO: Ideally completions from different sources would be selectively re-queried, so
 5870            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 5871            let mut completions = Vec::new();
 5872            let mut is_incomplete = false;
 5873            let mut display_options: Option<CompletionDisplayOptions> = None;
 5874            if let Some(provider_responses) = provider_responses.await.log_err()
 5875                && !provider_responses.is_empty()
 5876            {
 5877                for response in provider_responses {
 5878                    completions.extend(response.completions);
 5879                    is_incomplete = is_incomplete || response.is_incomplete;
 5880                    match display_options.as_mut() {
 5881                        None => {
 5882                            display_options = Some(response.display_options);
 5883                        }
 5884                        Some(options) => options.merge(&response.display_options),
 5885                    }
 5886                }
 5887                if completion_settings.words == WordsCompletionMode::Fallback {
 5888                    words = Task::ready(BTreeMap::default());
 5889                }
 5890            }
 5891            let display_options = display_options.unwrap_or_default();
 5892
 5893            let mut words = words.await;
 5894            if let Some(word_to_exclude) = &word_to_exclude {
 5895                words.remove(word_to_exclude);
 5896            }
 5897            for lsp_completion in &completions {
 5898                words.remove(&lsp_completion.new_text);
 5899            }
 5900            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 5901                replace_range: word_replace_range.clone(),
 5902                new_text: word.clone(),
 5903                label: CodeLabel::plain(word, None),
 5904                match_start: None,
 5905                snippet_deduplication_key: None,
 5906                icon_path: None,
 5907                documentation: None,
 5908                source: CompletionSource::BufferWord {
 5909                    word_range,
 5910                    resolved: false,
 5911                },
 5912                insert_text_mode: Some(InsertTextMode::AS_IS),
 5913                confirm: None,
 5914            }));
 5915
 5916            completions.extend(
 5917                snippets
 5918                    .await
 5919                    .into_iter()
 5920                    .flat_map(|response| response.completions),
 5921            );
 5922
 5923            let menu = if completions.is_empty() {
 5924                None
 5925            } else {
 5926                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 5927                    let languages = editor
 5928                        .workspace
 5929                        .as_ref()
 5930                        .and_then(|(workspace, _)| workspace.upgrade())
 5931                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 5932                    let menu = CompletionsMenu::new(
 5933                        id,
 5934                        requested_source.unwrap_or(if load_provider_completions {
 5935                            CompletionsMenuSource::Normal
 5936                        } else {
 5937                            CompletionsMenuSource::SnippetsOnly
 5938                        }),
 5939                        sort_completions,
 5940                        show_completion_documentation,
 5941                        position,
 5942                        query.clone(),
 5943                        is_incomplete,
 5944                        buffer.clone(),
 5945                        completions.into(),
 5946                        editor
 5947                            .context_menu()
 5948                            .borrow_mut()
 5949                            .as_ref()
 5950                            .map(|menu| menu.primary_scroll_handle()),
 5951                        display_options,
 5952                        snippet_sort_order,
 5953                        languages,
 5954                        language,
 5955                        cx,
 5956                    );
 5957
 5958                    let query = if filter_completions { query } else { None };
 5959                    let matches_task = menu.do_async_filtering(
 5960                        query.unwrap_or_default(),
 5961                        buffer_position,
 5962                        &buffer,
 5963                        cx,
 5964                    );
 5965                    (menu, matches_task)
 5966                }) else {
 5967                    return;
 5968                };
 5969
 5970                let matches = matches_task.await;
 5971
 5972                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 5973                    // Newer menu already set, so exit.
 5974                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5975                        editor.context_menu.borrow().as_ref()
 5976                        && prev_menu.id > id
 5977                    {
 5978                        return;
 5979                    };
 5980
 5981                    // Only valid to take prev_menu because either the new menu is immediately set
 5982                    // below, or the menu is hidden.
 5983                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 5984                        editor.context_menu.borrow_mut().take()
 5985                    {
 5986                        let position_matches =
 5987                            if prev_menu.initial_position == menu.initial_position {
 5988                                true
 5989                            } else {
 5990                                let snapshot = editor.buffer.read(cx).read(cx);
 5991                                prev_menu.initial_position.to_offset(&snapshot)
 5992                                    == menu.initial_position.to_offset(&snapshot)
 5993                            };
 5994                        if position_matches {
 5995                            // Preserve markdown cache before `set_filter_results` because it will
 5996                            // try to populate the documentation cache.
 5997                            menu.preserve_markdown_cache(prev_menu);
 5998                        }
 5999                    };
 6000
 6001                    menu.set_filter_results(matches, provider, window, cx);
 6002                }) else {
 6003                    return;
 6004                };
 6005
 6006                menu.visible().then_some(menu)
 6007            };
 6008
 6009            editor
 6010                .update_in(cx, |editor, window, cx| {
 6011                    if editor.focus_handle.is_focused(window)
 6012                        && let Some(menu) = menu
 6013                    {
 6014                        *editor.context_menu.borrow_mut() =
 6015                            Some(CodeContextMenu::Completions(menu));
 6016
 6017                        crate::hover_popover::hide_hover(editor, cx);
 6018                        if editor.show_edit_predictions_in_menu() {
 6019                            editor.update_visible_edit_prediction(window, cx);
 6020                        } else {
 6021                            editor.discard_edit_prediction(false, cx);
 6022                        }
 6023
 6024                        cx.notify();
 6025                        return;
 6026                    }
 6027
 6028                    if editor.completion_tasks.len() <= 1 {
 6029                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 6030                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 6031                        // If it was already hidden and we don't show edit predictions in the menu,
 6032                        // we should also show the edit prediction when available.
 6033                        if was_hidden && editor.show_edit_predictions_in_menu() {
 6034                            editor.update_visible_edit_prediction(window, cx);
 6035                        }
 6036                    }
 6037                })
 6038                .ok();
 6039        });
 6040
 6041        self.completion_tasks.push((id, task));
 6042    }
 6043
 6044    #[cfg(feature = "test-support")]
 6045    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 6046        let menu = self.context_menu.borrow();
 6047        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 6048            let completions = menu.completions.borrow();
 6049            Some(completions.to_vec())
 6050        } else {
 6051            None
 6052        }
 6053    }
 6054
 6055    pub fn with_completions_menu_matching_id<R>(
 6056        &self,
 6057        id: CompletionId,
 6058        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 6059    ) -> R {
 6060        let mut context_menu = self.context_menu.borrow_mut();
 6061        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 6062            return f(None);
 6063        };
 6064        if completions_menu.id != id {
 6065            return f(None);
 6066        }
 6067        f(Some(completions_menu))
 6068    }
 6069
 6070    pub fn confirm_completion(
 6071        &mut self,
 6072        action: &ConfirmCompletion,
 6073        window: &mut Window,
 6074        cx: &mut Context<Self>,
 6075    ) -> Option<Task<Result<()>>> {
 6076        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6077        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 6078    }
 6079
 6080    pub fn confirm_completion_insert(
 6081        &mut self,
 6082        _: &ConfirmCompletionInsert,
 6083        window: &mut Window,
 6084        cx: &mut Context<Self>,
 6085    ) -> Option<Task<Result<()>>> {
 6086        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6087        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 6088    }
 6089
 6090    pub fn confirm_completion_replace(
 6091        &mut self,
 6092        _: &ConfirmCompletionReplace,
 6093        window: &mut Window,
 6094        cx: &mut Context<Self>,
 6095    ) -> Option<Task<Result<()>>> {
 6096        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6097        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 6098    }
 6099
 6100    pub fn compose_completion(
 6101        &mut self,
 6102        action: &ComposeCompletion,
 6103        window: &mut Window,
 6104        cx: &mut Context<Self>,
 6105    ) -> Option<Task<Result<()>>> {
 6106        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6107        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 6108    }
 6109
 6110    fn do_completion(
 6111        &mut self,
 6112        item_ix: Option<usize>,
 6113        intent: CompletionIntent,
 6114        window: &mut Window,
 6115        cx: &mut Context<Editor>,
 6116    ) -> Option<Task<Result<()>>> {
 6117        use language::ToOffset as _;
 6118
 6119        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 6120        else {
 6121            return None;
 6122        };
 6123
 6124        let candidate_id = {
 6125            let entries = completions_menu.entries.borrow();
 6126            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 6127            if self.show_edit_predictions_in_menu() {
 6128                self.discard_edit_prediction(true, cx);
 6129            }
 6130            mat.candidate_id
 6131        };
 6132
 6133        let completion = completions_menu
 6134            .completions
 6135            .borrow()
 6136            .get(candidate_id)?
 6137            .clone();
 6138        cx.stop_propagation();
 6139
 6140        let buffer_handle = completions_menu.buffer.clone();
 6141
 6142        let CompletionEdit {
 6143            new_text,
 6144            snippet,
 6145            replace_range,
 6146        } = process_completion_for_edit(
 6147            &completion,
 6148            intent,
 6149            &buffer_handle,
 6150            &completions_menu.initial_position.text_anchor,
 6151            cx,
 6152        );
 6153
 6154        let buffer = buffer_handle.read(cx);
 6155        let snapshot = self.buffer.read(cx).snapshot(cx);
 6156        let newest_anchor = self.selections.newest_anchor();
 6157        let replace_range_multibuffer = {
 6158            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 6159            excerpt.map_range_from_buffer(replace_range.clone())
 6160        };
 6161        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6162            return None;
 6163        }
 6164
 6165        let old_text = buffer
 6166            .text_for_range(replace_range.clone())
 6167            .collect::<String>();
 6168        let lookbehind = newest_anchor
 6169            .start
 6170            .text_anchor
 6171            .to_offset(buffer)
 6172            .saturating_sub(replace_range.start.0);
 6173        let lookahead = replace_range
 6174            .end
 6175            .0
 6176            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6177        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6178        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6179
 6180        let selections = self
 6181            .selections
 6182            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 6183        let mut ranges = Vec::new();
 6184        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 6185
 6186        for selection in &selections {
 6187            let range = if selection.id == newest_anchor.id {
 6188                replace_range_multibuffer.clone()
 6189            } else {
 6190                let mut range = selection.range();
 6191
 6192                // if prefix is present, don't duplicate it
 6193                if snapshot.contains_str_at(range.start.saturating_sub_usize(lookbehind), prefix) {
 6194                    range.start = range.start.saturating_sub_usize(lookbehind);
 6195
 6196                    // if suffix is also present, mimic the newest cursor and replace it
 6197                    if selection.id != newest_anchor.id
 6198                        && snapshot.contains_str_at(range.end, suffix)
 6199                    {
 6200                        range.end += lookahead;
 6201                    }
 6202                }
 6203                range
 6204            };
 6205
 6206            ranges.push(range.clone());
 6207
 6208            if !self.linked_edit_ranges.is_empty() {
 6209                let start_anchor = snapshot.anchor_before(range.start);
 6210                let end_anchor = snapshot.anchor_after(range.end);
 6211                if let Some(ranges) = self
 6212                    .linked_editing_ranges_for(start_anchor.text_anchor..end_anchor.text_anchor, cx)
 6213                {
 6214                    for (buffer, edits) in ranges {
 6215                        linked_edits
 6216                            .entry(buffer.clone())
 6217                            .or_default()
 6218                            .extend(edits.into_iter().map(|range| (range, new_text.to_owned())));
 6219                    }
 6220                }
 6221            }
 6222        }
 6223
 6224        let common_prefix_len = old_text
 6225            .chars()
 6226            .zip(new_text.chars())
 6227            .take_while(|(a, b)| a == b)
 6228            .map(|(a, _)| a.len_utf8())
 6229            .sum::<usize>();
 6230
 6231        cx.emit(EditorEvent::InputHandled {
 6232            utf16_range_to_replace: None,
 6233            text: new_text[common_prefix_len..].into(),
 6234        });
 6235
 6236        self.transact(window, cx, |editor, window, cx| {
 6237            if let Some(mut snippet) = snippet {
 6238                snippet.text = new_text.to_string();
 6239                editor
 6240                    .insert_snippet(&ranges, snippet, window, cx)
 6241                    .log_err();
 6242            } else {
 6243                editor.buffer.update(cx, |multi_buffer, cx| {
 6244                    let auto_indent = match completion.insert_text_mode {
 6245                        Some(InsertTextMode::AS_IS) => None,
 6246                        _ => editor.autoindent_mode.clone(),
 6247                    };
 6248                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6249                    multi_buffer.edit(edits, auto_indent, cx);
 6250                });
 6251            }
 6252            for (buffer, edits) in linked_edits {
 6253                buffer.update(cx, |buffer, cx| {
 6254                    let snapshot = buffer.snapshot();
 6255                    let edits = edits
 6256                        .into_iter()
 6257                        .map(|(range, text)| {
 6258                            use text::ToPoint as TP;
 6259                            let end_point = TP::to_point(&range.end, &snapshot);
 6260                            let start_point = TP::to_point(&range.start, &snapshot);
 6261                            (start_point..end_point, text)
 6262                        })
 6263                        .sorted_by_key(|(range, _)| range.start);
 6264                    buffer.edit(edits, None, cx);
 6265                })
 6266            }
 6267
 6268            editor.refresh_edit_prediction(true, false, window, cx);
 6269        });
 6270        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6271
 6272        let show_new_completions_on_confirm = completion
 6273            .confirm
 6274            .as_ref()
 6275            .is_some_and(|confirm| confirm(intent, window, cx));
 6276        if show_new_completions_on_confirm {
 6277            self.open_or_update_completions_menu(None, None, false, window, cx);
 6278        }
 6279
 6280        let provider = self.completion_provider.as_ref()?;
 6281
 6282        let lsp_store = self.project().map(|project| project.read(cx).lsp_store());
 6283        let command = lsp_store.as_ref().and_then(|lsp_store| {
 6284            let CompletionSource::Lsp {
 6285                lsp_completion,
 6286                server_id,
 6287                ..
 6288            } = &completion.source
 6289            else {
 6290                return None;
 6291            };
 6292            let lsp_command = lsp_completion.command.as_ref()?;
 6293            let available_commands = lsp_store
 6294                .read(cx)
 6295                .lsp_server_capabilities
 6296                .get(server_id)
 6297                .and_then(|server_capabilities| {
 6298                    server_capabilities
 6299                        .execute_command_provider
 6300                        .as_ref()
 6301                        .map(|options| options.commands.as_slice())
 6302                })?;
 6303            if available_commands.contains(&lsp_command.command) {
 6304                Some(CodeAction {
 6305                    server_id: *server_id,
 6306                    range: language::Anchor::MIN..language::Anchor::MIN,
 6307                    lsp_action: LspAction::Command(lsp_command.clone()),
 6308                    resolved: false,
 6309                })
 6310            } else {
 6311                None
 6312            }
 6313        });
 6314
 6315        drop(completion);
 6316        let apply_edits = provider.apply_additional_edits_for_completion(
 6317            buffer_handle.clone(),
 6318            completions_menu.completions.clone(),
 6319            candidate_id,
 6320            true,
 6321            cx,
 6322        );
 6323
 6324        let editor_settings = EditorSettings::get_global(cx);
 6325        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6326            // After the code completion is finished, users often want to know what signatures are needed.
 6327            // so we should automatically call signature_help
 6328            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6329        }
 6330
 6331        Some(cx.spawn_in(window, async move |editor, cx| {
 6332            apply_edits.await?;
 6333
 6334            if let Some((lsp_store, command)) = lsp_store.zip(command) {
 6335                let title = command.lsp_action.title().to_owned();
 6336                let project_transaction = lsp_store
 6337                    .update(cx, |lsp_store, cx| {
 6338                        lsp_store.apply_code_action(buffer_handle, command, false, cx)
 6339                    })?
 6340                    .await
 6341                    .context("applying post-completion command")?;
 6342                if let Some(workspace) = editor.read_with(cx, |editor, _| editor.workspace())? {
 6343                    Self::open_project_transaction(
 6344                        &editor,
 6345                        workspace.downgrade(),
 6346                        project_transaction,
 6347                        title,
 6348                        cx,
 6349                    )
 6350                    .await?;
 6351                }
 6352            }
 6353
 6354            Ok(())
 6355        }))
 6356    }
 6357
 6358    pub fn toggle_code_actions(
 6359        &mut self,
 6360        action: &ToggleCodeActions,
 6361        window: &mut Window,
 6362        cx: &mut Context<Self>,
 6363    ) {
 6364        let quick_launch = action.quick_launch;
 6365        let mut context_menu = self.context_menu.borrow_mut();
 6366        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6367            if code_actions.deployed_from == action.deployed_from {
 6368                // Toggle if we're selecting the same one
 6369                *context_menu = None;
 6370                cx.notify();
 6371                return;
 6372            } else {
 6373                // Otherwise, clear it and start a new one
 6374                *context_menu = None;
 6375                cx.notify();
 6376            }
 6377        }
 6378        drop(context_menu);
 6379        let snapshot = self.snapshot(window, cx);
 6380        let deployed_from = action.deployed_from.clone();
 6381        let action = action.clone();
 6382        self.completion_tasks.clear();
 6383        self.discard_edit_prediction(false, cx);
 6384
 6385        let multibuffer_point = match &action.deployed_from {
 6386            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6387                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6388            }
 6389            _ => self
 6390                .selections
 6391                .newest::<Point>(&snapshot.display_snapshot)
 6392                .head(),
 6393        };
 6394        let Some((buffer, buffer_row)) = snapshot
 6395            .buffer_snapshot()
 6396            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6397            .and_then(|(buffer_snapshot, range)| {
 6398                self.buffer()
 6399                    .read(cx)
 6400                    .buffer(buffer_snapshot.remote_id())
 6401                    .map(|buffer| (buffer, range.start.row))
 6402            })
 6403        else {
 6404            return;
 6405        };
 6406        let buffer_id = buffer.read(cx).remote_id();
 6407        let tasks = self
 6408            .tasks
 6409            .get(&(buffer_id, buffer_row))
 6410            .map(|t| Arc::new(t.to_owned()));
 6411
 6412        if !self.focus_handle.is_focused(window) {
 6413            return;
 6414        }
 6415        let project = self.project.clone();
 6416
 6417        let code_actions_task = match deployed_from {
 6418            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6419            _ => self.code_actions(buffer_row, window, cx),
 6420        };
 6421
 6422        let runnable_task = match deployed_from {
 6423            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6424            _ => {
 6425                let mut task_context_task = Task::ready(None);
 6426                if let Some(tasks) = &tasks
 6427                    && let Some(project) = project
 6428                {
 6429                    task_context_task =
 6430                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6431                }
 6432
 6433                cx.spawn_in(window, {
 6434                    let buffer = buffer.clone();
 6435                    async move |editor, cx| {
 6436                        let task_context = task_context_task.await;
 6437
 6438                        let resolved_tasks =
 6439                            tasks
 6440                                .zip(task_context.clone())
 6441                                .map(|(tasks, task_context)| ResolvedTasks {
 6442                                    templates: tasks.resolve(&task_context).collect(),
 6443                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6444                                        multibuffer_point.row,
 6445                                        tasks.column,
 6446                                    )),
 6447                                });
 6448                        let debug_scenarios = editor
 6449                            .update(cx, |editor, cx| {
 6450                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6451                            })?
 6452                            .await;
 6453                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6454                    }
 6455                })
 6456            }
 6457        };
 6458
 6459        cx.spawn_in(window, async move |editor, cx| {
 6460            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6461            let code_actions = code_actions_task.await;
 6462            let spawn_straight_away = quick_launch
 6463                && resolved_tasks
 6464                    .as_ref()
 6465                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6466                && code_actions
 6467                    .as_ref()
 6468                    .is_none_or(|actions| actions.is_empty())
 6469                && debug_scenarios.is_empty();
 6470
 6471            editor.update_in(cx, |editor, window, cx| {
 6472                crate::hover_popover::hide_hover(editor, cx);
 6473                let actions = CodeActionContents::new(
 6474                    resolved_tasks,
 6475                    code_actions,
 6476                    debug_scenarios,
 6477                    task_context.unwrap_or_default(),
 6478                );
 6479
 6480                // Don't show the menu if there are no actions available
 6481                if actions.is_empty() {
 6482                    cx.notify();
 6483                    return Task::ready(Ok(()));
 6484                }
 6485
 6486                *editor.context_menu.borrow_mut() =
 6487                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6488                        buffer,
 6489                        actions,
 6490                        selected_item: Default::default(),
 6491                        scroll_handle: UniformListScrollHandle::default(),
 6492                        deployed_from,
 6493                    }));
 6494                cx.notify();
 6495                if spawn_straight_away
 6496                    && let Some(task) = editor.confirm_code_action(
 6497                        &ConfirmCodeAction { item_ix: Some(0) },
 6498                        window,
 6499                        cx,
 6500                    )
 6501                {
 6502                    return task;
 6503                }
 6504
 6505                Task::ready(Ok(()))
 6506            })
 6507        })
 6508        .detach_and_log_err(cx);
 6509    }
 6510
 6511    fn debug_scenarios(
 6512        &mut self,
 6513        resolved_tasks: &Option<ResolvedTasks>,
 6514        buffer: &Entity<Buffer>,
 6515        cx: &mut App,
 6516    ) -> Task<Vec<task::DebugScenario>> {
 6517        maybe!({
 6518            let project = self.project()?;
 6519            let dap_store = project.read(cx).dap_store();
 6520            let mut scenarios = vec![];
 6521            let resolved_tasks = resolved_tasks.as_ref()?;
 6522            let buffer = buffer.read(cx);
 6523            let language = buffer.language()?;
 6524            let file = buffer.file();
 6525            let debug_adapter = language_settings(language.name().into(), file, cx)
 6526                .debuggers
 6527                .first()
 6528                .map(SharedString::from)
 6529                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6530
 6531            dap_store.update(cx, |dap_store, cx| {
 6532                for (_, task) in &resolved_tasks.templates {
 6533                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6534                        task.original_task().clone(),
 6535                        debug_adapter.clone().into(),
 6536                        task.display_label().to_owned().into(),
 6537                        cx,
 6538                    );
 6539                    scenarios.push(maybe_scenario);
 6540                }
 6541            });
 6542            Some(cx.background_spawn(async move {
 6543                futures::future::join_all(scenarios)
 6544                    .await
 6545                    .into_iter()
 6546                    .flatten()
 6547                    .collect::<Vec<_>>()
 6548            }))
 6549        })
 6550        .unwrap_or_else(|| Task::ready(vec![]))
 6551    }
 6552
 6553    fn code_actions(
 6554        &mut self,
 6555        buffer_row: u32,
 6556        window: &mut Window,
 6557        cx: &mut Context<Self>,
 6558    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6559        let mut task = self.code_actions_task.take();
 6560        cx.spawn_in(window, async move |editor, cx| {
 6561            while let Some(prev_task) = task {
 6562                prev_task.await.log_err();
 6563                task = editor
 6564                    .update(cx, |this, _| this.code_actions_task.take())
 6565                    .ok()?;
 6566            }
 6567
 6568            editor
 6569                .update(cx, |editor, cx| {
 6570                    editor
 6571                        .available_code_actions
 6572                        .clone()
 6573                        .and_then(|(location, code_actions)| {
 6574                            let snapshot = location.buffer.read(cx).snapshot();
 6575                            let point_range = location.range.to_point(&snapshot);
 6576                            let point_range = point_range.start.row..=point_range.end.row;
 6577                            if point_range.contains(&buffer_row) {
 6578                                Some(code_actions)
 6579                            } else {
 6580                                None
 6581                            }
 6582                        })
 6583                })
 6584                .ok()
 6585                .flatten()
 6586        })
 6587    }
 6588
 6589    pub fn confirm_code_action(
 6590        &mut self,
 6591        action: &ConfirmCodeAction,
 6592        window: &mut Window,
 6593        cx: &mut Context<Self>,
 6594    ) -> Option<Task<Result<()>>> {
 6595        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6596
 6597        let actions_menu =
 6598            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6599                menu
 6600            } else {
 6601                return None;
 6602            };
 6603
 6604        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6605        let action = actions_menu.actions.get(action_ix)?;
 6606        let title = action.label();
 6607        let buffer = actions_menu.buffer;
 6608        let workspace = self.workspace()?;
 6609
 6610        match action {
 6611            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6612                workspace.update(cx, |workspace, cx| {
 6613                    workspace.schedule_resolved_task(
 6614                        task_source_kind,
 6615                        resolved_task,
 6616                        false,
 6617                        window,
 6618                        cx,
 6619                    );
 6620
 6621                    Some(Task::ready(Ok(())))
 6622                })
 6623            }
 6624            CodeActionsItem::CodeAction {
 6625                excerpt_id,
 6626                action,
 6627                provider,
 6628            } => {
 6629                let apply_code_action =
 6630                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6631                let workspace = workspace.downgrade();
 6632                Some(cx.spawn_in(window, async move |editor, cx| {
 6633                    let project_transaction = apply_code_action.await?;
 6634                    Self::open_project_transaction(
 6635                        &editor,
 6636                        workspace,
 6637                        project_transaction,
 6638                        title,
 6639                        cx,
 6640                    )
 6641                    .await
 6642                }))
 6643            }
 6644            CodeActionsItem::DebugScenario(scenario) => {
 6645                let context = actions_menu.actions.context;
 6646
 6647                workspace.update(cx, |workspace, cx| {
 6648                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6649                    workspace.start_debug_session(
 6650                        scenario,
 6651                        context,
 6652                        Some(buffer),
 6653                        None,
 6654                        window,
 6655                        cx,
 6656                    );
 6657                });
 6658                Some(Task::ready(Ok(())))
 6659            }
 6660        }
 6661    }
 6662
 6663    pub async fn open_project_transaction(
 6664        editor: &WeakEntity<Editor>,
 6665        workspace: WeakEntity<Workspace>,
 6666        transaction: ProjectTransaction,
 6667        title: String,
 6668        cx: &mut AsyncWindowContext,
 6669    ) -> Result<()> {
 6670        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6671        cx.update(|_, cx| {
 6672            entries.sort_unstable_by_key(|(buffer, _)| {
 6673                buffer.read(cx).file().map(|f| f.path().clone())
 6674            });
 6675        })?;
 6676        if entries.is_empty() {
 6677            return Ok(());
 6678        }
 6679
 6680        // If the project transaction's edits are all contained within this editor, then
 6681        // avoid opening a new editor to display them.
 6682
 6683        if let [(buffer, transaction)] = &*entries {
 6684            let excerpt = editor.update(cx, |editor, cx| {
 6685                editor
 6686                    .buffer()
 6687                    .read(cx)
 6688                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 6689            })?;
 6690            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 6691                && excerpted_buffer == *buffer
 6692            {
 6693                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 6694                    let excerpt_range = excerpt_range.to_offset(buffer);
 6695                    buffer
 6696                        .edited_ranges_for_transaction::<usize>(transaction)
 6697                        .all(|range| {
 6698                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 6699                        })
 6700                })?;
 6701
 6702                if all_edits_within_excerpt {
 6703                    return Ok(());
 6704                }
 6705            }
 6706        }
 6707
 6708        let mut ranges_to_highlight = Vec::new();
 6709        let excerpt_buffer = cx.new(|cx| {
 6710            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 6711            for (buffer_handle, transaction) in &entries {
 6712                let edited_ranges = buffer_handle
 6713                    .read(cx)
 6714                    .edited_ranges_for_transaction::<Point>(transaction)
 6715                    .collect::<Vec<_>>();
 6716                let (ranges, _) = multibuffer.set_excerpts_for_path(
 6717                    PathKey::for_buffer(buffer_handle, cx),
 6718                    buffer_handle.clone(),
 6719                    edited_ranges,
 6720                    multibuffer_context_lines(cx),
 6721                    cx,
 6722                );
 6723
 6724                ranges_to_highlight.extend(ranges);
 6725            }
 6726            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 6727            multibuffer
 6728        })?;
 6729
 6730        workspace.update_in(cx, |workspace, window, cx| {
 6731            let project = workspace.project().clone();
 6732            let editor =
 6733                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 6734            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 6735            editor.update(cx, |editor, cx| {
 6736                editor.highlight_background::<Self>(
 6737                    &ranges_to_highlight,
 6738                    |_, theme| theme.colors().editor_highlighted_line_background,
 6739                    cx,
 6740                );
 6741            });
 6742        })?;
 6743
 6744        Ok(())
 6745    }
 6746
 6747    pub fn clear_code_action_providers(&mut self) {
 6748        self.code_action_providers.clear();
 6749        self.available_code_actions.take();
 6750    }
 6751
 6752    pub fn add_code_action_provider(
 6753        &mut self,
 6754        provider: Rc<dyn CodeActionProvider>,
 6755        window: &mut Window,
 6756        cx: &mut Context<Self>,
 6757    ) {
 6758        if self
 6759            .code_action_providers
 6760            .iter()
 6761            .any(|existing_provider| existing_provider.id() == provider.id())
 6762        {
 6763            return;
 6764        }
 6765
 6766        self.code_action_providers.push(provider);
 6767        self.refresh_code_actions(window, cx);
 6768    }
 6769
 6770    pub fn remove_code_action_provider(
 6771        &mut self,
 6772        id: Arc<str>,
 6773        window: &mut Window,
 6774        cx: &mut Context<Self>,
 6775    ) {
 6776        self.code_action_providers
 6777            .retain(|provider| provider.id() != id);
 6778        self.refresh_code_actions(window, cx);
 6779    }
 6780
 6781    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 6782        !self.code_action_providers.is_empty()
 6783            && EditorSettings::get_global(cx).toolbar.code_actions
 6784    }
 6785
 6786    pub fn has_available_code_actions(&self) -> bool {
 6787        self.available_code_actions
 6788            .as_ref()
 6789            .is_some_and(|(_, actions)| !actions.is_empty())
 6790    }
 6791
 6792    fn render_inline_code_actions(
 6793        &self,
 6794        icon_size: ui::IconSize,
 6795        display_row: DisplayRow,
 6796        is_active: bool,
 6797        cx: &mut Context<Self>,
 6798    ) -> AnyElement {
 6799        let show_tooltip = !self.context_menu_visible();
 6800        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 6801            .icon_size(icon_size)
 6802            .shape(ui::IconButtonShape::Square)
 6803            .icon_color(ui::Color::Hidden)
 6804            .toggle_state(is_active)
 6805            .when(show_tooltip, |this| {
 6806                this.tooltip({
 6807                    let focus_handle = self.focus_handle.clone();
 6808                    move |_window, cx| {
 6809                        Tooltip::for_action_in(
 6810                            "Toggle Code Actions",
 6811                            &ToggleCodeActions {
 6812                                deployed_from: None,
 6813                                quick_launch: false,
 6814                            },
 6815                            &focus_handle,
 6816                            cx,
 6817                        )
 6818                    }
 6819                })
 6820            })
 6821            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 6822                window.focus(&editor.focus_handle(cx));
 6823                editor.toggle_code_actions(
 6824                    &crate::actions::ToggleCodeActions {
 6825                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 6826                            display_row,
 6827                        )),
 6828                        quick_launch: false,
 6829                    },
 6830                    window,
 6831                    cx,
 6832                );
 6833            }))
 6834            .into_any_element()
 6835    }
 6836
 6837    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 6838        &self.context_menu
 6839    }
 6840
 6841    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6842        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 6843            cx.background_executor()
 6844                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 6845                .await;
 6846
 6847            let (start_buffer, start, _, end, newest_selection) = this
 6848                .update(cx, |this, cx| {
 6849                    let newest_selection = this.selections.newest_anchor().clone();
 6850                    if newest_selection.head().diff_base_anchor.is_some() {
 6851                        return None;
 6852                    }
 6853                    let display_snapshot = this.display_snapshot(cx);
 6854                    let newest_selection_adjusted =
 6855                        this.selections.newest_adjusted(&display_snapshot);
 6856                    let buffer = this.buffer.read(cx);
 6857
 6858                    let (start_buffer, start) =
 6859                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 6860                    let (end_buffer, end) =
 6861                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 6862
 6863                    Some((start_buffer, start, end_buffer, end, newest_selection))
 6864                })?
 6865                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 6866                .context(
 6867                    "Expected selection to lie in a single buffer when refreshing code actions",
 6868                )?;
 6869            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 6870                let providers = this.code_action_providers.clone();
 6871                let tasks = this
 6872                    .code_action_providers
 6873                    .iter()
 6874                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 6875                    .collect::<Vec<_>>();
 6876                (providers, tasks)
 6877            })?;
 6878
 6879            let mut actions = Vec::new();
 6880            for (provider, provider_actions) in
 6881                providers.into_iter().zip(future::join_all(tasks).await)
 6882            {
 6883                if let Some(provider_actions) = provider_actions.log_err() {
 6884                    actions.extend(provider_actions.into_iter().map(|action| {
 6885                        AvailableCodeAction {
 6886                            excerpt_id: newest_selection.start.excerpt_id,
 6887                            action,
 6888                            provider: provider.clone(),
 6889                        }
 6890                    }));
 6891                }
 6892            }
 6893
 6894            this.update(cx, |this, cx| {
 6895                this.available_code_actions = if actions.is_empty() {
 6896                    None
 6897                } else {
 6898                    Some((
 6899                        Location {
 6900                            buffer: start_buffer,
 6901                            range: start..end,
 6902                        },
 6903                        actions.into(),
 6904                    ))
 6905                };
 6906                cx.notify();
 6907            })
 6908        }));
 6909    }
 6910
 6911    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 6912        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 6913            self.show_git_blame_inline = false;
 6914
 6915            self.show_git_blame_inline_delay_task =
 6916                Some(cx.spawn_in(window, async move |this, cx| {
 6917                    cx.background_executor().timer(delay).await;
 6918
 6919                    this.update(cx, |this, cx| {
 6920                        this.show_git_blame_inline = true;
 6921                        cx.notify();
 6922                    })
 6923                    .log_err();
 6924                }));
 6925        }
 6926    }
 6927
 6928    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 6929        let snapshot = self.snapshot(window, cx);
 6930        let cursor = self
 6931            .selections
 6932            .newest::<Point>(&snapshot.display_snapshot)
 6933            .head();
 6934        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 6935        else {
 6936            return;
 6937        };
 6938
 6939        if self.blame.is_none() {
 6940            self.start_git_blame(true, window, cx);
 6941        }
 6942        let Some(blame) = self.blame.as_ref() else {
 6943            return;
 6944        };
 6945
 6946        let row_info = RowInfo {
 6947            buffer_id: Some(buffer.remote_id()),
 6948            buffer_row: Some(point.row),
 6949            ..Default::default()
 6950        };
 6951        let Some((buffer, blame_entry)) = blame
 6952            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 6953            .flatten()
 6954        else {
 6955            return;
 6956        };
 6957
 6958        let anchor = self.selections.newest_anchor().head();
 6959        let position = self.to_pixel_point(anchor, &snapshot, window, cx);
 6960        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 6961            self.show_blame_popover(
 6962                buffer,
 6963                &blame_entry,
 6964                position + last_bounds.origin,
 6965                true,
 6966                cx,
 6967            );
 6968        };
 6969    }
 6970
 6971    fn show_blame_popover(
 6972        &mut self,
 6973        buffer: BufferId,
 6974        blame_entry: &BlameEntry,
 6975        position: gpui::Point<Pixels>,
 6976        ignore_timeout: bool,
 6977        cx: &mut Context<Self>,
 6978    ) {
 6979        if let Some(state) = &mut self.inline_blame_popover {
 6980            state.hide_task.take();
 6981        } else {
 6982            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 6983            let blame_entry = blame_entry.clone();
 6984            let show_task = cx.spawn(async move |editor, cx| {
 6985                if !ignore_timeout {
 6986                    cx.background_executor()
 6987                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 6988                        .await;
 6989                }
 6990                editor
 6991                    .update(cx, |editor, cx| {
 6992                        editor.inline_blame_popover_show_task.take();
 6993                        let Some(blame) = editor.blame.as_ref() else {
 6994                            return;
 6995                        };
 6996                        let blame = blame.read(cx);
 6997                        let details = blame.details_for_entry(buffer, &blame_entry);
 6998                        let markdown = cx.new(|cx| {
 6999                            Markdown::new(
 7000                                details
 7001                                    .as_ref()
 7002                                    .map(|message| message.message.clone())
 7003                                    .unwrap_or_default(),
 7004                                None,
 7005                                None,
 7006                                cx,
 7007                            )
 7008                        });
 7009                        editor.inline_blame_popover = Some(InlineBlamePopover {
 7010                            position,
 7011                            hide_task: None,
 7012                            popover_bounds: None,
 7013                            popover_state: InlineBlamePopoverState {
 7014                                scroll_handle: ScrollHandle::new(),
 7015                                commit_message: details,
 7016                                markdown,
 7017                            },
 7018                            keyboard_grace: ignore_timeout,
 7019                        });
 7020                        cx.notify();
 7021                    })
 7022                    .ok();
 7023            });
 7024            self.inline_blame_popover_show_task = Some(show_task);
 7025        }
 7026    }
 7027
 7028    pub fn has_mouse_context_menu(&self) -> bool {
 7029        self.mouse_context_menu.is_some()
 7030    }
 7031
 7032    pub fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 7033        self.inline_blame_popover_show_task.take();
 7034        if let Some(state) = &mut self.inline_blame_popover {
 7035            let hide_task = cx.spawn(async move |editor, cx| {
 7036                if !ignore_timeout {
 7037                    cx.background_executor()
 7038                        .timer(std::time::Duration::from_millis(100))
 7039                        .await;
 7040                }
 7041                editor
 7042                    .update(cx, |editor, cx| {
 7043                        editor.inline_blame_popover.take();
 7044                        cx.notify();
 7045                    })
 7046                    .ok();
 7047            });
 7048            state.hide_task = Some(hide_task);
 7049            true
 7050        } else {
 7051            false
 7052        }
 7053    }
 7054
 7055    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 7056        if self.pending_rename.is_some() {
 7057            return None;
 7058        }
 7059
 7060        let provider = self.semantics_provider.clone()?;
 7061        let buffer = self.buffer.read(cx);
 7062        let newest_selection = self.selections.newest_anchor().clone();
 7063        let cursor_position = newest_selection.head();
 7064        let (cursor_buffer, cursor_buffer_position) =
 7065            buffer.text_anchor_for_position(cursor_position, cx)?;
 7066        let (tail_buffer, tail_buffer_position) =
 7067            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 7068        if cursor_buffer != tail_buffer {
 7069            return None;
 7070        }
 7071
 7072        let snapshot = cursor_buffer.read(cx).snapshot();
 7073        let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 7074        let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 7075        if start_word_range != end_word_range {
 7076            self.document_highlights_task.take();
 7077            self.clear_background_highlights::<DocumentHighlightRead>(cx);
 7078            self.clear_background_highlights::<DocumentHighlightWrite>(cx);
 7079            return None;
 7080        }
 7081
 7082        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 7083        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 7084            cx.background_executor()
 7085                .timer(Duration::from_millis(debounce))
 7086                .await;
 7087
 7088            let highlights = if let Some(highlights) = cx
 7089                .update(|cx| {
 7090                    provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 7091                })
 7092                .ok()
 7093                .flatten()
 7094            {
 7095                highlights.await.log_err()
 7096            } else {
 7097                None
 7098            };
 7099
 7100            if let Some(highlights) = highlights {
 7101                this.update(cx, |this, cx| {
 7102                    if this.pending_rename.is_some() {
 7103                        return;
 7104                    }
 7105
 7106                    let buffer = this.buffer.read(cx);
 7107                    if buffer
 7108                        .text_anchor_for_position(cursor_position, cx)
 7109                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 7110                    {
 7111                        return;
 7112                    }
 7113
 7114                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 7115                    let mut write_ranges = Vec::new();
 7116                    let mut read_ranges = Vec::new();
 7117                    for highlight in highlights {
 7118                        let buffer_id = cursor_buffer.read(cx).remote_id();
 7119                        for (excerpt_id, excerpt_range) in buffer.excerpts_for_buffer(buffer_id, cx)
 7120                        {
 7121                            let start = highlight
 7122                                .range
 7123                                .start
 7124                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 7125                            let end = highlight
 7126                                .range
 7127                                .end
 7128                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 7129                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 7130                                continue;
 7131                            }
 7132
 7133                            let range = Anchor::range_in_buffer(excerpt_id, *start..*end);
 7134                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 7135                                write_ranges.push(range);
 7136                            } else {
 7137                                read_ranges.push(range);
 7138                            }
 7139                        }
 7140                    }
 7141
 7142                    this.highlight_background::<DocumentHighlightRead>(
 7143                        &read_ranges,
 7144                        |_, theme| theme.colors().editor_document_highlight_read_background,
 7145                        cx,
 7146                    );
 7147                    this.highlight_background::<DocumentHighlightWrite>(
 7148                        &write_ranges,
 7149                        |_, theme| theme.colors().editor_document_highlight_write_background,
 7150                        cx,
 7151                    );
 7152                    cx.notify();
 7153                })
 7154                .log_err();
 7155            }
 7156        }));
 7157        None
 7158    }
 7159
 7160    fn prepare_highlight_query_from_selection(
 7161        &mut self,
 7162        window: &Window,
 7163        cx: &mut Context<Editor>,
 7164    ) -> Option<(String, Range<Anchor>)> {
 7165        if matches!(self.mode, EditorMode::SingleLine) {
 7166            return None;
 7167        }
 7168        if !EditorSettings::get_global(cx).selection_highlight {
 7169            return None;
 7170        }
 7171        if self.selections.count() != 1 || self.selections.line_mode() {
 7172            return None;
 7173        }
 7174        let snapshot = self.snapshot(window, cx);
 7175        let selection = self.selections.newest::<Point>(&snapshot);
 7176        // If the selection spans multiple rows OR it is empty
 7177        if selection.start.row != selection.end.row
 7178            || selection.start.column == selection.end.column
 7179        {
 7180            return None;
 7181        }
 7182        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 7183        let query = snapshot
 7184            .buffer_snapshot()
 7185            .text_for_range(selection_anchor_range.clone())
 7186            .collect::<String>();
 7187        if query.trim().is_empty() {
 7188            return None;
 7189        }
 7190        Some((query, selection_anchor_range))
 7191    }
 7192
 7193    #[ztracing::instrument(skip_all)]
 7194    fn update_selection_occurrence_highlights(
 7195        &mut self,
 7196        query_text: String,
 7197        query_range: Range<Anchor>,
 7198        multi_buffer_range_to_query: Range<Point>,
 7199        use_debounce: bool,
 7200        window: &mut Window,
 7201        cx: &mut Context<Editor>,
 7202    ) -> Task<()> {
 7203        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7204        cx.spawn_in(window, async move |editor, cx| {
 7205            if use_debounce {
 7206                cx.background_executor()
 7207                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 7208                    .await;
 7209            }
 7210            let match_task = cx.background_spawn(async move {
 7211                let buffer_ranges = multi_buffer_snapshot
 7212                    .range_to_buffer_ranges(multi_buffer_range_to_query)
 7213                    .into_iter()
 7214                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 7215                let mut match_ranges = Vec::new();
 7216                let Ok(regex) = project::search::SearchQuery::text(
 7217                    query_text.clone(),
 7218                    false,
 7219                    false,
 7220                    false,
 7221                    Default::default(),
 7222                    Default::default(),
 7223                    false,
 7224                    None,
 7225                ) else {
 7226                    return Vec::default();
 7227                };
 7228                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7229                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7230                    match_ranges.extend(
 7231                        regex
 7232                            .search(
 7233                                buffer_snapshot,
 7234                                Some(search_range.start.0..search_range.end.0),
 7235                            )
 7236                            .await
 7237                            .into_iter()
 7238                            .filter_map(|match_range| {
 7239                                let match_start = buffer_snapshot
 7240                                    .anchor_after(search_range.start + match_range.start);
 7241                                let match_end = buffer_snapshot
 7242                                    .anchor_before(search_range.start + match_range.end);
 7243                                let match_anchor_range =
 7244                                    Anchor::range_in_buffer(excerpt_id, match_start..match_end);
 7245                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7246                            }),
 7247                    );
 7248                }
 7249                match_ranges
 7250            });
 7251            let match_ranges = match_task.await;
 7252            editor
 7253                .update_in(cx, |editor, _, cx| {
 7254                    editor.clear_background_highlights::<SelectedTextHighlight>(cx);
 7255                    if !match_ranges.is_empty() {
 7256                        editor.highlight_background::<SelectedTextHighlight>(
 7257                            &match_ranges,
 7258                            |_, theme| theme.colors().editor_document_highlight_bracket_background,
 7259                            cx,
 7260                        )
 7261                    }
 7262                })
 7263                .log_err();
 7264        })
 7265    }
 7266
 7267    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7268        struct NewlineFold;
 7269        let type_id = std::any::TypeId::of::<NewlineFold>();
 7270        if !self.mode.is_single_line() {
 7271            return;
 7272        }
 7273        let snapshot = self.snapshot(window, cx);
 7274        if snapshot.buffer_snapshot().max_point().row == 0 {
 7275            return;
 7276        }
 7277        let task = cx.background_spawn(async move {
 7278            let new_newlines = snapshot
 7279                .buffer_chars_at(MultiBufferOffset(0))
 7280                .filter_map(|(c, i)| {
 7281                    if c == '\n' {
 7282                        Some(
 7283                            snapshot.buffer_snapshot().anchor_after(i)
 7284                                ..snapshot.buffer_snapshot().anchor_before(i + 1usize),
 7285                        )
 7286                    } else {
 7287                        None
 7288                    }
 7289                })
 7290                .collect::<Vec<_>>();
 7291            let existing_newlines = snapshot
 7292                .folds_in_range(MultiBufferOffset(0)..snapshot.buffer_snapshot().len())
 7293                .filter_map(|fold| {
 7294                    if fold.placeholder.type_tag == Some(type_id) {
 7295                        Some(fold.range.start..fold.range.end)
 7296                    } else {
 7297                        None
 7298                    }
 7299                })
 7300                .collect::<Vec<_>>();
 7301
 7302            (new_newlines, existing_newlines)
 7303        });
 7304        self.folding_newlines = cx.spawn(async move |this, cx| {
 7305            let (new_newlines, existing_newlines) = task.await;
 7306            if new_newlines == existing_newlines {
 7307                return;
 7308            }
 7309            let placeholder = FoldPlaceholder {
 7310                render: Arc::new(move |_, _, cx| {
 7311                    div()
 7312                        .bg(cx.theme().status().hint_background)
 7313                        .border_b_1()
 7314                        .size_full()
 7315                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7316                        .border_color(cx.theme().status().hint)
 7317                        .child("\\n")
 7318                        .into_any()
 7319                }),
 7320                constrain_width: false,
 7321                merge_adjacent: false,
 7322                type_tag: Some(type_id),
 7323            };
 7324            let creases = new_newlines
 7325                .into_iter()
 7326                .map(|range| Crease::simple(range, placeholder.clone()))
 7327                .collect();
 7328            this.update(cx, |this, cx| {
 7329                this.display_map.update(cx, |display_map, cx| {
 7330                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7331                    display_map.fold(creases, cx);
 7332                });
 7333            })
 7334            .ok();
 7335        });
 7336    }
 7337
 7338    #[ztracing::instrument(skip_all)]
 7339    fn refresh_selected_text_highlights(
 7340        &mut self,
 7341        on_buffer_edit: bool,
 7342        window: &mut Window,
 7343        cx: &mut Context<Editor>,
 7344    ) {
 7345        let Some((query_text, query_range)) =
 7346            self.prepare_highlight_query_from_selection(window, cx)
 7347        else {
 7348            self.clear_background_highlights::<SelectedTextHighlight>(cx);
 7349            self.quick_selection_highlight_task.take();
 7350            self.debounced_selection_highlight_task.take();
 7351            return;
 7352        };
 7353        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7354        if on_buffer_edit
 7355            || self
 7356                .quick_selection_highlight_task
 7357                .as_ref()
 7358                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7359        {
 7360            let multi_buffer_visible_start = self
 7361                .scroll_manager
 7362                .anchor()
 7363                .anchor
 7364                .to_point(&multi_buffer_snapshot);
 7365            let multi_buffer_visible_end = multi_buffer_snapshot.clip_point(
 7366                multi_buffer_visible_start
 7367                    + Point::new(self.visible_line_count().unwrap_or(0.).ceil() as u32, 0),
 7368                Bias::Left,
 7369            );
 7370            let multi_buffer_visible_range = multi_buffer_visible_start..multi_buffer_visible_end;
 7371            self.quick_selection_highlight_task = Some((
 7372                query_range.clone(),
 7373                self.update_selection_occurrence_highlights(
 7374                    query_text.clone(),
 7375                    query_range.clone(),
 7376                    multi_buffer_visible_range,
 7377                    false,
 7378                    window,
 7379                    cx,
 7380                ),
 7381            ));
 7382        }
 7383        if on_buffer_edit
 7384            || self
 7385                .debounced_selection_highlight_task
 7386                .as_ref()
 7387                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7388        {
 7389            let multi_buffer_start = multi_buffer_snapshot
 7390                .anchor_before(MultiBufferOffset(0))
 7391                .to_point(&multi_buffer_snapshot);
 7392            let multi_buffer_end = multi_buffer_snapshot
 7393                .anchor_after(multi_buffer_snapshot.len())
 7394                .to_point(&multi_buffer_snapshot);
 7395            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7396            self.debounced_selection_highlight_task = Some((
 7397                query_range.clone(),
 7398                self.update_selection_occurrence_highlights(
 7399                    query_text,
 7400                    query_range,
 7401                    multi_buffer_full_range,
 7402                    true,
 7403                    window,
 7404                    cx,
 7405                ),
 7406            ));
 7407        }
 7408    }
 7409
 7410    pub fn refresh_edit_prediction(
 7411        &mut self,
 7412        debounce: bool,
 7413        user_requested: bool,
 7414        window: &mut Window,
 7415        cx: &mut Context<Self>,
 7416    ) -> Option<()> {
 7417        if DisableAiSettings::get_global(cx).disable_ai {
 7418            return None;
 7419        }
 7420
 7421        let provider = self.edit_prediction_provider()?;
 7422        let cursor = self.selections.newest_anchor().head();
 7423        let (buffer, cursor_buffer_position) =
 7424            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7425
 7426        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7427            self.discard_edit_prediction(false, cx);
 7428            return None;
 7429        }
 7430
 7431        self.update_visible_edit_prediction(window, cx);
 7432
 7433        if !user_requested
 7434            && (!self.should_show_edit_predictions()
 7435                || !self.is_focused(window)
 7436                || buffer.read(cx).is_empty())
 7437        {
 7438            self.discard_edit_prediction(false, cx);
 7439            return None;
 7440        }
 7441
 7442        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7443        Some(())
 7444    }
 7445
 7446    fn show_edit_predictions_in_menu(&self) -> bool {
 7447        match self.edit_prediction_settings {
 7448            EditPredictionSettings::Disabled => false,
 7449            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7450        }
 7451    }
 7452
 7453    pub fn edit_predictions_enabled(&self) -> bool {
 7454        match self.edit_prediction_settings {
 7455            EditPredictionSettings::Disabled => false,
 7456            EditPredictionSettings::Enabled { .. } => true,
 7457        }
 7458    }
 7459
 7460    fn edit_prediction_requires_modifier(&self) -> bool {
 7461        match self.edit_prediction_settings {
 7462            EditPredictionSettings::Disabled => false,
 7463            EditPredictionSettings::Enabled {
 7464                preview_requires_modifier,
 7465                ..
 7466            } => preview_requires_modifier,
 7467        }
 7468    }
 7469
 7470    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7471        if self.edit_prediction_provider.is_none() || DisableAiSettings::get_global(cx).disable_ai {
 7472            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7473            self.discard_edit_prediction(false, cx);
 7474        } else {
 7475            let selection = self.selections.newest_anchor();
 7476            let cursor = selection.head();
 7477
 7478            if let Some((buffer, cursor_buffer_position)) =
 7479                self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7480            {
 7481                self.edit_prediction_settings =
 7482                    self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7483            }
 7484        }
 7485    }
 7486
 7487    fn edit_prediction_settings_at_position(
 7488        &self,
 7489        buffer: &Entity<Buffer>,
 7490        buffer_position: language::Anchor,
 7491        cx: &App,
 7492    ) -> EditPredictionSettings {
 7493        if !self.mode.is_full()
 7494            || !self.show_edit_predictions_override.unwrap_or(true)
 7495            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7496        {
 7497            return EditPredictionSettings::Disabled;
 7498        }
 7499
 7500        let buffer = buffer.read(cx);
 7501
 7502        let file = buffer.file();
 7503
 7504        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7505            return EditPredictionSettings::Disabled;
 7506        };
 7507
 7508        let by_provider = matches!(
 7509            self.menu_edit_predictions_policy,
 7510            MenuEditPredictionsPolicy::ByProvider
 7511        );
 7512
 7513        let show_in_menu = by_provider
 7514            && self
 7515                .edit_prediction_provider
 7516                .as_ref()
 7517                .is_some_and(|provider| provider.provider.show_predictions_in_menu());
 7518
 7519        let preview_requires_modifier =
 7520            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7521
 7522        EditPredictionSettings::Enabled {
 7523            show_in_menu,
 7524            preview_requires_modifier,
 7525        }
 7526    }
 7527
 7528    fn should_show_edit_predictions(&self) -> bool {
 7529        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7530    }
 7531
 7532    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7533        matches!(
 7534            self.edit_prediction_preview,
 7535            EditPredictionPreview::Active { .. }
 7536        )
 7537    }
 7538
 7539    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7540        let cursor = self.selections.newest_anchor().head();
 7541        if let Some((buffer, cursor_position)) =
 7542            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7543        {
 7544            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7545        } else {
 7546            false
 7547        }
 7548    }
 7549
 7550    pub fn supports_minimap(&self, cx: &App) -> bool {
 7551        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7552    }
 7553
 7554    fn edit_predictions_enabled_in_buffer(
 7555        &self,
 7556        buffer: &Entity<Buffer>,
 7557        buffer_position: language::Anchor,
 7558        cx: &App,
 7559    ) -> bool {
 7560        maybe!({
 7561            if self.read_only(cx) {
 7562                return Some(false);
 7563            }
 7564            let provider = self.edit_prediction_provider()?;
 7565            if !provider.is_enabled(buffer, buffer_position, cx) {
 7566                return Some(false);
 7567            }
 7568            let buffer = buffer.read(cx);
 7569            let Some(file) = buffer.file() else {
 7570                return Some(true);
 7571            };
 7572            let settings = all_language_settings(Some(file), cx);
 7573            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7574        })
 7575        .unwrap_or(false)
 7576    }
 7577
 7578    fn cycle_edit_prediction(
 7579        &mut self,
 7580        direction: Direction,
 7581        window: &mut Window,
 7582        cx: &mut Context<Self>,
 7583    ) -> Option<()> {
 7584        let provider = self.edit_prediction_provider()?;
 7585        let cursor = self.selections.newest_anchor().head();
 7586        let (buffer, cursor_buffer_position) =
 7587            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7588        if self.edit_predictions_hidden_for_vim_mode || !self.should_show_edit_predictions() {
 7589            return None;
 7590        }
 7591
 7592        provider.cycle(buffer, cursor_buffer_position, direction, cx);
 7593        self.update_visible_edit_prediction(window, cx);
 7594
 7595        Some(())
 7596    }
 7597
 7598    pub fn show_edit_prediction(
 7599        &mut self,
 7600        _: &ShowEditPrediction,
 7601        window: &mut Window,
 7602        cx: &mut Context<Self>,
 7603    ) {
 7604        if !self.has_active_edit_prediction() {
 7605            self.refresh_edit_prediction(false, true, window, cx);
 7606            return;
 7607        }
 7608
 7609        self.update_visible_edit_prediction(window, cx);
 7610    }
 7611
 7612    pub fn display_cursor_names(
 7613        &mut self,
 7614        _: &DisplayCursorNames,
 7615        window: &mut Window,
 7616        cx: &mut Context<Self>,
 7617    ) {
 7618        self.show_cursor_names(window, cx);
 7619    }
 7620
 7621    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7622        self.show_cursor_names = true;
 7623        cx.notify();
 7624        cx.spawn_in(window, async move |this, cx| {
 7625            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 7626            this.update(cx, |this, cx| {
 7627                this.show_cursor_names = false;
 7628                cx.notify()
 7629            })
 7630            .ok()
 7631        })
 7632        .detach();
 7633    }
 7634
 7635    pub fn next_edit_prediction(
 7636        &mut self,
 7637        _: &NextEditPrediction,
 7638        window: &mut Window,
 7639        cx: &mut Context<Self>,
 7640    ) {
 7641        if self.has_active_edit_prediction() {
 7642            self.cycle_edit_prediction(Direction::Next, window, cx);
 7643        } else {
 7644            let is_copilot_disabled = self
 7645                .refresh_edit_prediction(false, true, window, cx)
 7646                .is_none();
 7647            if is_copilot_disabled {
 7648                cx.propagate();
 7649            }
 7650        }
 7651    }
 7652
 7653    pub fn previous_edit_prediction(
 7654        &mut self,
 7655        _: &PreviousEditPrediction,
 7656        window: &mut Window,
 7657        cx: &mut Context<Self>,
 7658    ) {
 7659        if self.has_active_edit_prediction() {
 7660            self.cycle_edit_prediction(Direction::Prev, window, cx);
 7661        } else {
 7662            let is_copilot_disabled = self
 7663                .refresh_edit_prediction(false, true, window, cx)
 7664                .is_none();
 7665            if is_copilot_disabled {
 7666                cx.propagate();
 7667            }
 7668        }
 7669    }
 7670
 7671    pub fn accept_partial_edit_prediction(
 7672        &mut self,
 7673        granularity: EditPredictionGranularity,
 7674        window: &mut Window,
 7675        cx: &mut Context<Self>,
 7676    ) {
 7677        if self.show_edit_predictions_in_menu() {
 7678            self.hide_context_menu(window, cx);
 7679        }
 7680
 7681        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 7682            return;
 7683        };
 7684
 7685        if !matches!(granularity, EditPredictionGranularity::Full) && self.selections.count() != 1 {
 7686            return;
 7687        }
 7688
 7689        match &active_edit_prediction.completion {
 7690            EditPrediction::MoveWithin { target, .. } => {
 7691                let target = *target;
 7692
 7693                if matches!(granularity, EditPredictionGranularity::Full) {
 7694                    if let Some(position_map) = &self.last_position_map {
 7695                        let target_row = target.to_display_point(&position_map.snapshot).row();
 7696                        let is_visible = position_map.visible_row_range.contains(&target_row);
 7697
 7698                        if is_visible || !self.edit_prediction_requires_modifier() {
 7699                            self.unfold_ranges(&[target..target], true, false, cx);
 7700                            self.change_selections(
 7701                                SelectionEffects::scroll(Autoscroll::newest()),
 7702                                window,
 7703                                cx,
 7704                                |selections| {
 7705                                    selections.select_anchor_ranges([target..target]);
 7706                                },
 7707                            );
 7708                            self.clear_row_highlights::<EditPredictionPreview>();
 7709                            self.edit_prediction_preview
 7710                                .set_previous_scroll_position(None);
 7711                        } else {
 7712                            // Highlight and request scroll
 7713                            self.edit_prediction_preview
 7714                                .set_previous_scroll_position(Some(
 7715                                    position_map.snapshot.scroll_anchor,
 7716                                ));
 7717                            self.highlight_rows::<EditPredictionPreview>(
 7718                                target..target,
 7719                                cx.theme().colors().editor_highlighted_line_background,
 7720                                RowHighlightOptions {
 7721                                    autoscroll: true,
 7722                                    ..Default::default()
 7723                                },
 7724                                cx,
 7725                            );
 7726                            self.request_autoscroll(Autoscroll::fit(), cx);
 7727                        }
 7728                    }
 7729                } else {
 7730                    self.change_selections(
 7731                        SelectionEffects::scroll(Autoscroll::newest()),
 7732                        window,
 7733                        cx,
 7734                        |selections| {
 7735                            selections.select_anchor_ranges([target..target]);
 7736                        },
 7737                    );
 7738                }
 7739            }
 7740            EditPrediction::MoveOutside { snapshot, target } => {
 7741                if let Some(workspace) = self.workspace() {
 7742                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 7743                        .detach_and_log_err(cx);
 7744                }
 7745            }
 7746            EditPrediction::Edit { edits, .. } => {
 7747                self.report_edit_prediction_event(
 7748                    active_edit_prediction.completion_id.clone(),
 7749                    true,
 7750                    cx,
 7751                );
 7752
 7753                match granularity {
 7754                    EditPredictionGranularity::Full => {
 7755                        if let Some(provider) = self.edit_prediction_provider() {
 7756                            provider.accept(cx);
 7757                        }
 7758
 7759                        let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 7760                        let snapshot = self.buffer.read(cx).snapshot(cx);
 7761                        let last_edit_end = edits.last().unwrap().0.end.bias_right(&snapshot);
 7762
 7763                        self.buffer.update(cx, |buffer, cx| {
 7764                            buffer.edit(edits.iter().cloned(), None, cx)
 7765                        });
 7766
 7767                        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 7768                            s.select_anchor_ranges([last_edit_end..last_edit_end]);
 7769                        });
 7770
 7771                        let selections = self.selections.disjoint_anchors_arc();
 7772                        if let Some(transaction_id_now) =
 7773                            self.buffer.read(cx).last_transaction_id(cx)
 7774                        {
 7775                            if transaction_id_prev != Some(transaction_id_now) {
 7776                                self.selection_history
 7777                                    .insert_transaction(transaction_id_now, selections);
 7778                            }
 7779                        }
 7780
 7781                        self.update_visible_edit_prediction(window, cx);
 7782                        if self.active_edit_prediction.is_none() {
 7783                            self.refresh_edit_prediction(true, true, window, cx);
 7784                        }
 7785                        cx.notify();
 7786                    }
 7787                    _ => {
 7788                        let snapshot = self.buffer.read(cx).snapshot(cx);
 7789                        let cursor_offset = self
 7790                            .selections
 7791                            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 7792                            .head();
 7793
 7794                        let insertion = edits.iter().find_map(|(range, text)| {
 7795                            let range = range.to_offset(&snapshot);
 7796                            if range.is_empty() && range.start == cursor_offset {
 7797                                Some(text)
 7798                            } else {
 7799                                None
 7800                            }
 7801                        });
 7802
 7803                        if let Some(text) = insertion {
 7804                            let text_to_insert = match granularity {
 7805                                EditPredictionGranularity::Word => {
 7806                                    let mut partial = text
 7807                                        .chars()
 7808                                        .by_ref()
 7809                                        .take_while(|c| c.is_alphabetic())
 7810                                        .collect::<String>();
 7811                                    if partial.is_empty() {
 7812                                        partial = text
 7813                                            .chars()
 7814                                            .by_ref()
 7815                                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 7816                                            .collect::<String>();
 7817                                    }
 7818                                    partial
 7819                                }
 7820                                EditPredictionGranularity::Line => {
 7821                                    if let Some(line) = text.split_inclusive('\n').next() {
 7822                                        line.to_string()
 7823                                    } else {
 7824                                        text.to_string()
 7825                                    }
 7826                                }
 7827                                EditPredictionGranularity::Full => unreachable!(),
 7828                            };
 7829
 7830                            cx.emit(EditorEvent::InputHandled {
 7831                                utf16_range_to_replace: None,
 7832                                text: text_to_insert.clone().into(),
 7833                            });
 7834
 7835                            self.insert_with_autoindent_mode(&text_to_insert, None, window, cx);
 7836                            self.refresh_edit_prediction(true, true, window, cx);
 7837                            cx.notify();
 7838                        } else {
 7839                            self.accept_partial_edit_prediction(
 7840                                EditPredictionGranularity::Full,
 7841                                window,
 7842                                cx,
 7843                            );
 7844                        }
 7845                    }
 7846                }
 7847            }
 7848        }
 7849
 7850        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 7851    }
 7852
 7853    pub fn accept_next_word_edit_prediction(
 7854        &mut self,
 7855        _: &AcceptNextWordEditPrediction,
 7856        window: &mut Window,
 7857        cx: &mut Context<Self>,
 7858    ) {
 7859        self.accept_partial_edit_prediction(EditPredictionGranularity::Word, window, cx);
 7860    }
 7861
 7862    pub fn accept_next_line_edit_prediction(
 7863        &mut self,
 7864        _: &AcceptNextLineEditPrediction,
 7865        window: &mut Window,
 7866        cx: &mut Context<Self>,
 7867    ) {
 7868        self.accept_partial_edit_prediction(EditPredictionGranularity::Line, window, cx);
 7869    }
 7870
 7871    pub fn accept_edit_prediction(
 7872        &mut self,
 7873        _: &AcceptEditPrediction,
 7874        window: &mut Window,
 7875        cx: &mut Context<Self>,
 7876    ) {
 7877        self.accept_partial_edit_prediction(EditPredictionGranularity::Full, window, cx);
 7878    }
 7879
 7880    fn discard_edit_prediction(
 7881        &mut self,
 7882        should_report_edit_prediction_event: bool,
 7883        cx: &mut Context<Self>,
 7884    ) -> bool {
 7885        if should_report_edit_prediction_event {
 7886            let completion_id = self
 7887                .active_edit_prediction
 7888                .as_ref()
 7889                .and_then(|active_completion| active_completion.completion_id.clone());
 7890
 7891            self.report_edit_prediction_event(completion_id, false, cx);
 7892        }
 7893
 7894        if let Some(provider) = self.edit_prediction_provider() {
 7895            provider.discard(cx);
 7896        }
 7897
 7898        self.take_active_edit_prediction(cx)
 7899    }
 7900
 7901    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 7902        let Some(provider) = self.edit_prediction_provider() else {
 7903            return;
 7904        };
 7905
 7906        let Some((_, buffer, _)) = self
 7907            .buffer
 7908            .read(cx)
 7909            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 7910        else {
 7911            return;
 7912        };
 7913
 7914        let extension = buffer
 7915            .read(cx)
 7916            .file()
 7917            .and_then(|file| Some(file.path().extension()?.to_string()));
 7918
 7919        let event_type = match accepted {
 7920            true => "Edit Prediction Accepted",
 7921            false => "Edit Prediction Discarded",
 7922        };
 7923        telemetry::event!(
 7924            event_type,
 7925            provider = provider.name(),
 7926            prediction_id = id,
 7927            suggestion_accepted = accepted,
 7928            file_extension = extension,
 7929        );
 7930    }
 7931
 7932    fn open_editor_at_anchor(
 7933        snapshot: &language::BufferSnapshot,
 7934        target: language::Anchor,
 7935        workspace: &Entity<Workspace>,
 7936        window: &mut Window,
 7937        cx: &mut App,
 7938    ) -> Task<Result<()>> {
 7939        workspace.update(cx, |workspace, cx| {
 7940            let path = snapshot.file().map(|file| file.full_path(cx));
 7941            let Some(path) =
 7942                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 7943            else {
 7944                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 7945            };
 7946            let target = text::ToPoint::to_point(&target, snapshot);
 7947            let item = workspace.open_path(path, None, true, window, cx);
 7948            window.spawn(cx, async move |cx| {
 7949                let Some(editor) = item.await?.downcast::<Editor>() else {
 7950                    return Ok(());
 7951                };
 7952                editor
 7953                    .update_in(cx, |editor, window, cx| {
 7954                        editor.go_to_singleton_buffer_point(target, window, cx);
 7955                    })
 7956                    .ok();
 7957                anyhow::Ok(())
 7958            })
 7959        })
 7960    }
 7961
 7962    pub fn has_active_edit_prediction(&self) -> bool {
 7963        self.active_edit_prediction.is_some()
 7964    }
 7965
 7966    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 7967        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 7968            return false;
 7969        };
 7970
 7971        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 7972        self.clear_highlights::<EditPredictionHighlight>(cx);
 7973        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 7974        true
 7975    }
 7976
 7977    /// Returns true when we're displaying the edit prediction popover below the cursor
 7978    /// like we are not previewing and the LSP autocomplete menu is visible
 7979    /// or we are in `when_holding_modifier` mode.
 7980    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 7981        if self.edit_prediction_preview_is_active()
 7982            || !self.show_edit_predictions_in_menu()
 7983            || !self.edit_predictions_enabled()
 7984        {
 7985            return false;
 7986        }
 7987
 7988        if self.has_visible_completions_menu() {
 7989            return true;
 7990        }
 7991
 7992        has_completion && self.edit_prediction_requires_modifier()
 7993    }
 7994
 7995    fn handle_modifiers_changed(
 7996        &mut self,
 7997        modifiers: Modifiers,
 7998        position_map: &PositionMap,
 7999        window: &mut Window,
 8000        cx: &mut Context<Self>,
 8001    ) {
 8002        // Ensure that the edit prediction preview is updated, even when not
 8003        // enabled, if there's an active edit prediction preview.
 8004        if self.show_edit_predictions_in_menu()
 8005            || matches!(
 8006                self.edit_prediction_preview,
 8007                EditPredictionPreview::Active { .. }
 8008            )
 8009        {
 8010            self.update_edit_prediction_preview(&modifiers, window, cx);
 8011        }
 8012
 8013        self.update_selection_mode(&modifiers, position_map, window, cx);
 8014
 8015        let mouse_position = window.mouse_position();
 8016        if !position_map.text_hitbox.is_hovered(window) {
 8017            return;
 8018        }
 8019
 8020        self.update_hovered_link(
 8021            position_map.point_for_position(mouse_position),
 8022            &position_map.snapshot,
 8023            modifiers,
 8024            window,
 8025            cx,
 8026        )
 8027    }
 8028
 8029    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 8030        match EditorSettings::get_global(cx).multi_cursor_modifier {
 8031            MultiCursorModifier::Alt => modifiers.secondary(),
 8032            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 8033        }
 8034    }
 8035
 8036    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 8037        match EditorSettings::get_global(cx).multi_cursor_modifier {
 8038            MultiCursorModifier::Alt => modifiers.alt,
 8039            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 8040        }
 8041    }
 8042
 8043    fn columnar_selection_mode(
 8044        modifiers: &Modifiers,
 8045        cx: &mut Context<Self>,
 8046    ) -> Option<ColumnarMode> {
 8047        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 8048            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 8049                Some(ColumnarMode::FromMouse)
 8050            } else if Self::is_alt_pressed(modifiers, cx) {
 8051                Some(ColumnarMode::FromSelection)
 8052            } else {
 8053                None
 8054            }
 8055        } else {
 8056            None
 8057        }
 8058    }
 8059
 8060    fn update_selection_mode(
 8061        &mut self,
 8062        modifiers: &Modifiers,
 8063        position_map: &PositionMap,
 8064        window: &mut Window,
 8065        cx: &mut Context<Self>,
 8066    ) {
 8067        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 8068            return;
 8069        };
 8070        if self.selections.pending_anchor().is_none() {
 8071            return;
 8072        }
 8073
 8074        let mouse_position = window.mouse_position();
 8075        let point_for_position = position_map.point_for_position(mouse_position);
 8076        let position = point_for_position.previous_valid;
 8077
 8078        self.select(
 8079            SelectPhase::BeginColumnar {
 8080                position,
 8081                reset: false,
 8082                mode,
 8083                goal_column: point_for_position.exact_unclipped.column(),
 8084            },
 8085            window,
 8086            cx,
 8087        );
 8088    }
 8089
 8090    fn update_edit_prediction_preview(
 8091        &mut self,
 8092        modifiers: &Modifiers,
 8093        window: &mut Window,
 8094        cx: &mut Context<Self>,
 8095    ) {
 8096        let mut modifiers_held = false;
 8097
 8098        // Check bindings for all granularities.
 8099        // If the user holds the key for Word, Line, or Full, we want to show the preview.
 8100        let granularities = [
 8101            EditPredictionGranularity::Full,
 8102            EditPredictionGranularity::Line,
 8103            EditPredictionGranularity::Word,
 8104        ];
 8105
 8106        for granularity in granularities {
 8107            if let Some(keystroke) = self
 8108                .accept_edit_prediction_keybind(granularity, window, cx)
 8109                .keystroke()
 8110            {
 8111                modifiers_held = modifiers_held
 8112                    || (keystroke.modifiers() == modifiers && keystroke.modifiers().modified());
 8113            }
 8114        }
 8115
 8116        if modifiers_held {
 8117            if matches!(
 8118                self.edit_prediction_preview,
 8119                EditPredictionPreview::Inactive { .. }
 8120            ) {
 8121                if let Some(provider) = self.edit_prediction_provider.as_ref() {
 8122                    provider.provider.did_show(cx)
 8123                }
 8124
 8125                self.edit_prediction_preview = EditPredictionPreview::Active {
 8126                    previous_scroll_position: None,
 8127                    since: Instant::now(),
 8128                };
 8129
 8130                self.update_visible_edit_prediction(window, cx);
 8131                cx.notify();
 8132            }
 8133        } else if let EditPredictionPreview::Active {
 8134            previous_scroll_position,
 8135            since,
 8136        } = self.edit_prediction_preview
 8137        {
 8138            if let (Some(previous_scroll_position), Some(position_map)) =
 8139                (previous_scroll_position, self.last_position_map.as_ref())
 8140            {
 8141                self.set_scroll_position(
 8142                    previous_scroll_position
 8143                        .scroll_position(&position_map.snapshot.display_snapshot),
 8144                    window,
 8145                    cx,
 8146                );
 8147            }
 8148
 8149            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 8150                released_too_fast: since.elapsed() < Duration::from_millis(200),
 8151            };
 8152            self.clear_row_highlights::<EditPredictionPreview>();
 8153            self.update_visible_edit_prediction(window, cx);
 8154            cx.notify();
 8155        }
 8156    }
 8157
 8158    fn update_visible_edit_prediction(
 8159        &mut self,
 8160        _window: &mut Window,
 8161        cx: &mut Context<Self>,
 8162    ) -> Option<()> {
 8163        if DisableAiSettings::get_global(cx).disable_ai {
 8164            return None;
 8165        }
 8166
 8167        if self.ime_transaction.is_some() {
 8168            self.discard_edit_prediction(false, cx);
 8169            return None;
 8170        }
 8171
 8172        let selection = self.selections.newest_anchor();
 8173        let cursor = selection.head();
 8174        let multibuffer = self.buffer.read(cx).snapshot(cx);
 8175        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 8176        let excerpt_id = cursor.excerpt_id;
 8177
 8178        let show_in_menu = self.show_edit_predictions_in_menu();
 8179        let completions_menu_has_precedence = !show_in_menu
 8180            && (self.context_menu.borrow().is_some()
 8181                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 8182
 8183        if completions_menu_has_precedence
 8184            || !offset_selection.is_empty()
 8185            || self
 8186                .active_edit_prediction
 8187                .as_ref()
 8188                .is_some_and(|completion| {
 8189                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 8190                        return false;
 8191                    };
 8192                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 8193                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 8194                    !invalidation_range.contains(&offset_selection.head())
 8195                })
 8196        {
 8197            self.discard_edit_prediction(false, cx);
 8198            return None;
 8199        }
 8200
 8201        self.take_active_edit_prediction(cx);
 8202        let Some(provider) = self.edit_prediction_provider() else {
 8203            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8204            return None;
 8205        };
 8206
 8207        let (buffer, cursor_buffer_position) =
 8208            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 8209
 8210        self.edit_prediction_settings =
 8211            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 8212
 8213        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 8214
 8215        if self.edit_prediction_indent_conflict {
 8216            let cursor_point = cursor.to_point(&multibuffer);
 8217            let mut suggested_indent = None;
 8218            multibuffer.suggested_indents_callback(
 8219                cursor_point.row..cursor_point.row + 1,
 8220                |_, indent| {
 8221                    suggested_indent = Some(indent);
 8222                    ControlFlow::Break(())
 8223                },
 8224                cx,
 8225            );
 8226
 8227            if let Some(indent) = suggested_indent
 8228                && indent.len == cursor_point.column
 8229            {
 8230                self.edit_prediction_indent_conflict = false;
 8231            }
 8232        }
 8233
 8234        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 8235
 8236        let (completion_id, edits, edit_preview) = match edit_prediction {
 8237            edit_prediction_types::EditPrediction::Local {
 8238                id,
 8239                edits,
 8240                edit_preview,
 8241            } => (id, edits, edit_preview),
 8242            edit_prediction_types::EditPrediction::Jump {
 8243                id,
 8244                snapshot,
 8245                target,
 8246            } => {
 8247                self.stale_edit_prediction_in_menu = None;
 8248                self.active_edit_prediction = Some(EditPredictionState {
 8249                    inlay_ids: vec![],
 8250                    completion: EditPrediction::MoveOutside { snapshot, target },
 8251                    completion_id: id,
 8252                    invalidation_range: None,
 8253                });
 8254                cx.notify();
 8255                return Some(());
 8256            }
 8257        };
 8258
 8259        let edits = edits
 8260            .into_iter()
 8261            .flat_map(|(range, new_text)| {
 8262                Some((
 8263                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8264                    new_text,
 8265                ))
 8266            })
 8267            .collect::<Vec<_>>();
 8268        if edits.is_empty() {
 8269            return None;
 8270        }
 8271
 8272        let first_edit_start = edits.first().unwrap().0.start;
 8273        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8274        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8275
 8276        let last_edit_end = edits.last().unwrap().0.end;
 8277        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8278        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8279
 8280        let cursor_row = cursor.to_point(&multibuffer).row;
 8281
 8282        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8283
 8284        let mut inlay_ids = Vec::new();
 8285        let invalidation_row_range;
 8286        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8287            Some(cursor_row..edit_end_row)
 8288        } else if cursor_row > edit_end_row {
 8289            Some(edit_start_row..cursor_row)
 8290        } else {
 8291            None
 8292        };
 8293        let supports_jump = self
 8294            .edit_prediction_provider
 8295            .as_ref()
 8296            .map(|provider| provider.provider.supports_jump_to_edit())
 8297            .unwrap_or(true);
 8298
 8299        let is_move = supports_jump
 8300            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8301        let completion = if is_move {
 8302            invalidation_row_range =
 8303                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8304            let target = first_edit_start;
 8305            EditPrediction::MoveWithin { target, snapshot }
 8306        } else {
 8307            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8308                && !self.edit_predictions_hidden_for_vim_mode;
 8309
 8310            if show_completions_in_buffer {
 8311                if let Some(provider) = &self.edit_prediction_provider {
 8312                    provider.provider.did_show(cx);
 8313                }
 8314                if edits
 8315                    .iter()
 8316                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8317                {
 8318                    let mut inlays = Vec::new();
 8319                    for (range, new_text) in &edits {
 8320                        let inlay = Inlay::edit_prediction(
 8321                            post_inc(&mut self.next_inlay_id),
 8322                            range.start,
 8323                            new_text.as_ref(),
 8324                        );
 8325                        inlay_ids.push(inlay.id);
 8326                        inlays.push(inlay);
 8327                    }
 8328
 8329                    self.splice_inlays(&[], inlays, cx);
 8330                } else {
 8331                    let background_color = cx.theme().status().deleted_background;
 8332                    self.highlight_text::<EditPredictionHighlight>(
 8333                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8334                        HighlightStyle {
 8335                            background_color: Some(background_color),
 8336                            ..Default::default()
 8337                        },
 8338                        cx,
 8339                    );
 8340                }
 8341            }
 8342
 8343            invalidation_row_range = edit_start_row..edit_end_row;
 8344
 8345            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8346                if provider.show_tab_accept_marker() {
 8347                    EditDisplayMode::TabAccept
 8348                } else {
 8349                    EditDisplayMode::Inline
 8350                }
 8351            } else {
 8352                EditDisplayMode::DiffPopover
 8353            };
 8354
 8355            EditPrediction::Edit {
 8356                edits,
 8357                edit_preview,
 8358                display_mode,
 8359                snapshot,
 8360            }
 8361        };
 8362
 8363        let invalidation_range = multibuffer
 8364            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8365            ..multibuffer.anchor_after(Point::new(
 8366                invalidation_row_range.end,
 8367                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8368            ));
 8369
 8370        self.stale_edit_prediction_in_menu = None;
 8371        self.active_edit_prediction = Some(EditPredictionState {
 8372            inlay_ids,
 8373            completion,
 8374            completion_id,
 8375            invalidation_range: Some(invalidation_range),
 8376        });
 8377
 8378        cx.notify();
 8379
 8380        Some(())
 8381    }
 8382
 8383    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionDelegateHandle>> {
 8384        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8385    }
 8386
 8387    fn clear_tasks(&mut self) {
 8388        self.tasks.clear()
 8389    }
 8390
 8391    fn insert_tasks(&mut self, key: (BufferId, BufferRow), value: RunnableTasks) {
 8392        if self.tasks.insert(key, value).is_some() {
 8393            // This case should hopefully be rare, but just in case...
 8394            log::error!(
 8395                "multiple different run targets found on a single line, only the last target will be rendered"
 8396            )
 8397        }
 8398    }
 8399
 8400    /// Get all display points of breakpoints that will be rendered within editor
 8401    ///
 8402    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8403    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8404    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8405    fn active_breakpoints(
 8406        &self,
 8407        range: Range<DisplayRow>,
 8408        window: &mut Window,
 8409        cx: &mut Context<Self>,
 8410    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8411        let mut breakpoint_display_points = HashMap::default();
 8412
 8413        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8414            return breakpoint_display_points;
 8415        };
 8416
 8417        let snapshot = self.snapshot(window, cx);
 8418
 8419        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8420        let Some(project) = self.project() else {
 8421            return breakpoint_display_points;
 8422        };
 8423
 8424        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8425            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8426
 8427        for (buffer_snapshot, range, excerpt_id) in
 8428            multi_buffer_snapshot.range_to_buffer_ranges(range)
 8429        {
 8430            let Some(buffer) = project
 8431                .read(cx)
 8432                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8433            else {
 8434                continue;
 8435            };
 8436            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8437                &buffer,
 8438                Some(
 8439                    buffer_snapshot.anchor_before(range.start)
 8440                        ..buffer_snapshot.anchor_after(range.end),
 8441                ),
 8442                buffer_snapshot,
 8443                cx,
 8444            );
 8445            for (breakpoint, state) in breakpoints {
 8446                let multi_buffer_anchor = Anchor::in_buffer(excerpt_id, breakpoint.position);
 8447                let position = multi_buffer_anchor
 8448                    .to_point(&multi_buffer_snapshot)
 8449                    .to_display_point(&snapshot);
 8450
 8451                breakpoint_display_points.insert(
 8452                    position.row(),
 8453                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8454                );
 8455            }
 8456        }
 8457
 8458        breakpoint_display_points
 8459    }
 8460
 8461    fn breakpoint_context_menu(
 8462        &self,
 8463        anchor: Anchor,
 8464        window: &mut Window,
 8465        cx: &mut Context<Self>,
 8466    ) -> Entity<ui::ContextMenu> {
 8467        let weak_editor = cx.weak_entity();
 8468        let focus_handle = self.focus_handle(cx);
 8469
 8470        let row = self
 8471            .buffer
 8472            .read(cx)
 8473            .snapshot(cx)
 8474            .summary_for_anchor::<Point>(&anchor)
 8475            .row;
 8476
 8477        let breakpoint = self
 8478            .breakpoint_at_row(row, window, cx)
 8479            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8480
 8481        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8482            "Edit Log Breakpoint"
 8483        } else {
 8484            "Set Log Breakpoint"
 8485        };
 8486
 8487        let condition_breakpoint_msg = if breakpoint
 8488            .as_ref()
 8489            .is_some_and(|bp| bp.1.condition.is_some())
 8490        {
 8491            "Edit Condition Breakpoint"
 8492        } else {
 8493            "Set Condition Breakpoint"
 8494        };
 8495
 8496        let hit_condition_breakpoint_msg = if breakpoint
 8497            .as_ref()
 8498            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8499        {
 8500            "Edit Hit Condition Breakpoint"
 8501        } else {
 8502            "Set Hit Condition Breakpoint"
 8503        };
 8504
 8505        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8506            "Unset Breakpoint"
 8507        } else {
 8508            "Set Breakpoint"
 8509        };
 8510
 8511        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8512
 8513        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8514            BreakpointState::Enabled => Some("Disable"),
 8515            BreakpointState::Disabled => Some("Enable"),
 8516        });
 8517
 8518        let (anchor, breakpoint) =
 8519            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8520
 8521        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8522            menu.on_blur_subscription(Subscription::new(|| {}))
 8523                .context(focus_handle)
 8524                .when(run_to_cursor, |this| {
 8525                    let weak_editor = weak_editor.clone();
 8526                    this.entry("Run to cursor", None, move |window, cx| {
 8527                        weak_editor
 8528                            .update(cx, |editor, cx| {
 8529                                editor.change_selections(
 8530                                    SelectionEffects::no_scroll(),
 8531                                    window,
 8532                                    cx,
 8533                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8534                                );
 8535                            })
 8536                            .ok();
 8537
 8538                        window.dispatch_action(Box::new(RunToCursor), cx);
 8539                    })
 8540                    .separator()
 8541                })
 8542                .when_some(toggle_state_msg, |this, msg| {
 8543                    this.entry(msg, None, {
 8544                        let weak_editor = weak_editor.clone();
 8545                        let breakpoint = breakpoint.clone();
 8546                        move |_window, cx| {
 8547                            weak_editor
 8548                                .update(cx, |this, cx| {
 8549                                    this.edit_breakpoint_at_anchor(
 8550                                        anchor,
 8551                                        breakpoint.as_ref().clone(),
 8552                                        BreakpointEditAction::InvertState,
 8553                                        cx,
 8554                                    );
 8555                                })
 8556                                .log_err();
 8557                        }
 8558                    })
 8559                })
 8560                .entry(set_breakpoint_msg, None, {
 8561                    let weak_editor = weak_editor.clone();
 8562                    let breakpoint = breakpoint.clone();
 8563                    move |_window, cx| {
 8564                        weak_editor
 8565                            .update(cx, |this, cx| {
 8566                                this.edit_breakpoint_at_anchor(
 8567                                    anchor,
 8568                                    breakpoint.as_ref().clone(),
 8569                                    BreakpointEditAction::Toggle,
 8570                                    cx,
 8571                                );
 8572                            })
 8573                            .log_err();
 8574                    }
 8575                })
 8576                .entry(log_breakpoint_msg, None, {
 8577                    let breakpoint = breakpoint.clone();
 8578                    let weak_editor = weak_editor.clone();
 8579                    move |window, cx| {
 8580                        weak_editor
 8581                            .update(cx, |this, cx| {
 8582                                this.add_edit_breakpoint_block(
 8583                                    anchor,
 8584                                    breakpoint.as_ref(),
 8585                                    BreakpointPromptEditAction::Log,
 8586                                    window,
 8587                                    cx,
 8588                                );
 8589                            })
 8590                            .log_err();
 8591                    }
 8592                })
 8593                .entry(condition_breakpoint_msg, None, {
 8594                    let breakpoint = breakpoint.clone();
 8595                    let weak_editor = weak_editor.clone();
 8596                    move |window, cx| {
 8597                        weak_editor
 8598                            .update(cx, |this, cx| {
 8599                                this.add_edit_breakpoint_block(
 8600                                    anchor,
 8601                                    breakpoint.as_ref(),
 8602                                    BreakpointPromptEditAction::Condition,
 8603                                    window,
 8604                                    cx,
 8605                                );
 8606                            })
 8607                            .log_err();
 8608                    }
 8609                })
 8610                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8611                    weak_editor
 8612                        .update(cx, |this, cx| {
 8613                            this.add_edit_breakpoint_block(
 8614                                anchor,
 8615                                breakpoint.as_ref(),
 8616                                BreakpointPromptEditAction::HitCondition,
 8617                                window,
 8618                                cx,
 8619                            );
 8620                        })
 8621                        .log_err();
 8622                })
 8623        })
 8624    }
 8625
 8626    fn render_breakpoint(
 8627        &self,
 8628        position: Anchor,
 8629        row: DisplayRow,
 8630        breakpoint: &Breakpoint,
 8631        state: Option<BreakpointSessionState>,
 8632        cx: &mut Context<Self>,
 8633    ) -> IconButton {
 8634        let is_rejected = state.is_some_and(|s| !s.verified);
 8635        // Is it a breakpoint that shows up when hovering over gutter?
 8636        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 8637            (false, false),
 8638            |PhantomBreakpointIndicator {
 8639                 is_active,
 8640                 display_row,
 8641                 collides_with_existing_breakpoint,
 8642             }| {
 8643                (
 8644                    is_active && display_row == row,
 8645                    collides_with_existing_breakpoint,
 8646                )
 8647            },
 8648        );
 8649
 8650        let (color, icon) = {
 8651            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 8652                (false, false) => ui::IconName::DebugBreakpoint,
 8653                (true, false) => ui::IconName::DebugLogBreakpoint,
 8654                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 8655                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 8656            };
 8657
 8658            let color = cx.theme().colors();
 8659
 8660            let color = if is_phantom {
 8661                if collides_with_existing {
 8662                    Color::Custom(color.debugger_accent.blend(color.text.opacity(0.6)))
 8663                } else {
 8664                    Color::Hint
 8665                }
 8666            } else if is_rejected {
 8667                Color::Disabled
 8668            } else {
 8669                Color::Debugger
 8670            };
 8671
 8672            (color, icon)
 8673        };
 8674
 8675        let breakpoint = Arc::from(breakpoint.clone());
 8676
 8677        let alt_as_text = gpui::Keystroke {
 8678            modifiers: Modifiers::secondary_key(),
 8679            ..Default::default()
 8680        };
 8681        let primary_action_text = if breakpoint.is_disabled() {
 8682            "Enable breakpoint"
 8683        } else if is_phantom && !collides_with_existing {
 8684            "Set breakpoint"
 8685        } else {
 8686            "Unset breakpoint"
 8687        };
 8688        let focus_handle = self.focus_handle.clone();
 8689
 8690        let meta = if is_rejected {
 8691            SharedString::from("No executable code is associated with this line.")
 8692        } else if collides_with_existing && !breakpoint.is_disabled() {
 8693            SharedString::from(format!(
 8694                "{alt_as_text}-click to disable,\nright-click for more options."
 8695            ))
 8696        } else {
 8697            SharedString::from("Right-click for more options.")
 8698        };
 8699        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 8700            .icon_size(IconSize::XSmall)
 8701            .size(ui::ButtonSize::None)
 8702            .when(is_rejected, |this| {
 8703                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 8704            })
 8705            .icon_color(color)
 8706            .style(ButtonStyle::Transparent)
 8707            .on_click(cx.listener({
 8708                move |editor, event: &ClickEvent, window, cx| {
 8709                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 8710                        BreakpointEditAction::InvertState
 8711                    } else {
 8712                        BreakpointEditAction::Toggle
 8713                    };
 8714
 8715                    window.focus(&editor.focus_handle(cx));
 8716                    editor.edit_breakpoint_at_anchor(
 8717                        position,
 8718                        breakpoint.as_ref().clone(),
 8719                        edit_action,
 8720                        cx,
 8721                    );
 8722                }
 8723            }))
 8724            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8725                editor.set_breakpoint_context_menu(
 8726                    row,
 8727                    Some(position),
 8728                    event.position(),
 8729                    window,
 8730                    cx,
 8731                );
 8732            }))
 8733            .tooltip(move |_window, cx| {
 8734                Tooltip::with_meta_in(
 8735                    primary_action_text,
 8736                    Some(&ToggleBreakpoint),
 8737                    meta.clone(),
 8738                    &focus_handle,
 8739                    cx,
 8740                )
 8741            })
 8742    }
 8743
 8744    fn build_tasks_context(
 8745        project: &Entity<Project>,
 8746        buffer: &Entity<Buffer>,
 8747        buffer_row: u32,
 8748        tasks: &Arc<RunnableTasks>,
 8749        cx: &mut Context<Self>,
 8750    ) -> Task<Option<task::TaskContext>> {
 8751        let position = Point::new(buffer_row, tasks.column);
 8752        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 8753        let location = Location {
 8754            buffer: buffer.clone(),
 8755            range: range_start..range_start,
 8756        };
 8757        // Fill in the environmental variables from the tree-sitter captures
 8758        let mut captured_task_variables = TaskVariables::default();
 8759        for (capture_name, value) in tasks.extra_variables.clone() {
 8760            captured_task_variables.insert(
 8761                task::VariableName::Custom(capture_name.into()),
 8762                value.clone(),
 8763            );
 8764        }
 8765        project.update(cx, |project, cx| {
 8766            project.task_store().update(cx, |task_store, cx| {
 8767                task_store.task_context_for_location(captured_task_variables, location, cx)
 8768            })
 8769        })
 8770    }
 8771
 8772    pub fn spawn_nearest_task(
 8773        &mut self,
 8774        action: &SpawnNearestTask,
 8775        window: &mut Window,
 8776        cx: &mut Context<Self>,
 8777    ) {
 8778        let Some((workspace, _)) = self.workspace.clone() else {
 8779            return;
 8780        };
 8781        let Some(project) = self.project.clone() else {
 8782            return;
 8783        };
 8784
 8785        // Try to find a closest, enclosing node using tree-sitter that has a task
 8786        let Some((buffer, buffer_row, tasks)) = self
 8787            .find_enclosing_node_task(cx)
 8788            // Or find the task that's closest in row-distance.
 8789            .or_else(|| self.find_closest_task(cx))
 8790        else {
 8791            return;
 8792        };
 8793
 8794        let reveal_strategy = action.reveal;
 8795        let task_context = Self::build_tasks_context(&project, &buffer, buffer_row, &tasks, cx);
 8796        cx.spawn_in(window, async move |_, cx| {
 8797            let context = task_context.await?;
 8798            let (task_source_kind, mut resolved_task) = tasks.resolve(&context).next()?;
 8799
 8800            let resolved = &mut resolved_task.resolved;
 8801            resolved.reveal = reveal_strategy;
 8802
 8803            workspace
 8804                .update_in(cx, |workspace, window, cx| {
 8805                    workspace.schedule_resolved_task(
 8806                        task_source_kind,
 8807                        resolved_task,
 8808                        false,
 8809                        window,
 8810                        cx,
 8811                    );
 8812                })
 8813                .ok()
 8814        })
 8815        .detach();
 8816    }
 8817
 8818    fn find_closest_task(
 8819        &mut self,
 8820        cx: &mut Context<Self>,
 8821    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8822        let cursor_row = self
 8823            .selections
 8824            .newest_adjusted(&self.display_snapshot(cx))
 8825            .head()
 8826            .row;
 8827
 8828        let ((buffer_id, row), tasks) = self
 8829            .tasks
 8830            .iter()
 8831            .min_by_key(|((_, row), _)| cursor_row.abs_diff(*row))?;
 8832
 8833        let buffer = self.buffer.read(cx).buffer(*buffer_id)?;
 8834        let tasks = Arc::new(tasks.to_owned());
 8835        Some((buffer, *row, tasks))
 8836    }
 8837
 8838    fn find_enclosing_node_task(
 8839        &mut self,
 8840        cx: &mut Context<Self>,
 8841    ) -> Option<(Entity<Buffer>, u32, Arc<RunnableTasks>)> {
 8842        let snapshot = self.buffer.read(cx).snapshot(cx);
 8843        let offset = self
 8844            .selections
 8845            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 8846            .head();
 8847        let mut excerpt = snapshot.excerpt_containing(offset..offset)?;
 8848        let offset = excerpt.map_offset_to_buffer(offset);
 8849        let buffer_id = excerpt.buffer().remote_id();
 8850
 8851        let layer = excerpt.buffer().syntax_layer_at(offset)?;
 8852        let mut cursor = layer.node().walk();
 8853
 8854        while cursor.goto_first_child_for_byte(offset.0).is_some() {
 8855            if cursor.node().end_byte() == offset.0 {
 8856                cursor.goto_next_sibling();
 8857            }
 8858        }
 8859
 8860        // Ascend to the smallest ancestor that contains the range and has a task.
 8861        loop {
 8862            let node = cursor.node();
 8863            let node_range = node.byte_range();
 8864            let symbol_start_row = excerpt.buffer().offset_to_point(node.start_byte()).row;
 8865
 8866            // Check if this node contains our offset
 8867            if node_range.start <= offset.0 && node_range.end >= offset.0 {
 8868                // If it contains offset, check for task
 8869                if let Some(tasks) = self.tasks.get(&(buffer_id, symbol_start_row)) {
 8870                    let buffer = self.buffer.read(cx).buffer(buffer_id)?;
 8871                    return Some((buffer, symbol_start_row, Arc::new(tasks.to_owned())));
 8872                }
 8873            }
 8874
 8875            if !cursor.goto_parent() {
 8876                break;
 8877            }
 8878        }
 8879        None
 8880    }
 8881
 8882    fn render_run_indicator(
 8883        &self,
 8884        _style: &EditorStyle,
 8885        is_active: bool,
 8886        row: DisplayRow,
 8887        breakpoint: Option<(Anchor, Breakpoint, Option<BreakpointSessionState>)>,
 8888        cx: &mut Context<Self>,
 8889    ) -> IconButton {
 8890        let color = Color::Muted;
 8891        let position = breakpoint.as_ref().map(|(anchor, _, _)| *anchor);
 8892
 8893        IconButton::new(
 8894            ("run_indicator", row.0 as usize),
 8895            ui::IconName::PlayOutlined,
 8896        )
 8897        .shape(ui::IconButtonShape::Square)
 8898        .icon_size(IconSize::XSmall)
 8899        .icon_color(color)
 8900        .toggle_state(is_active)
 8901        .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
 8902            let quick_launch = match e {
 8903                ClickEvent::Keyboard(_) => true,
 8904                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
 8905            };
 8906
 8907            window.focus(&editor.focus_handle(cx));
 8908            editor.toggle_code_actions(
 8909                &ToggleCodeActions {
 8910                    deployed_from: Some(CodeActionSource::RunMenu(row)),
 8911                    quick_launch,
 8912                },
 8913                window,
 8914                cx,
 8915            );
 8916        }))
 8917        .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 8918            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
 8919        }))
 8920    }
 8921
 8922    pub fn context_menu_visible(&self) -> bool {
 8923        !self.edit_prediction_preview_is_active()
 8924            && self
 8925                .context_menu
 8926                .borrow()
 8927                .as_ref()
 8928                .is_some_and(|menu| menu.visible())
 8929    }
 8930
 8931    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 8932        self.context_menu
 8933            .borrow()
 8934            .as_ref()
 8935            .map(|menu| menu.origin())
 8936    }
 8937
 8938    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 8939        self.context_menu_options = Some(options);
 8940    }
 8941
 8942    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 8943    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 8944
 8945    fn render_edit_prediction_popover(
 8946        &mut self,
 8947        text_bounds: &Bounds<Pixels>,
 8948        content_origin: gpui::Point<Pixels>,
 8949        right_margin: Pixels,
 8950        editor_snapshot: &EditorSnapshot,
 8951        visible_row_range: Range<DisplayRow>,
 8952        scroll_top: ScrollOffset,
 8953        scroll_bottom: ScrollOffset,
 8954        line_layouts: &[LineWithInvisibles],
 8955        line_height: Pixels,
 8956        scroll_position: gpui::Point<ScrollOffset>,
 8957        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 8958        newest_selection_head: Option<DisplayPoint>,
 8959        editor_width: Pixels,
 8960        style: &EditorStyle,
 8961        window: &mut Window,
 8962        cx: &mut App,
 8963    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 8964        if self.mode().is_minimap() {
 8965            return None;
 8966        }
 8967        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 8968
 8969        if self.edit_prediction_visible_in_cursor_popover(true) {
 8970            return None;
 8971        }
 8972
 8973        match &active_edit_prediction.completion {
 8974            EditPrediction::MoveWithin { target, .. } => {
 8975                let target_display_point = target.to_display_point(editor_snapshot);
 8976
 8977                if self.edit_prediction_requires_modifier() {
 8978                    if !self.edit_prediction_preview_is_active() {
 8979                        return None;
 8980                    }
 8981
 8982                    self.render_edit_prediction_modifier_jump_popover(
 8983                        text_bounds,
 8984                        content_origin,
 8985                        visible_row_range,
 8986                        line_layouts,
 8987                        line_height,
 8988                        scroll_pixel_position,
 8989                        newest_selection_head,
 8990                        target_display_point,
 8991                        window,
 8992                        cx,
 8993                    )
 8994                } else {
 8995                    self.render_edit_prediction_eager_jump_popover(
 8996                        text_bounds,
 8997                        content_origin,
 8998                        editor_snapshot,
 8999                        visible_row_range,
 9000                        scroll_top,
 9001                        scroll_bottom,
 9002                        line_height,
 9003                        scroll_pixel_position,
 9004                        target_display_point,
 9005                        editor_width,
 9006                        window,
 9007                        cx,
 9008                    )
 9009                }
 9010            }
 9011            EditPrediction::Edit {
 9012                display_mode: EditDisplayMode::Inline,
 9013                ..
 9014            } => None,
 9015            EditPrediction::Edit {
 9016                display_mode: EditDisplayMode::TabAccept,
 9017                edits,
 9018                ..
 9019            } => {
 9020                let range = &edits.first()?.0;
 9021                let target_display_point = range.end.to_display_point(editor_snapshot);
 9022
 9023                self.render_edit_prediction_end_of_line_popover(
 9024                    "Accept",
 9025                    editor_snapshot,
 9026                    visible_row_range,
 9027                    target_display_point,
 9028                    line_height,
 9029                    scroll_pixel_position,
 9030                    content_origin,
 9031                    editor_width,
 9032                    window,
 9033                    cx,
 9034                )
 9035            }
 9036            EditPrediction::Edit {
 9037                edits,
 9038                edit_preview,
 9039                display_mode: EditDisplayMode::DiffPopover,
 9040                snapshot,
 9041            } => self.render_edit_prediction_diff_popover(
 9042                text_bounds,
 9043                content_origin,
 9044                right_margin,
 9045                editor_snapshot,
 9046                visible_row_range,
 9047                line_layouts,
 9048                line_height,
 9049                scroll_position,
 9050                scroll_pixel_position,
 9051                newest_selection_head,
 9052                editor_width,
 9053                style,
 9054                edits,
 9055                edit_preview,
 9056                snapshot,
 9057                window,
 9058                cx,
 9059            ),
 9060            EditPrediction::MoveOutside { snapshot, .. } => {
 9061                let mut element = self
 9062                    .render_edit_prediction_jump_outside_popover(snapshot, window, cx)
 9063                    .into_any();
 9064
 9065                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9066                let origin_x = text_bounds.size.width - size.width - px(30.);
 9067                let origin = text_bounds.origin + gpui::Point::new(origin_x, px(16.));
 9068                element.prepaint_at(origin, window, cx);
 9069
 9070                Some((element, origin))
 9071            }
 9072        }
 9073    }
 9074
 9075    fn render_edit_prediction_modifier_jump_popover(
 9076        &mut self,
 9077        text_bounds: &Bounds<Pixels>,
 9078        content_origin: gpui::Point<Pixels>,
 9079        visible_row_range: Range<DisplayRow>,
 9080        line_layouts: &[LineWithInvisibles],
 9081        line_height: Pixels,
 9082        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9083        newest_selection_head: Option<DisplayPoint>,
 9084        target_display_point: DisplayPoint,
 9085        window: &mut Window,
 9086        cx: &mut App,
 9087    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9088        let scrolled_content_origin =
 9089            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 9090
 9091        const SCROLL_PADDING_Y: Pixels = px(12.);
 9092
 9093        if target_display_point.row() < visible_row_range.start {
 9094            return self.render_edit_prediction_scroll_popover(
 9095                |_| SCROLL_PADDING_Y,
 9096                IconName::ArrowUp,
 9097                visible_row_range,
 9098                line_layouts,
 9099                newest_selection_head,
 9100                scrolled_content_origin,
 9101                window,
 9102                cx,
 9103            );
 9104        } else if target_display_point.row() >= visible_row_range.end {
 9105            return self.render_edit_prediction_scroll_popover(
 9106                |size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 9107                IconName::ArrowDown,
 9108                visible_row_range,
 9109                line_layouts,
 9110                newest_selection_head,
 9111                scrolled_content_origin,
 9112                window,
 9113                cx,
 9114            );
 9115        }
 9116
 9117        const POLE_WIDTH: Pixels = px(2.);
 9118
 9119        let line_layout =
 9120            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 9121        let target_column = target_display_point.column() as usize;
 9122
 9123        let target_x = line_layout.x_for_index(target_column);
 9124        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 9125            - scroll_pixel_position.y;
 9126
 9127        let flag_on_right = target_x < text_bounds.size.width / 2.;
 9128
 9129        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 9130        border_color.l += 0.001;
 9131
 9132        let mut element = v_flex()
 9133            .items_end()
 9134            .when(flag_on_right, |el| el.items_start())
 9135            .child(if flag_on_right {
 9136                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9137                    .rounded_bl(px(0.))
 9138                    .rounded_tl(px(0.))
 9139                    .border_l_2()
 9140                    .border_color(border_color)
 9141            } else {
 9142                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9143                    .rounded_br(px(0.))
 9144                    .rounded_tr(px(0.))
 9145                    .border_r_2()
 9146                    .border_color(border_color)
 9147            })
 9148            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 9149            .into_any();
 9150
 9151        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9152
 9153        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 9154            - point(
 9155                if flag_on_right {
 9156                    POLE_WIDTH
 9157                } else {
 9158                    size.width - POLE_WIDTH
 9159                },
 9160                size.height - line_height,
 9161            );
 9162
 9163        origin.x = origin.x.max(content_origin.x);
 9164
 9165        element.prepaint_at(origin, window, cx);
 9166
 9167        Some((element, origin))
 9168    }
 9169
 9170    fn render_edit_prediction_scroll_popover(
 9171        &mut self,
 9172        to_y: impl Fn(Size<Pixels>) -> Pixels,
 9173        scroll_icon: IconName,
 9174        visible_row_range: Range<DisplayRow>,
 9175        line_layouts: &[LineWithInvisibles],
 9176        newest_selection_head: Option<DisplayPoint>,
 9177        scrolled_content_origin: gpui::Point<Pixels>,
 9178        window: &mut Window,
 9179        cx: &mut App,
 9180    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9181        let mut element = self
 9182            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 9183            .into_any();
 9184
 9185        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9186
 9187        let cursor = newest_selection_head?;
 9188        let cursor_row_layout =
 9189            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 9190        let cursor_column = cursor.column() as usize;
 9191
 9192        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 9193
 9194        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 9195
 9196        element.prepaint_at(origin, window, cx);
 9197        Some((element, origin))
 9198    }
 9199
 9200    fn render_edit_prediction_eager_jump_popover(
 9201        &mut self,
 9202        text_bounds: &Bounds<Pixels>,
 9203        content_origin: gpui::Point<Pixels>,
 9204        editor_snapshot: &EditorSnapshot,
 9205        visible_row_range: Range<DisplayRow>,
 9206        scroll_top: ScrollOffset,
 9207        scroll_bottom: ScrollOffset,
 9208        line_height: Pixels,
 9209        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9210        target_display_point: DisplayPoint,
 9211        editor_width: Pixels,
 9212        window: &mut Window,
 9213        cx: &mut App,
 9214    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9215        if target_display_point.row().as_f64() < scroll_top {
 9216            let mut element = self
 9217                .render_edit_prediction_line_popover(
 9218                    "Jump to Edit",
 9219                    Some(IconName::ArrowUp),
 9220                    window,
 9221                    cx,
 9222                )
 9223                .into_any();
 9224
 9225            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9226            let offset = point(
 9227                (text_bounds.size.width - size.width) / 2.,
 9228                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9229            );
 9230
 9231            let origin = text_bounds.origin + offset;
 9232            element.prepaint_at(origin, window, cx);
 9233            Some((element, origin))
 9234        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 9235            let mut element = self
 9236                .render_edit_prediction_line_popover(
 9237                    "Jump to Edit",
 9238                    Some(IconName::ArrowDown),
 9239                    window,
 9240                    cx,
 9241                )
 9242                .into_any();
 9243
 9244            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9245            let offset = point(
 9246                (text_bounds.size.width - size.width) / 2.,
 9247                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9248            );
 9249
 9250            let origin = text_bounds.origin + offset;
 9251            element.prepaint_at(origin, window, cx);
 9252            Some((element, origin))
 9253        } else {
 9254            self.render_edit_prediction_end_of_line_popover(
 9255                "Jump to Edit",
 9256                editor_snapshot,
 9257                visible_row_range,
 9258                target_display_point,
 9259                line_height,
 9260                scroll_pixel_position,
 9261                content_origin,
 9262                editor_width,
 9263                window,
 9264                cx,
 9265            )
 9266        }
 9267    }
 9268
 9269    fn render_edit_prediction_end_of_line_popover(
 9270        self: &mut Editor,
 9271        label: &'static str,
 9272        editor_snapshot: &EditorSnapshot,
 9273        visible_row_range: Range<DisplayRow>,
 9274        target_display_point: DisplayPoint,
 9275        line_height: Pixels,
 9276        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9277        content_origin: gpui::Point<Pixels>,
 9278        editor_width: Pixels,
 9279        window: &mut Window,
 9280        cx: &mut App,
 9281    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9282        let target_line_end = DisplayPoint::new(
 9283            target_display_point.row(),
 9284            editor_snapshot.line_len(target_display_point.row()),
 9285        );
 9286
 9287        let mut element = self
 9288            .render_edit_prediction_line_popover(label, None, window, cx)
 9289            .into_any();
 9290
 9291        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9292
 9293        let line_origin =
 9294            self.display_to_pixel_point(target_line_end, editor_snapshot, window, cx)?;
 9295
 9296        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9297        let mut origin = start_point
 9298            + line_origin
 9299            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9300        origin.x = origin.x.max(content_origin.x);
 9301
 9302        let max_x = content_origin.x + editor_width - size.width;
 9303
 9304        if origin.x > max_x {
 9305            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9306
 9307            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9308                origin.y += offset;
 9309                IconName::ArrowUp
 9310            } else {
 9311                origin.y -= offset;
 9312                IconName::ArrowDown
 9313            };
 9314
 9315            element = self
 9316                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9317                .into_any();
 9318
 9319            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9320
 9321            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9322        }
 9323
 9324        element.prepaint_at(origin, window, cx);
 9325        Some((element, origin))
 9326    }
 9327
 9328    fn render_edit_prediction_diff_popover(
 9329        self: &Editor,
 9330        text_bounds: &Bounds<Pixels>,
 9331        content_origin: gpui::Point<Pixels>,
 9332        right_margin: Pixels,
 9333        editor_snapshot: &EditorSnapshot,
 9334        visible_row_range: Range<DisplayRow>,
 9335        line_layouts: &[LineWithInvisibles],
 9336        line_height: Pixels,
 9337        scroll_position: gpui::Point<ScrollOffset>,
 9338        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9339        newest_selection_head: Option<DisplayPoint>,
 9340        editor_width: Pixels,
 9341        style: &EditorStyle,
 9342        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9343        edit_preview: &Option<language::EditPreview>,
 9344        snapshot: &language::BufferSnapshot,
 9345        window: &mut Window,
 9346        cx: &mut App,
 9347    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9348        let edit_start = edits
 9349            .first()
 9350            .unwrap()
 9351            .0
 9352            .start
 9353            .to_display_point(editor_snapshot);
 9354        let edit_end = edits
 9355            .last()
 9356            .unwrap()
 9357            .0
 9358            .end
 9359            .to_display_point(editor_snapshot);
 9360
 9361        let is_visible = visible_row_range.contains(&edit_start.row())
 9362            || visible_row_range.contains(&edit_end.row());
 9363        if !is_visible {
 9364            return None;
 9365        }
 9366
 9367        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9368            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9369        } else {
 9370            // Fallback for providers without edit_preview
 9371            crate::edit_prediction_fallback_text(edits, cx)
 9372        };
 9373
 9374        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9375        let line_count = highlighted_edits.text.lines().count();
 9376
 9377        const BORDER_WIDTH: Pixels = px(1.);
 9378
 9379        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9380        let has_keybind = keybind.is_some();
 9381
 9382        let mut element = h_flex()
 9383            .items_start()
 9384            .child(
 9385                h_flex()
 9386                    .bg(cx.theme().colors().editor_background)
 9387                    .border(BORDER_WIDTH)
 9388                    .shadow_xs()
 9389                    .border_color(cx.theme().colors().border)
 9390                    .rounded_l_lg()
 9391                    .when(line_count > 1, |el| el.rounded_br_lg())
 9392                    .pr_1()
 9393                    .child(styled_text),
 9394            )
 9395            .child(
 9396                h_flex()
 9397                    .h(line_height + BORDER_WIDTH * 2.)
 9398                    .px_1p5()
 9399                    .gap_1()
 9400                    // Workaround: For some reason, there's a gap if we don't do this
 9401                    .ml(-BORDER_WIDTH)
 9402                    .shadow(vec![gpui::BoxShadow {
 9403                        color: gpui::black().opacity(0.05),
 9404                        offset: point(px(1.), px(1.)),
 9405                        blur_radius: px(2.),
 9406                        spread_radius: px(0.),
 9407                    }])
 9408                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9409                    .border(BORDER_WIDTH)
 9410                    .border_color(cx.theme().colors().border)
 9411                    .rounded_r_lg()
 9412                    .id("edit_prediction_diff_popover_keybind")
 9413                    .when(!has_keybind, |el| {
 9414                        let status_colors = cx.theme().status();
 9415
 9416                        el.bg(status_colors.error_background)
 9417                            .border_color(status_colors.error.opacity(0.6))
 9418                            .child(Icon::new(IconName::Info).color(Color::Error))
 9419                            .cursor_default()
 9420                            .hoverable_tooltip(move |_window, cx| {
 9421                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9422                            })
 9423                    })
 9424                    .children(keybind),
 9425            )
 9426            .into_any();
 9427
 9428        let longest_row =
 9429            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9430        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9431            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9432        } else {
 9433            layout_line(
 9434                longest_row,
 9435                editor_snapshot,
 9436                style,
 9437                editor_width,
 9438                |_| false,
 9439                window,
 9440                cx,
 9441            )
 9442            .width
 9443        };
 9444
 9445        let viewport_bounds =
 9446            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9447                right: -right_margin,
 9448                ..Default::default()
 9449            });
 9450
 9451        let x_after_longest = Pixels::from(
 9452            ScrollPixelOffset::from(
 9453                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9454            ) - scroll_pixel_position.x,
 9455        );
 9456
 9457        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9458
 9459        // Fully visible if it can be displayed within the window (allow overlapping other
 9460        // panes). However, this is only allowed if the popover starts within text_bounds.
 9461        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9462            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9463
 9464        let mut origin = if can_position_to_the_right {
 9465            point(
 9466                x_after_longest,
 9467                text_bounds.origin.y
 9468                    + Pixels::from(
 9469                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9470                            - scroll_pixel_position.y,
 9471                    ),
 9472            )
 9473        } else {
 9474            let cursor_row = newest_selection_head.map(|head| head.row());
 9475            let above_edit = edit_start
 9476                .row()
 9477                .0
 9478                .checked_sub(line_count as u32)
 9479                .map(DisplayRow);
 9480            let below_edit = Some(edit_end.row() + 1);
 9481            let above_cursor =
 9482                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9483            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9484
 9485            // Place the edit popover adjacent to the edit if there is a location
 9486            // available that is onscreen and does not obscure the cursor. Otherwise,
 9487            // place it adjacent to the cursor.
 9488            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9489                .into_iter()
 9490                .flatten()
 9491                .find(|&start_row| {
 9492                    let end_row = start_row + line_count as u32;
 9493                    visible_row_range.contains(&start_row)
 9494                        && visible_row_range.contains(&end_row)
 9495                        && cursor_row
 9496                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9497                })?;
 9498
 9499            content_origin
 9500                + point(
 9501                    Pixels::from(-scroll_pixel_position.x),
 9502                    Pixels::from(
 9503                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9504                    ),
 9505                )
 9506        };
 9507
 9508        origin.x -= BORDER_WIDTH;
 9509
 9510        window.defer_draw(element, origin, 1);
 9511
 9512        // Do not return an element, since it will already be drawn due to defer_draw.
 9513        None
 9514    }
 9515
 9516    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9517        px(30.)
 9518    }
 9519
 9520    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9521        if self.read_only(cx) {
 9522            cx.theme().players().read_only()
 9523        } else {
 9524            self.style.as_ref().unwrap().local_player
 9525        }
 9526    }
 9527
 9528    fn render_edit_prediction_accept_keybind(
 9529        &self,
 9530        window: &mut Window,
 9531        cx: &mut App,
 9532    ) -> Option<AnyElement> {
 9533        let accept_binding =
 9534            self.accept_edit_prediction_keybind(EditPredictionGranularity::Full, window, cx);
 9535        let accept_keystroke = accept_binding.keystroke()?;
 9536
 9537        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9538
 9539        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9540            Color::Accent
 9541        } else {
 9542            Color::Muted
 9543        };
 9544
 9545        h_flex()
 9546            .px_0p5()
 9547            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9548            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9549            .text_size(TextSize::XSmall.rems(cx))
 9550            .child(h_flex().children(ui::render_modifiers(
 9551                accept_keystroke.modifiers(),
 9552                PlatformStyle::platform(),
 9553                Some(modifiers_color),
 9554                Some(IconSize::XSmall.rems().into()),
 9555                true,
 9556            )))
 9557            .when(is_platform_style_mac, |parent| {
 9558                parent.child(accept_keystroke.key().to_string())
 9559            })
 9560            .when(!is_platform_style_mac, |parent| {
 9561                parent.child(
 9562                    Key::new(
 9563                        util::capitalize(accept_keystroke.key()),
 9564                        Some(Color::Default),
 9565                    )
 9566                    .size(Some(IconSize::XSmall.rems().into())),
 9567                )
 9568            })
 9569            .into_any()
 9570            .into()
 9571    }
 9572
 9573    fn render_edit_prediction_line_popover(
 9574        &self,
 9575        label: impl Into<SharedString>,
 9576        icon: Option<IconName>,
 9577        window: &mut Window,
 9578        cx: &mut App,
 9579    ) -> Stateful<Div> {
 9580        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9581
 9582        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9583        let has_keybind = keybind.is_some();
 9584
 9585        h_flex()
 9586            .id("ep-line-popover")
 9587            .py_0p5()
 9588            .pl_1()
 9589            .pr(padding_right)
 9590            .gap_1()
 9591            .rounded_md()
 9592            .border_1()
 9593            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9594            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9595            .shadow_xs()
 9596            .when(!has_keybind, |el| {
 9597                let status_colors = cx.theme().status();
 9598
 9599                el.bg(status_colors.error_background)
 9600                    .border_color(status_colors.error.opacity(0.6))
 9601                    .pl_2()
 9602                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9603                    .cursor_default()
 9604                    .hoverable_tooltip(move |_window, cx| {
 9605                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9606                    })
 9607            })
 9608            .children(keybind)
 9609            .child(
 9610                Label::new(label)
 9611                    .size(LabelSize::Small)
 9612                    .when(!has_keybind, |el| {
 9613                        el.color(cx.theme().status().error.into()).strikethrough()
 9614                    }),
 9615            )
 9616            .when(!has_keybind, |el| {
 9617                el.child(
 9618                    h_flex().ml_1().child(
 9619                        Icon::new(IconName::Info)
 9620                            .size(IconSize::Small)
 9621                            .color(cx.theme().status().error.into()),
 9622                    ),
 9623                )
 9624            })
 9625            .when_some(icon, |element, icon| {
 9626                element.child(
 9627                    div()
 9628                        .mt(px(1.5))
 9629                        .child(Icon::new(icon).size(IconSize::Small)),
 9630                )
 9631            })
 9632    }
 9633
 9634    fn render_edit_prediction_jump_outside_popover(
 9635        &self,
 9636        snapshot: &BufferSnapshot,
 9637        window: &mut Window,
 9638        cx: &mut App,
 9639    ) -> Stateful<Div> {
 9640        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9641        let has_keybind = keybind.is_some();
 9642
 9643        let file_name = snapshot
 9644            .file()
 9645            .map(|file| SharedString::new(file.file_name(cx)))
 9646            .unwrap_or(SharedString::new_static("untitled"));
 9647
 9648        h_flex()
 9649            .id("ep-jump-outside-popover")
 9650            .py_1()
 9651            .px_2()
 9652            .gap_1()
 9653            .rounded_md()
 9654            .border_1()
 9655            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9656            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9657            .shadow_xs()
 9658            .when(!has_keybind, |el| {
 9659                let status_colors = cx.theme().status();
 9660
 9661                el.bg(status_colors.error_background)
 9662                    .border_color(status_colors.error.opacity(0.6))
 9663                    .pl_2()
 9664                    .child(Icon::new(IconName::ZedPredictError).color(Color::Error))
 9665                    .cursor_default()
 9666                    .hoverable_tooltip(move |_window, cx| {
 9667                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9668                    })
 9669            })
 9670            .children(keybind)
 9671            .child(
 9672                Label::new(file_name)
 9673                    .size(LabelSize::Small)
 9674                    .buffer_font(cx)
 9675                    .when(!has_keybind, |el| {
 9676                        el.color(cx.theme().status().error.into()).strikethrough()
 9677                    }),
 9678            )
 9679            .when(!has_keybind, |el| {
 9680                el.child(
 9681                    h_flex().ml_1().child(
 9682                        Icon::new(IconName::Info)
 9683                            .size(IconSize::Small)
 9684                            .color(cx.theme().status().error.into()),
 9685                    ),
 9686                )
 9687            })
 9688            .child(
 9689                div()
 9690                    .mt(px(1.5))
 9691                    .child(Icon::new(IconName::ArrowUpRight).size(IconSize::Small)),
 9692            )
 9693    }
 9694
 9695    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9696        let accent_color = cx.theme().colors().text_accent;
 9697        let editor_bg_color = cx.theme().colors().editor_background;
 9698        editor_bg_color.blend(accent_color.opacity(0.1))
 9699    }
 9700
 9701    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9702        let accent_color = cx.theme().colors().text_accent;
 9703        let editor_bg_color = cx.theme().colors().editor_background;
 9704        editor_bg_color.blend(accent_color.opacity(0.6))
 9705    }
 9706    fn get_prediction_provider_icon_name(
 9707        provider: &Option<RegisteredEditPredictionDelegate>,
 9708    ) -> IconName {
 9709        match provider {
 9710            Some(provider) => match provider.provider.name() {
 9711                "copilot" => IconName::Copilot,
 9712                "supermaven" => IconName::Supermaven,
 9713                _ => IconName::ZedPredict,
 9714            },
 9715            None => IconName::ZedPredict,
 9716        }
 9717    }
 9718
 9719    fn render_edit_prediction_cursor_popover(
 9720        &self,
 9721        min_width: Pixels,
 9722        max_width: Pixels,
 9723        cursor_point: Point,
 9724        style: &EditorStyle,
 9725        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9726        _window: &Window,
 9727        cx: &mut Context<Editor>,
 9728    ) -> Option<AnyElement> {
 9729        let provider = self.edit_prediction_provider.as_ref()?;
 9730        let provider_icon = Self::get_prediction_provider_icon_name(&self.edit_prediction_provider);
 9731
 9732        let is_refreshing = provider.provider.is_refreshing(cx);
 9733
 9734        fn pending_completion_container(icon: IconName) -> Div {
 9735            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9736        }
 9737
 9738        let completion = match &self.active_edit_prediction {
 9739            Some(prediction) => {
 9740                if !self.has_visible_completions_menu() {
 9741                    const RADIUS: Pixels = px(6.);
 9742                    const BORDER_WIDTH: Pixels = px(1.);
 9743
 9744                    return Some(
 9745                        h_flex()
 9746                            .elevation_2(cx)
 9747                            .border(BORDER_WIDTH)
 9748                            .border_color(cx.theme().colors().border)
 9749                            .when(accept_keystroke.is_none(), |el| {
 9750                                el.border_color(cx.theme().status().error)
 9751                            })
 9752                            .rounded(RADIUS)
 9753                            .rounded_tl(px(0.))
 9754                            .overflow_hidden()
 9755                            .child(div().px_1p5().child(match &prediction.completion {
 9756                                EditPrediction::MoveWithin { target, snapshot } => {
 9757                                    use text::ToPoint as _;
 9758                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9759                                    {
 9760                                        Icon::new(IconName::ZedPredictDown)
 9761                                    } else {
 9762                                        Icon::new(IconName::ZedPredictUp)
 9763                                    }
 9764                                }
 9765                                EditPrediction::MoveOutside { .. } => {
 9766                                    // TODO [zeta2] custom icon for external jump?
 9767                                    Icon::new(provider_icon)
 9768                                }
 9769                                EditPrediction::Edit { .. } => Icon::new(provider_icon),
 9770                            }))
 9771                            .child(
 9772                                h_flex()
 9773                                    .gap_1()
 9774                                    .py_1()
 9775                                    .px_2()
 9776                                    .rounded_r(RADIUS - BORDER_WIDTH)
 9777                                    .border_l_1()
 9778                                    .border_color(cx.theme().colors().border)
 9779                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9780                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
 9781                                        el.child(
 9782                                            Label::new("Hold")
 9783                                                .size(LabelSize::Small)
 9784                                                .when(accept_keystroke.is_none(), |el| {
 9785                                                    el.strikethrough()
 9786                                                })
 9787                                                .line_height_style(LineHeightStyle::UiLabel),
 9788                                        )
 9789                                    })
 9790                                    .id("edit_prediction_cursor_popover_keybind")
 9791                                    .when(accept_keystroke.is_none(), |el| {
 9792                                        let status_colors = cx.theme().status();
 9793
 9794                                        el.bg(status_colors.error_background)
 9795                                            .border_color(status_colors.error.opacity(0.6))
 9796                                            .child(Icon::new(IconName::Info).color(Color::Error))
 9797                                            .cursor_default()
 9798                                            .hoverable_tooltip(move |_window, cx| {
 9799                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
 9800                                                    .into()
 9801                                            })
 9802                                    })
 9803                                    .when_some(
 9804                                        accept_keystroke.as_ref(),
 9805                                        |el, accept_keystroke| {
 9806                                            el.child(h_flex().children(ui::render_modifiers(
 9807                                                accept_keystroke.modifiers(),
 9808                                                PlatformStyle::platform(),
 9809                                                Some(Color::Default),
 9810                                                Some(IconSize::XSmall.rems().into()),
 9811                                                false,
 9812                                            )))
 9813                                        },
 9814                                    ),
 9815                            )
 9816                            .into_any(),
 9817                    );
 9818                }
 9819
 9820                self.render_edit_prediction_cursor_popover_preview(
 9821                    prediction,
 9822                    cursor_point,
 9823                    style,
 9824                    cx,
 9825                )?
 9826            }
 9827
 9828            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
 9829                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
 9830                    stale_completion,
 9831                    cursor_point,
 9832                    style,
 9833                    cx,
 9834                )?,
 9835
 9836                None => pending_completion_container(provider_icon)
 9837                    .child(Label::new("...").size(LabelSize::Small)),
 9838            },
 9839
 9840            None => pending_completion_container(provider_icon)
 9841                .child(Label::new("...").size(LabelSize::Small)),
 9842        };
 9843
 9844        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
 9845            completion
 9846                .with_animation(
 9847                    "loading-completion",
 9848                    Animation::new(Duration::from_secs(2))
 9849                        .repeat()
 9850                        .with_easing(pulsating_between(0.4, 0.8)),
 9851                    |label, delta| label.opacity(delta),
 9852                )
 9853                .into_any_element()
 9854        } else {
 9855            completion.into_any_element()
 9856        };
 9857
 9858        let has_completion = self.active_edit_prediction.is_some();
 9859
 9860        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9861        Some(
 9862            h_flex()
 9863                .min_w(min_width)
 9864                .max_w(max_width)
 9865                .flex_1()
 9866                .elevation_2(cx)
 9867                .border_color(cx.theme().colors().border)
 9868                .child(
 9869                    div()
 9870                        .flex_1()
 9871                        .py_1()
 9872                        .px_2()
 9873                        .overflow_hidden()
 9874                        .child(completion),
 9875                )
 9876                .when_some(accept_keystroke, |el, accept_keystroke| {
 9877                    if !accept_keystroke.modifiers().modified() {
 9878                        return el;
 9879                    }
 9880
 9881                    el.child(
 9882                        h_flex()
 9883                            .h_full()
 9884                            .border_l_1()
 9885                            .rounded_r_lg()
 9886                            .border_color(cx.theme().colors().border)
 9887                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9888                            .gap_1()
 9889                            .py_1()
 9890                            .px_2()
 9891                            .child(
 9892                                h_flex()
 9893                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9894                                    .when(is_platform_style_mac, |parent| parent.gap_1())
 9895                                    .child(h_flex().children(ui::render_modifiers(
 9896                                        accept_keystroke.modifiers(),
 9897                                        PlatformStyle::platform(),
 9898                                        Some(if !has_completion {
 9899                                            Color::Muted
 9900                                        } else {
 9901                                            Color::Default
 9902                                        }),
 9903                                        None,
 9904                                        false,
 9905                                    ))),
 9906                            )
 9907                            .child(Label::new("Preview").into_any_element())
 9908                            .opacity(if has_completion { 1.0 } else { 0.4 }),
 9909                    )
 9910                })
 9911                .into_any(),
 9912        )
 9913    }
 9914
 9915    fn render_edit_prediction_cursor_popover_preview(
 9916        &self,
 9917        completion: &EditPredictionState,
 9918        cursor_point: Point,
 9919        style: &EditorStyle,
 9920        cx: &mut Context<Editor>,
 9921    ) -> Option<Div> {
 9922        use text::ToPoint as _;
 9923
 9924        fn render_relative_row_jump(
 9925            prefix: impl Into<String>,
 9926            current_row: u32,
 9927            target_row: u32,
 9928        ) -> Div {
 9929            let (row_diff, arrow) = if target_row < current_row {
 9930                (current_row - target_row, IconName::ArrowUp)
 9931            } else {
 9932                (target_row - current_row, IconName::ArrowDown)
 9933            };
 9934
 9935            h_flex()
 9936                .child(
 9937                    Label::new(format!("{}{}", prefix.into(), row_diff))
 9938                        .color(Color::Muted)
 9939                        .size(LabelSize::Small),
 9940                )
 9941                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
 9942        }
 9943
 9944        let supports_jump = self
 9945            .edit_prediction_provider
 9946            .as_ref()
 9947            .map(|provider| provider.provider.supports_jump_to_edit())
 9948            .unwrap_or(true);
 9949
 9950        match &completion.completion {
 9951            EditPrediction::MoveWithin {
 9952                target, snapshot, ..
 9953            } => {
 9954                if !supports_jump {
 9955                    return None;
 9956                }
 9957
 9958                Some(
 9959                    h_flex()
 9960                        .px_2()
 9961                        .gap_2()
 9962                        .flex_1()
 9963                        .child(
 9964                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
 9965                                Icon::new(IconName::ZedPredictDown)
 9966                            } else {
 9967                                Icon::new(IconName::ZedPredictUp)
 9968                            },
 9969                        )
 9970                        .child(Label::new("Jump to Edit")),
 9971                )
 9972            }
 9973            EditPrediction::MoveOutside { snapshot, .. } => {
 9974                let file_name = snapshot
 9975                    .file()
 9976                    .map(|file| file.file_name(cx))
 9977                    .unwrap_or("untitled");
 9978                Some(
 9979                    h_flex()
 9980                        .px_2()
 9981                        .gap_2()
 9982                        .flex_1()
 9983                        .child(Icon::new(IconName::ZedPredict))
 9984                        .child(Label::new(format!("Jump to {file_name}"))),
 9985                )
 9986            }
 9987            EditPrediction::Edit {
 9988                edits,
 9989                edit_preview,
 9990                snapshot,
 9991                display_mode: _,
 9992            } => {
 9993                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
 9994
 9995                let (highlighted_edits, has_more_lines) =
 9996                    if let Some(edit_preview) = edit_preview.as_ref() {
 9997                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
 9998                            .first_line_preview()
 9999                    } else {
10000                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
10001                    };
10002
10003                let styled_text = gpui::StyledText::new(highlighted_edits.text)
10004                    .with_default_highlights(&style.text, highlighted_edits.highlights);
10005
10006                let preview = h_flex()
10007                    .gap_1()
10008                    .min_w_16()
10009                    .child(styled_text)
10010                    .when(has_more_lines, |parent| parent.child(""));
10011
10012                let left = if supports_jump && first_edit_row != cursor_point.row {
10013                    render_relative_row_jump("", cursor_point.row, first_edit_row)
10014                        .into_any_element()
10015                } else {
10016                    let icon_name =
10017                        Editor::get_prediction_provider_icon_name(&self.edit_prediction_provider);
10018                    Icon::new(icon_name).into_any_element()
10019                };
10020
10021                Some(
10022                    h_flex()
10023                        .h_full()
10024                        .flex_1()
10025                        .gap_2()
10026                        .pr_1()
10027                        .overflow_x_hidden()
10028                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
10029                        .child(left)
10030                        .child(preview),
10031                )
10032            }
10033        }
10034    }
10035
10036    pub fn render_context_menu(
10037        &mut self,
10038        max_height_in_lines: u32,
10039        window: &mut Window,
10040        cx: &mut Context<Editor>,
10041    ) -> Option<AnyElement> {
10042        let menu = self.context_menu.borrow();
10043        let menu = menu.as_ref()?;
10044        if !menu.visible() {
10045            return None;
10046        };
10047        self.style
10048            .as_ref()
10049            .map(|style| menu.render(style, max_height_in_lines, window, cx))
10050    }
10051
10052    fn render_context_menu_aside(
10053        &mut self,
10054        max_size: Size<Pixels>,
10055        window: &mut Window,
10056        cx: &mut Context<Editor>,
10057    ) -> Option<AnyElement> {
10058        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
10059            if menu.visible() {
10060                menu.render_aside(max_size, window, cx)
10061            } else {
10062                None
10063            }
10064        })
10065    }
10066
10067    fn hide_context_menu(
10068        &mut self,
10069        window: &mut Window,
10070        cx: &mut Context<Self>,
10071    ) -> Option<CodeContextMenu> {
10072        cx.notify();
10073        self.completion_tasks.clear();
10074        let context_menu = self.context_menu.borrow_mut().take();
10075        self.stale_edit_prediction_in_menu.take();
10076        self.update_visible_edit_prediction(window, cx);
10077        if let Some(CodeContextMenu::Completions(_)) = &context_menu
10078            && let Some(completion_provider) = &self.completion_provider
10079        {
10080            completion_provider.selection_changed(None, window, cx);
10081        }
10082        context_menu
10083    }
10084
10085    fn show_snippet_choices(
10086        &mut self,
10087        choices: &Vec<String>,
10088        selection: Range<Anchor>,
10089        cx: &mut Context<Self>,
10090    ) {
10091        let Some((_, buffer, _)) = self
10092            .buffer()
10093            .read(cx)
10094            .excerpt_containing(selection.start, cx)
10095        else {
10096            return;
10097        };
10098        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
10099        else {
10100            return;
10101        };
10102        if buffer != end_buffer {
10103            log::error!("expected anchor range to have matching buffer IDs");
10104            return;
10105        }
10106
10107        let id = post_inc(&mut self.next_completion_id);
10108        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
10109        let mut context_menu = self.context_menu.borrow_mut();
10110        let old_menu = context_menu.take();
10111        *context_menu = Some(CodeContextMenu::Completions(
10112            CompletionsMenu::new_snippet_choices(
10113                id,
10114                true,
10115                choices,
10116                selection,
10117                buffer,
10118                old_menu.map(|menu| menu.primary_scroll_handle()),
10119                snippet_sort_order,
10120            ),
10121        ));
10122    }
10123
10124    pub fn insert_snippet(
10125        &mut self,
10126        insertion_ranges: &[Range<MultiBufferOffset>],
10127        snippet: Snippet,
10128        window: &mut Window,
10129        cx: &mut Context<Self>,
10130    ) -> Result<()> {
10131        struct Tabstop<T> {
10132            is_end_tabstop: bool,
10133            ranges: Vec<Range<T>>,
10134            choices: Option<Vec<String>>,
10135        }
10136
10137        let tabstops = self.buffer.update(cx, |buffer, cx| {
10138            let snippet_text: Arc<str> = snippet.text.clone().into();
10139            let edits = insertion_ranges
10140                .iter()
10141                .cloned()
10142                .map(|range| (range, snippet_text.clone()));
10143            let autoindent_mode = AutoindentMode::Block {
10144                original_indent_columns: Vec::new(),
10145            };
10146            buffer.edit(edits, Some(autoindent_mode), cx);
10147
10148            let snapshot = &*buffer.read(cx);
10149            let snippet = &snippet;
10150            snippet
10151                .tabstops
10152                .iter()
10153                .map(|tabstop| {
10154                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
10155                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
10156                    });
10157                    let mut tabstop_ranges = tabstop
10158                        .ranges
10159                        .iter()
10160                        .flat_map(|tabstop_range| {
10161                            let mut delta = 0_isize;
10162                            insertion_ranges.iter().map(move |insertion_range| {
10163                                let insertion_start = insertion_range.start + delta;
10164                                delta += snippet.text.len() as isize
10165                                    - (insertion_range.end - insertion_range.start) as isize;
10166
10167                                let start =
10168                                    (insertion_start + tabstop_range.start).min(snapshot.len());
10169                                let end = (insertion_start + tabstop_range.end).min(snapshot.len());
10170                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
10171                            })
10172                        })
10173                        .collect::<Vec<_>>();
10174                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
10175
10176                    Tabstop {
10177                        is_end_tabstop,
10178                        ranges: tabstop_ranges,
10179                        choices: tabstop.choices.clone(),
10180                    }
10181                })
10182                .collect::<Vec<_>>()
10183        });
10184        if let Some(tabstop) = tabstops.first() {
10185            self.change_selections(Default::default(), window, cx, |s| {
10186                // Reverse order so that the first range is the newest created selection.
10187                // Completions will use it and autoscroll will prioritize it.
10188                s.select_ranges(tabstop.ranges.iter().rev().cloned());
10189            });
10190
10191            if let Some(choices) = &tabstop.choices
10192                && let Some(selection) = tabstop.ranges.first()
10193            {
10194                self.show_snippet_choices(choices, selection.clone(), cx)
10195            }
10196
10197            // If we're already at the last tabstop and it's at the end of the snippet,
10198            // we're done, we don't need to keep the state around.
10199            if !tabstop.is_end_tabstop {
10200                let choices = tabstops
10201                    .iter()
10202                    .map(|tabstop| tabstop.choices.clone())
10203                    .collect();
10204
10205                let ranges = tabstops
10206                    .into_iter()
10207                    .map(|tabstop| tabstop.ranges)
10208                    .collect::<Vec<_>>();
10209
10210                self.snippet_stack.push(SnippetState {
10211                    active_index: 0,
10212                    ranges,
10213                    choices,
10214                });
10215            }
10216
10217            // Check whether the just-entered snippet ends with an auto-closable bracket.
10218            if self.autoclose_regions.is_empty() {
10219                let snapshot = self.buffer.read(cx).snapshot(cx);
10220                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
10221                    let selection_head = selection.head();
10222                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
10223                        continue;
10224                    };
10225
10226                    let mut bracket_pair = None;
10227                    let max_lookup_length = scope
10228                        .brackets()
10229                        .map(|(pair, _)| {
10230                            pair.start
10231                                .as_str()
10232                                .chars()
10233                                .count()
10234                                .max(pair.end.as_str().chars().count())
10235                        })
10236                        .max();
10237                    if let Some(max_lookup_length) = max_lookup_length {
10238                        let next_text = snapshot
10239                            .chars_at(selection_head)
10240                            .take(max_lookup_length)
10241                            .collect::<String>();
10242                        let prev_text = snapshot
10243                            .reversed_chars_at(selection_head)
10244                            .take(max_lookup_length)
10245                            .collect::<String>();
10246
10247                        for (pair, enabled) in scope.brackets() {
10248                            if enabled
10249                                && pair.close
10250                                && prev_text.starts_with(pair.start.as_str())
10251                                && next_text.starts_with(pair.end.as_str())
10252                            {
10253                                bracket_pair = Some(pair.clone());
10254                                break;
10255                            }
10256                        }
10257                    }
10258
10259                    if let Some(pair) = bracket_pair {
10260                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
10261                        let autoclose_enabled =
10262                            self.use_autoclose && snapshot_settings.use_autoclose;
10263                        if autoclose_enabled {
10264                            let start = snapshot.anchor_after(selection_head);
10265                            let end = snapshot.anchor_after(selection_head);
10266                            self.autoclose_regions.push(AutocloseRegion {
10267                                selection_id: selection.id,
10268                                range: start..end,
10269                                pair,
10270                            });
10271                        }
10272                    }
10273                }
10274            }
10275        }
10276        Ok(())
10277    }
10278
10279    pub fn move_to_next_snippet_tabstop(
10280        &mut self,
10281        window: &mut Window,
10282        cx: &mut Context<Self>,
10283    ) -> bool {
10284        self.move_to_snippet_tabstop(Bias::Right, window, cx)
10285    }
10286
10287    pub fn move_to_prev_snippet_tabstop(
10288        &mut self,
10289        window: &mut Window,
10290        cx: &mut Context<Self>,
10291    ) -> bool {
10292        self.move_to_snippet_tabstop(Bias::Left, window, cx)
10293    }
10294
10295    pub fn move_to_snippet_tabstop(
10296        &mut self,
10297        bias: Bias,
10298        window: &mut Window,
10299        cx: &mut Context<Self>,
10300    ) -> bool {
10301        if let Some(mut snippet) = self.snippet_stack.pop() {
10302            match bias {
10303                Bias::Left => {
10304                    if snippet.active_index > 0 {
10305                        snippet.active_index -= 1;
10306                    } else {
10307                        self.snippet_stack.push(snippet);
10308                        return false;
10309                    }
10310                }
10311                Bias::Right => {
10312                    if snippet.active_index + 1 < snippet.ranges.len() {
10313                        snippet.active_index += 1;
10314                    } else {
10315                        self.snippet_stack.push(snippet);
10316                        return false;
10317                    }
10318                }
10319            }
10320            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10321                self.change_selections(Default::default(), window, cx, |s| {
10322                    // Reverse order so that the first range is the newest created selection.
10323                    // Completions will use it and autoscroll will prioritize it.
10324                    s.select_ranges(current_ranges.iter().rev().cloned())
10325                });
10326
10327                if let Some(choices) = &snippet.choices[snippet.active_index]
10328                    && let Some(selection) = current_ranges.first()
10329                {
10330                    self.show_snippet_choices(choices, selection.clone(), cx);
10331                }
10332
10333                // If snippet state is not at the last tabstop, push it back on the stack
10334                if snippet.active_index + 1 < snippet.ranges.len() {
10335                    self.snippet_stack.push(snippet);
10336                }
10337                return true;
10338            }
10339        }
10340
10341        false
10342    }
10343
10344    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10345        self.transact(window, cx, |this, window, cx| {
10346            this.select_all(&SelectAll, window, cx);
10347            this.insert("", window, cx);
10348        });
10349    }
10350
10351    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10352        if self.read_only(cx) {
10353            return;
10354        }
10355        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10356        self.transact(window, cx, |this, window, cx| {
10357            this.select_autoclose_pair(window, cx);
10358
10359            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10360
10361            let mut linked_ranges = HashMap::<_, Vec<_>>::default();
10362            if !this.linked_edit_ranges.is_empty() {
10363                let selections = this.selections.all::<MultiBufferPoint>(&display_map);
10364                let snapshot = this.buffer.read(cx).snapshot(cx);
10365
10366                for selection in selections.iter() {
10367                    let selection_start = snapshot.anchor_before(selection.start).text_anchor;
10368                    let selection_end = snapshot.anchor_after(selection.end).text_anchor;
10369                    if selection_start.buffer_id != selection_end.buffer_id {
10370                        continue;
10371                    }
10372                    if let Some(ranges) =
10373                        this.linked_editing_ranges_for(selection_start..selection_end, cx)
10374                    {
10375                        for (buffer, entries) in ranges {
10376                            linked_ranges.entry(buffer).or_default().extend(entries);
10377                        }
10378                    }
10379                }
10380            }
10381
10382            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10383            for selection in &mut selections {
10384                if selection.is_empty() {
10385                    let old_head = selection.head();
10386                    let mut new_head =
10387                        movement::left(&display_map, old_head.to_display_point(&display_map))
10388                            .to_point(&display_map);
10389                    if let Some((buffer, line_buffer_range)) = display_map
10390                        .buffer_snapshot()
10391                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10392                    {
10393                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10394                        let indent_len = match indent_size.kind {
10395                            IndentKind::Space => {
10396                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10397                            }
10398                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10399                        };
10400                        if old_head.column <= indent_size.len && old_head.column > 0 {
10401                            let indent_len = indent_len.get();
10402                            new_head = cmp::min(
10403                                new_head,
10404                                MultiBufferPoint::new(
10405                                    old_head.row,
10406                                    ((old_head.column - 1) / indent_len) * indent_len,
10407                                ),
10408                            );
10409                        }
10410                    }
10411
10412                    selection.set_head(new_head, SelectionGoal::None);
10413                }
10414            }
10415
10416            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10417            this.insert("", window, cx);
10418            let empty_str: Arc<str> = Arc::from("");
10419            for (buffer, edits) in linked_ranges {
10420                let snapshot = buffer.read(cx).snapshot();
10421                use text::ToPoint as TP;
10422
10423                let edits = edits
10424                    .into_iter()
10425                    .map(|range| {
10426                        let end_point = TP::to_point(&range.end, &snapshot);
10427                        let mut start_point = TP::to_point(&range.start, &snapshot);
10428
10429                        if end_point == start_point {
10430                            let offset = text::ToOffset::to_offset(&range.start, &snapshot)
10431                                .saturating_sub(1);
10432                            start_point =
10433                                snapshot.clip_point(TP::to_point(&offset, &snapshot), Bias::Left);
10434                        };
10435
10436                        (start_point..end_point, empty_str.clone())
10437                    })
10438                    .sorted_by_key(|(range, _)| range.start)
10439                    .collect::<Vec<_>>();
10440                buffer.update(cx, |this, cx| {
10441                    this.edit(edits, None, cx);
10442                })
10443            }
10444            this.refresh_edit_prediction(true, false, window, cx);
10445            refresh_linked_ranges(this, window, cx);
10446        });
10447    }
10448
10449    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10450        if self.read_only(cx) {
10451            return;
10452        }
10453        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10454        self.transact(window, cx, |this, window, cx| {
10455            this.change_selections(Default::default(), window, cx, |s| {
10456                s.move_with(|map, selection| {
10457                    if selection.is_empty() {
10458                        let cursor = movement::right(map, selection.head());
10459                        selection.end = cursor;
10460                        selection.reversed = true;
10461                        selection.goal = SelectionGoal::None;
10462                    }
10463                })
10464            });
10465            this.insert("", window, cx);
10466            this.refresh_edit_prediction(true, false, window, cx);
10467        });
10468    }
10469
10470    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10471        if self.mode.is_single_line() {
10472            cx.propagate();
10473            return;
10474        }
10475
10476        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10477        if self.move_to_prev_snippet_tabstop(window, cx) {
10478            return;
10479        }
10480        self.outdent(&Outdent, window, cx);
10481    }
10482
10483    pub fn next_snippet_tabstop(
10484        &mut self,
10485        _: &NextSnippetTabstop,
10486        window: &mut Window,
10487        cx: &mut Context<Self>,
10488    ) {
10489        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10490            cx.propagate();
10491            return;
10492        }
10493
10494        if self.move_to_next_snippet_tabstop(window, cx) {
10495            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10496            return;
10497        }
10498        cx.propagate();
10499    }
10500
10501    pub fn previous_snippet_tabstop(
10502        &mut self,
10503        _: &PreviousSnippetTabstop,
10504        window: &mut Window,
10505        cx: &mut Context<Self>,
10506    ) {
10507        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10508            cx.propagate();
10509            return;
10510        }
10511
10512        if self.move_to_prev_snippet_tabstop(window, cx) {
10513            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10514            return;
10515        }
10516        cx.propagate();
10517    }
10518
10519    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10520        if self.mode.is_single_line() {
10521            cx.propagate();
10522            return;
10523        }
10524
10525        if self.move_to_next_snippet_tabstop(window, cx) {
10526            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10527            return;
10528        }
10529        if self.read_only(cx) {
10530            return;
10531        }
10532        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10533        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10534        let buffer = self.buffer.read(cx);
10535        let snapshot = buffer.snapshot(cx);
10536        let rows_iter = selections.iter().map(|s| s.head().row);
10537        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10538
10539        let has_some_cursor_in_whitespace = selections
10540            .iter()
10541            .filter(|selection| selection.is_empty())
10542            .any(|selection| {
10543                let cursor = selection.head();
10544                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10545                cursor.column < current_indent.len
10546            });
10547
10548        let mut edits = Vec::new();
10549        let mut prev_edited_row = 0;
10550        let mut row_delta = 0;
10551        for selection in &mut selections {
10552            if selection.start.row != prev_edited_row {
10553                row_delta = 0;
10554            }
10555            prev_edited_row = selection.end.row;
10556
10557            // If the selection is non-empty, then increase the indentation of the selected lines.
10558            if !selection.is_empty() {
10559                row_delta =
10560                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10561                continue;
10562            }
10563
10564            let cursor = selection.head();
10565            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10566            if let Some(suggested_indent) =
10567                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10568            {
10569                // Don't do anything if already at suggested indent
10570                // and there is any other cursor which is not
10571                if has_some_cursor_in_whitespace
10572                    && cursor.column == current_indent.len
10573                    && current_indent.len == suggested_indent.len
10574                {
10575                    continue;
10576                }
10577
10578                // Adjust line and move cursor to suggested indent
10579                // if cursor is not at suggested indent
10580                if cursor.column < suggested_indent.len
10581                    && cursor.column <= current_indent.len
10582                    && current_indent.len <= suggested_indent.len
10583                {
10584                    selection.start = Point::new(cursor.row, suggested_indent.len);
10585                    selection.end = selection.start;
10586                    if row_delta == 0 {
10587                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10588                            cursor.row,
10589                            current_indent,
10590                            suggested_indent,
10591                        ));
10592                        row_delta = suggested_indent.len - current_indent.len;
10593                    }
10594                    continue;
10595                }
10596
10597                // If current indent is more than suggested indent
10598                // only move cursor to current indent and skip indent
10599                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10600                    selection.start = Point::new(cursor.row, current_indent.len);
10601                    selection.end = selection.start;
10602                    continue;
10603                }
10604            }
10605
10606            // Otherwise, insert a hard or soft tab.
10607            let settings = buffer.language_settings_at(cursor, cx);
10608            let tab_size = if settings.hard_tabs {
10609                IndentSize::tab()
10610            } else {
10611                let tab_size = settings.tab_size.get();
10612                let indent_remainder = snapshot
10613                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10614                    .flat_map(str::chars)
10615                    .fold(row_delta % tab_size, |counter: u32, c| {
10616                        if c == '\t' {
10617                            0
10618                        } else {
10619                            (counter + 1) % tab_size
10620                        }
10621                    });
10622
10623                let chars_to_next_tab_stop = tab_size - indent_remainder;
10624                IndentSize::spaces(chars_to_next_tab_stop)
10625            };
10626            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10627            selection.end = selection.start;
10628            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10629            row_delta += tab_size.len;
10630        }
10631
10632        self.transact(window, cx, |this, window, cx| {
10633            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10634            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10635            this.refresh_edit_prediction(true, false, window, cx);
10636        });
10637    }
10638
10639    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10640        if self.read_only(cx) {
10641            return;
10642        }
10643        if self.mode.is_single_line() {
10644            cx.propagate();
10645            return;
10646        }
10647
10648        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10649        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10650        let mut prev_edited_row = 0;
10651        let mut row_delta = 0;
10652        let mut edits = Vec::new();
10653        let buffer = self.buffer.read(cx);
10654        let snapshot = buffer.snapshot(cx);
10655        for selection in &mut selections {
10656            if selection.start.row != prev_edited_row {
10657                row_delta = 0;
10658            }
10659            prev_edited_row = selection.end.row;
10660
10661            row_delta =
10662                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10663        }
10664
10665        self.transact(window, cx, |this, window, cx| {
10666            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10667            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10668        });
10669    }
10670
10671    fn indent_selection(
10672        buffer: &MultiBuffer,
10673        snapshot: &MultiBufferSnapshot,
10674        selection: &mut Selection<Point>,
10675        edits: &mut Vec<(Range<Point>, String)>,
10676        delta_for_start_row: u32,
10677        cx: &App,
10678    ) -> u32 {
10679        let settings = buffer.language_settings_at(selection.start, cx);
10680        let tab_size = settings.tab_size.get();
10681        let indent_kind = if settings.hard_tabs {
10682            IndentKind::Tab
10683        } else {
10684            IndentKind::Space
10685        };
10686        let mut start_row = selection.start.row;
10687        let mut end_row = selection.end.row + 1;
10688
10689        // If a selection ends at the beginning of a line, don't indent
10690        // that last line.
10691        if selection.end.column == 0 && selection.end.row > selection.start.row {
10692            end_row -= 1;
10693        }
10694
10695        // Avoid re-indenting a row that has already been indented by a
10696        // previous selection, but still update this selection's column
10697        // to reflect that indentation.
10698        if delta_for_start_row > 0 {
10699            start_row += 1;
10700            selection.start.column += delta_for_start_row;
10701            if selection.end.row == selection.start.row {
10702                selection.end.column += delta_for_start_row;
10703            }
10704        }
10705
10706        let mut delta_for_end_row = 0;
10707        let has_multiple_rows = start_row + 1 != end_row;
10708        for row in start_row..end_row {
10709            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10710            let indent_delta = match (current_indent.kind, indent_kind) {
10711                (IndentKind::Space, IndentKind::Space) => {
10712                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10713                    IndentSize::spaces(columns_to_next_tab_stop)
10714                }
10715                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10716                (_, IndentKind::Tab) => IndentSize::tab(),
10717            };
10718
10719            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10720                0
10721            } else {
10722                selection.start.column
10723            };
10724            let row_start = Point::new(row, start);
10725            edits.push((
10726                row_start..row_start,
10727                indent_delta.chars().collect::<String>(),
10728            ));
10729
10730            // Update this selection's endpoints to reflect the indentation.
10731            if row == selection.start.row {
10732                selection.start.column += indent_delta.len;
10733            }
10734            if row == selection.end.row {
10735                selection.end.column += indent_delta.len;
10736                delta_for_end_row = indent_delta.len;
10737            }
10738        }
10739
10740        if selection.start.row == selection.end.row {
10741            delta_for_start_row + delta_for_end_row
10742        } else {
10743            delta_for_end_row
10744        }
10745    }
10746
10747    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10748        if self.read_only(cx) {
10749            return;
10750        }
10751        if self.mode.is_single_line() {
10752            cx.propagate();
10753            return;
10754        }
10755
10756        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10757        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10758        let selections = self.selections.all::<Point>(&display_map);
10759        let mut deletion_ranges = Vec::new();
10760        let mut last_outdent = None;
10761        {
10762            let buffer = self.buffer.read(cx);
10763            let snapshot = buffer.snapshot(cx);
10764            for selection in &selections {
10765                let settings = buffer.language_settings_at(selection.start, cx);
10766                let tab_size = settings.tab_size.get();
10767                let mut rows = selection.spanned_rows(false, &display_map);
10768
10769                // Avoid re-outdenting a row that has already been outdented by a
10770                // previous selection.
10771                if let Some(last_row) = last_outdent
10772                    && last_row == rows.start
10773                {
10774                    rows.start = rows.start.next_row();
10775                }
10776                let has_multiple_rows = rows.len() > 1;
10777                for row in rows.iter_rows() {
10778                    let indent_size = snapshot.indent_size_for_line(row);
10779                    if indent_size.len > 0 {
10780                        let deletion_len = match indent_size.kind {
10781                            IndentKind::Space => {
10782                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10783                                if columns_to_prev_tab_stop == 0 {
10784                                    tab_size
10785                                } else {
10786                                    columns_to_prev_tab_stop
10787                                }
10788                            }
10789                            IndentKind::Tab => 1,
10790                        };
10791                        let start = if has_multiple_rows
10792                            || deletion_len > selection.start.column
10793                            || indent_size.len < selection.start.column
10794                        {
10795                            0
10796                        } else {
10797                            selection.start.column - deletion_len
10798                        };
10799                        deletion_ranges.push(
10800                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
10801                        );
10802                        last_outdent = Some(row);
10803                    }
10804                }
10805            }
10806        }
10807
10808        self.transact(window, cx, |this, window, cx| {
10809            this.buffer.update(cx, |buffer, cx| {
10810                let empty_str: Arc<str> = Arc::default();
10811                buffer.edit(
10812                    deletion_ranges
10813                        .into_iter()
10814                        .map(|range| (range, empty_str.clone())),
10815                    None,
10816                    cx,
10817                );
10818            });
10819            let selections = this
10820                .selections
10821                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10822            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10823        });
10824    }
10825
10826    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
10827        if self.read_only(cx) {
10828            return;
10829        }
10830        if self.mode.is_single_line() {
10831            cx.propagate();
10832            return;
10833        }
10834
10835        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10836        let selections = self
10837            .selections
10838            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
10839            .into_iter()
10840            .map(|s| s.range());
10841
10842        self.transact(window, cx, |this, window, cx| {
10843            this.buffer.update(cx, |buffer, cx| {
10844                buffer.autoindent_ranges(selections, cx);
10845            });
10846            let selections = this
10847                .selections
10848                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
10849            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10850        });
10851    }
10852
10853    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
10854        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10855        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10856        let selections = self.selections.all::<Point>(&display_map);
10857
10858        let mut new_cursors = Vec::new();
10859        let mut edit_ranges = Vec::new();
10860        let mut selections = selections.iter().peekable();
10861        while let Some(selection) = selections.next() {
10862            let mut rows = selection.spanned_rows(false, &display_map);
10863
10864            // Accumulate contiguous regions of rows that we want to delete.
10865            while let Some(next_selection) = selections.peek() {
10866                let next_rows = next_selection.spanned_rows(false, &display_map);
10867                if next_rows.start <= rows.end {
10868                    rows.end = next_rows.end;
10869                    selections.next().unwrap();
10870                } else {
10871                    break;
10872                }
10873            }
10874
10875            let buffer = display_map.buffer_snapshot();
10876            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
10877            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
10878                // If there's a line after the range, delete the \n from the end of the row range
10879                (
10880                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
10881                    rows.end,
10882                )
10883            } else {
10884                // If there isn't a line after the range, delete the \n from the line before the
10885                // start of the row range
10886                edit_start = edit_start.saturating_sub_usize(1);
10887                (buffer.len(), rows.start.previous_row())
10888            };
10889
10890            let text_layout_details = self.text_layout_details(window);
10891            let x = display_map.x_for_display_point(
10892                selection.head().to_display_point(&display_map),
10893                &text_layout_details,
10894            );
10895            let row = Point::new(target_row.0, 0)
10896                .to_display_point(&display_map)
10897                .row();
10898            let column = display_map.display_column_for_x(row, x, &text_layout_details);
10899
10900            new_cursors.push((
10901                selection.id,
10902                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
10903                SelectionGoal::None,
10904            ));
10905            edit_ranges.push(edit_start..edit_end);
10906        }
10907
10908        self.transact(window, cx, |this, window, cx| {
10909            let buffer = this.buffer.update(cx, |buffer, cx| {
10910                let empty_str: Arc<str> = Arc::default();
10911                buffer.edit(
10912                    edit_ranges
10913                        .into_iter()
10914                        .map(|range| (range, empty_str.clone())),
10915                    None,
10916                    cx,
10917                );
10918                buffer.snapshot(cx)
10919            });
10920            let new_selections = new_cursors
10921                .into_iter()
10922                .map(|(id, cursor, goal)| {
10923                    let cursor = cursor.to_point(&buffer);
10924                    Selection {
10925                        id,
10926                        start: cursor,
10927                        end: cursor,
10928                        reversed: false,
10929                        goal,
10930                    }
10931                })
10932                .collect();
10933
10934            this.change_selections(Default::default(), window, cx, |s| {
10935                s.select(new_selections);
10936            });
10937        });
10938    }
10939
10940    pub fn join_lines_impl(
10941        &mut self,
10942        insert_whitespace: bool,
10943        window: &mut Window,
10944        cx: &mut Context<Self>,
10945    ) {
10946        if self.read_only(cx) {
10947            return;
10948        }
10949        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
10950        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
10951            let start = MultiBufferRow(selection.start.row);
10952            // Treat single line selections as if they include the next line. Otherwise this action
10953            // would do nothing for single line selections individual cursors.
10954            let end = if selection.start.row == selection.end.row {
10955                MultiBufferRow(selection.start.row + 1)
10956            } else {
10957                MultiBufferRow(selection.end.row)
10958            };
10959
10960            if let Some(last_row_range) = row_ranges.last_mut()
10961                && start <= last_row_range.end
10962            {
10963                last_row_range.end = end;
10964                continue;
10965            }
10966            row_ranges.push(start..end);
10967        }
10968
10969        let snapshot = self.buffer.read(cx).snapshot(cx);
10970        let mut cursor_positions = Vec::new();
10971        for row_range in &row_ranges {
10972            let anchor = snapshot.anchor_before(Point::new(
10973                row_range.end.previous_row().0,
10974                snapshot.line_len(row_range.end.previous_row()),
10975            ));
10976            cursor_positions.push(anchor..anchor);
10977        }
10978
10979        self.transact(window, cx, |this, window, cx| {
10980            for row_range in row_ranges.into_iter().rev() {
10981                for row in row_range.iter_rows().rev() {
10982                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
10983                    let next_line_row = row.next_row();
10984                    let indent = snapshot.indent_size_for_line(next_line_row);
10985                    let start_of_next_line = Point::new(next_line_row.0, indent.len);
10986
10987                    let replace =
10988                        if snapshot.line_len(next_line_row) > indent.len && insert_whitespace {
10989                            " "
10990                        } else {
10991                            ""
10992                        };
10993
10994                    this.buffer.update(cx, |buffer, cx| {
10995                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
10996                    });
10997                }
10998            }
10999
11000            this.change_selections(Default::default(), window, cx, |s| {
11001                s.select_anchor_ranges(cursor_positions)
11002            });
11003        });
11004    }
11005
11006    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
11007        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11008        self.join_lines_impl(true, window, cx);
11009    }
11010
11011    pub fn sort_lines_case_sensitive(
11012        &mut self,
11013        _: &SortLinesCaseSensitive,
11014        window: &mut Window,
11015        cx: &mut Context<Self>,
11016    ) {
11017        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
11018    }
11019
11020    pub fn sort_lines_by_length(
11021        &mut self,
11022        _: &SortLinesByLength,
11023        window: &mut Window,
11024        cx: &mut Context<Self>,
11025    ) {
11026        self.manipulate_immutable_lines(window, cx, |lines| {
11027            lines.sort_by_key(|&line| line.chars().count())
11028        })
11029    }
11030
11031    pub fn sort_lines_case_insensitive(
11032        &mut self,
11033        _: &SortLinesCaseInsensitive,
11034        window: &mut Window,
11035        cx: &mut Context<Self>,
11036    ) {
11037        self.manipulate_immutable_lines(window, cx, |lines| {
11038            lines.sort_by_key(|line| line.to_lowercase())
11039        })
11040    }
11041
11042    pub fn unique_lines_case_insensitive(
11043        &mut self,
11044        _: &UniqueLinesCaseInsensitive,
11045        window: &mut Window,
11046        cx: &mut Context<Self>,
11047    ) {
11048        self.manipulate_immutable_lines(window, cx, |lines| {
11049            let mut seen = HashSet::default();
11050            lines.retain(|line| seen.insert(line.to_lowercase()));
11051        })
11052    }
11053
11054    pub fn unique_lines_case_sensitive(
11055        &mut self,
11056        _: &UniqueLinesCaseSensitive,
11057        window: &mut Window,
11058        cx: &mut Context<Self>,
11059    ) {
11060        self.manipulate_immutable_lines(window, cx, |lines| {
11061            let mut seen = HashSet::default();
11062            lines.retain(|line| seen.insert(*line));
11063        })
11064    }
11065
11066    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
11067        let snapshot = self.buffer.read(cx).snapshot(cx);
11068        for selection in self.selections.disjoint_anchors_arc().iter() {
11069            if snapshot
11070                .language_at(selection.start)
11071                .and_then(|lang| lang.config().wrap_characters.as_ref())
11072                .is_some()
11073            {
11074                return true;
11075            }
11076        }
11077        false
11078    }
11079
11080    fn wrap_selections_in_tag(
11081        &mut self,
11082        _: &WrapSelectionsInTag,
11083        window: &mut Window,
11084        cx: &mut Context<Self>,
11085    ) {
11086        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11087
11088        let snapshot = self.buffer.read(cx).snapshot(cx);
11089
11090        let mut edits = Vec::new();
11091        let mut boundaries = Vec::new();
11092
11093        for selection in self
11094            .selections
11095            .all_adjusted(&self.display_snapshot(cx))
11096            .iter()
11097        {
11098            let Some(wrap_config) = snapshot
11099                .language_at(selection.start)
11100                .and_then(|lang| lang.config().wrap_characters.clone())
11101            else {
11102                continue;
11103            };
11104
11105            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
11106            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
11107
11108            let start_before = snapshot.anchor_before(selection.start);
11109            let end_after = snapshot.anchor_after(selection.end);
11110
11111            edits.push((start_before..start_before, open_tag));
11112            edits.push((end_after..end_after, close_tag));
11113
11114            boundaries.push((
11115                start_before,
11116                end_after,
11117                wrap_config.start_prefix.len(),
11118                wrap_config.end_suffix.len(),
11119            ));
11120        }
11121
11122        if edits.is_empty() {
11123            return;
11124        }
11125
11126        self.transact(window, cx, |this, window, cx| {
11127            let buffer = this.buffer.update(cx, |buffer, cx| {
11128                buffer.edit(edits, None, cx);
11129                buffer.snapshot(cx)
11130            });
11131
11132            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
11133            for (start_before, end_after, start_prefix_len, end_suffix_len) in
11134                boundaries.into_iter()
11135            {
11136                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
11137                let close_offset = end_after
11138                    .to_offset(&buffer)
11139                    .saturating_sub_usize(end_suffix_len);
11140                new_selections.push(open_offset..open_offset);
11141                new_selections.push(close_offset..close_offset);
11142            }
11143
11144            this.change_selections(Default::default(), window, cx, |s| {
11145                s.select_ranges(new_selections);
11146            });
11147
11148            this.request_autoscroll(Autoscroll::fit(), cx);
11149        });
11150    }
11151
11152    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
11153        let Some(project) = self.project.clone() else {
11154            return;
11155        };
11156        self.reload(project, window, cx)
11157            .detach_and_notify_err(window, cx);
11158    }
11159
11160    pub fn restore_file(
11161        &mut self,
11162        _: &::git::RestoreFile,
11163        window: &mut Window,
11164        cx: &mut Context<Self>,
11165    ) {
11166        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11167        let mut buffer_ids = HashSet::default();
11168        let snapshot = self.buffer().read(cx).snapshot(cx);
11169        for selection in self
11170            .selections
11171            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
11172        {
11173            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
11174        }
11175
11176        let buffer = self.buffer().read(cx);
11177        let ranges = buffer_ids
11178            .into_iter()
11179            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
11180            .collect::<Vec<_>>();
11181
11182        self.restore_hunks_in_ranges(ranges, window, cx);
11183    }
11184
11185    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
11186        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11187        let selections = self
11188            .selections
11189            .all(&self.display_snapshot(cx))
11190            .into_iter()
11191            .map(|s| s.range())
11192            .collect();
11193        self.restore_hunks_in_ranges(selections, window, cx);
11194    }
11195
11196    pub fn restore_hunks_in_ranges(
11197        &mut self,
11198        ranges: Vec<Range<Point>>,
11199        window: &mut Window,
11200        cx: &mut Context<Editor>,
11201    ) {
11202        let mut revert_changes = HashMap::default();
11203        let chunk_by = self
11204            .snapshot(window, cx)
11205            .hunks_for_ranges(ranges)
11206            .into_iter()
11207            .chunk_by(|hunk| hunk.buffer_id);
11208        for (buffer_id, hunks) in &chunk_by {
11209            let hunks = hunks.collect::<Vec<_>>();
11210            for hunk in &hunks {
11211                self.prepare_restore_change(&mut revert_changes, hunk, cx);
11212            }
11213            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
11214        }
11215        drop(chunk_by);
11216        if !revert_changes.is_empty() {
11217            self.transact(window, cx, |editor, window, cx| {
11218                editor.restore(revert_changes, window, cx);
11219            });
11220        }
11221    }
11222
11223    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
11224        if let Some(status) = self
11225            .addons
11226            .iter()
11227            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
11228        {
11229            return Some(status);
11230        }
11231        self.project
11232            .as_ref()?
11233            .read(cx)
11234            .status_for_buffer_id(buffer_id, cx)
11235    }
11236
11237    pub fn open_active_item_in_terminal(
11238        &mut self,
11239        _: &OpenInTerminal,
11240        window: &mut Window,
11241        cx: &mut Context<Self>,
11242    ) {
11243        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
11244            let project_path = buffer.read(cx).project_path(cx)?;
11245            let project = self.project()?.read(cx);
11246            let entry = project.entry_for_path(&project_path, cx)?;
11247            let parent = match &entry.canonical_path {
11248                Some(canonical_path) => canonical_path.to_path_buf(),
11249                None => project.absolute_path(&project_path, cx)?,
11250            }
11251            .parent()?
11252            .to_path_buf();
11253            Some(parent)
11254        }) {
11255            window.dispatch_action(OpenTerminal { working_directory }.boxed_clone(), cx);
11256        }
11257    }
11258
11259    fn set_breakpoint_context_menu(
11260        &mut self,
11261        display_row: DisplayRow,
11262        position: Option<Anchor>,
11263        clicked_point: gpui::Point<Pixels>,
11264        window: &mut Window,
11265        cx: &mut Context<Self>,
11266    ) {
11267        let source = self
11268            .buffer
11269            .read(cx)
11270            .snapshot(cx)
11271            .anchor_before(Point::new(display_row.0, 0u32));
11272
11273        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
11274
11275        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
11276            self,
11277            source,
11278            clicked_point,
11279            context_menu,
11280            window,
11281            cx,
11282        );
11283    }
11284
11285    fn add_edit_breakpoint_block(
11286        &mut self,
11287        anchor: Anchor,
11288        breakpoint: &Breakpoint,
11289        edit_action: BreakpointPromptEditAction,
11290        window: &mut Window,
11291        cx: &mut Context<Self>,
11292    ) {
11293        let weak_editor = cx.weak_entity();
11294        let bp_prompt = cx.new(|cx| {
11295            BreakpointPromptEditor::new(
11296                weak_editor,
11297                anchor,
11298                breakpoint.clone(),
11299                edit_action,
11300                window,
11301                cx,
11302            )
11303        });
11304
11305        let height = bp_prompt.update(cx, |this, cx| {
11306            this.prompt
11307                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
11308        });
11309        let cloned_prompt = bp_prompt.clone();
11310        let blocks = vec![BlockProperties {
11311            style: BlockStyle::Sticky,
11312            placement: BlockPlacement::Above(anchor),
11313            height: Some(height),
11314            render: Arc::new(move |cx| {
11315                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
11316                cloned_prompt.clone().into_any_element()
11317            }),
11318            priority: 0,
11319        }];
11320
11321        let focus_handle = bp_prompt.focus_handle(cx);
11322        window.focus(&focus_handle);
11323
11324        let block_ids = self.insert_blocks(blocks, None, cx);
11325        bp_prompt.update(cx, |prompt, _| {
11326            prompt.add_block_ids(block_ids);
11327        });
11328    }
11329
11330    pub(crate) fn breakpoint_at_row(
11331        &self,
11332        row: u32,
11333        window: &mut Window,
11334        cx: &mut Context<Self>,
11335    ) -> Option<(Anchor, Breakpoint)> {
11336        let snapshot = self.snapshot(window, cx);
11337        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11338
11339        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11340    }
11341
11342    pub(crate) fn breakpoint_at_anchor(
11343        &self,
11344        breakpoint_position: Anchor,
11345        snapshot: &EditorSnapshot,
11346        cx: &mut Context<Self>,
11347    ) -> Option<(Anchor, Breakpoint)> {
11348        let buffer = self
11349            .buffer
11350            .read(cx)
11351            .buffer_for_anchor(breakpoint_position, cx)?;
11352
11353        let enclosing_excerpt = breakpoint_position.excerpt_id;
11354        let buffer_snapshot = buffer.read(cx).snapshot();
11355
11356        let row = buffer_snapshot
11357            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11358            .row;
11359
11360        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11361        let anchor_end = snapshot
11362            .buffer_snapshot()
11363            .anchor_after(Point::new(row, line_len));
11364
11365        self.breakpoint_store
11366            .as_ref()?
11367            .read_with(cx, |breakpoint_store, cx| {
11368                breakpoint_store
11369                    .breakpoints(
11370                        &buffer,
11371                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11372                        &buffer_snapshot,
11373                        cx,
11374                    )
11375                    .next()
11376                    .and_then(|(bp, _)| {
11377                        let breakpoint_row = buffer_snapshot
11378                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11379                            .row;
11380
11381                        if breakpoint_row == row {
11382                            snapshot
11383                                .buffer_snapshot()
11384                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11385                                .map(|position| (position, bp.bp.clone()))
11386                        } else {
11387                            None
11388                        }
11389                    })
11390            })
11391    }
11392
11393    pub fn edit_log_breakpoint(
11394        &mut self,
11395        _: &EditLogBreakpoint,
11396        window: &mut Window,
11397        cx: &mut Context<Self>,
11398    ) {
11399        if self.breakpoint_store.is_none() {
11400            return;
11401        }
11402
11403        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11404            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11405                message: None,
11406                state: BreakpointState::Enabled,
11407                condition: None,
11408                hit_condition: None,
11409            });
11410
11411            self.add_edit_breakpoint_block(
11412                anchor,
11413                &breakpoint,
11414                BreakpointPromptEditAction::Log,
11415                window,
11416                cx,
11417            );
11418        }
11419    }
11420
11421    fn breakpoints_at_cursors(
11422        &self,
11423        window: &mut Window,
11424        cx: &mut Context<Self>,
11425    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11426        let snapshot = self.snapshot(window, cx);
11427        let cursors = self
11428            .selections
11429            .disjoint_anchors_arc()
11430            .iter()
11431            .map(|selection| {
11432                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11433
11434                let breakpoint_position = self
11435                    .breakpoint_at_row(cursor_position.row, window, cx)
11436                    .map(|bp| bp.0)
11437                    .unwrap_or_else(|| {
11438                        snapshot
11439                            .display_snapshot
11440                            .buffer_snapshot()
11441                            .anchor_after(Point::new(cursor_position.row, 0))
11442                    });
11443
11444                let breakpoint = self
11445                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11446                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11447
11448                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11449            })
11450            // 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.
11451            .collect::<HashMap<Anchor, _>>();
11452
11453        cursors.into_iter().collect()
11454    }
11455
11456    pub fn enable_breakpoint(
11457        &mut self,
11458        _: &crate::actions::EnableBreakpoint,
11459        window: &mut Window,
11460        cx: &mut Context<Self>,
11461    ) {
11462        if self.breakpoint_store.is_none() {
11463            return;
11464        }
11465
11466        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11467            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11468                continue;
11469            };
11470            self.edit_breakpoint_at_anchor(
11471                anchor,
11472                breakpoint,
11473                BreakpointEditAction::InvertState,
11474                cx,
11475            );
11476        }
11477    }
11478
11479    pub fn disable_breakpoint(
11480        &mut self,
11481        _: &crate::actions::DisableBreakpoint,
11482        window: &mut Window,
11483        cx: &mut Context<Self>,
11484    ) {
11485        if self.breakpoint_store.is_none() {
11486            return;
11487        }
11488
11489        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11490            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11491                continue;
11492            };
11493            self.edit_breakpoint_at_anchor(
11494                anchor,
11495                breakpoint,
11496                BreakpointEditAction::InvertState,
11497                cx,
11498            );
11499        }
11500    }
11501
11502    pub fn toggle_breakpoint(
11503        &mut self,
11504        _: &crate::actions::ToggleBreakpoint,
11505        window: &mut Window,
11506        cx: &mut Context<Self>,
11507    ) {
11508        if self.breakpoint_store.is_none() {
11509            return;
11510        }
11511
11512        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11513            if let Some(breakpoint) = breakpoint {
11514                self.edit_breakpoint_at_anchor(
11515                    anchor,
11516                    breakpoint,
11517                    BreakpointEditAction::Toggle,
11518                    cx,
11519                );
11520            } else {
11521                self.edit_breakpoint_at_anchor(
11522                    anchor,
11523                    Breakpoint::new_standard(),
11524                    BreakpointEditAction::Toggle,
11525                    cx,
11526                );
11527            }
11528        }
11529    }
11530
11531    pub fn edit_breakpoint_at_anchor(
11532        &mut self,
11533        breakpoint_position: Anchor,
11534        breakpoint: Breakpoint,
11535        edit_action: BreakpointEditAction,
11536        cx: &mut Context<Self>,
11537    ) {
11538        let Some(breakpoint_store) = &self.breakpoint_store else {
11539            return;
11540        };
11541
11542        let Some(buffer) = self
11543            .buffer
11544            .read(cx)
11545            .buffer_for_anchor(breakpoint_position, cx)
11546        else {
11547            return;
11548        };
11549
11550        breakpoint_store.update(cx, |breakpoint_store, cx| {
11551            breakpoint_store.toggle_breakpoint(
11552                buffer,
11553                BreakpointWithPosition {
11554                    position: breakpoint_position.text_anchor,
11555                    bp: breakpoint,
11556                },
11557                edit_action,
11558                cx,
11559            );
11560        });
11561
11562        cx.notify();
11563    }
11564
11565    #[cfg(any(test, feature = "test-support"))]
11566    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11567        self.breakpoint_store.clone()
11568    }
11569
11570    pub fn prepare_restore_change(
11571        &self,
11572        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11573        hunk: &MultiBufferDiffHunk,
11574        cx: &mut App,
11575    ) -> Option<()> {
11576        if hunk.is_created_file() {
11577            return None;
11578        }
11579        let buffer = self.buffer.read(cx);
11580        let diff = buffer.diff_for(hunk.buffer_id)?;
11581        let buffer = buffer.buffer(hunk.buffer_id)?;
11582        let buffer = buffer.read(cx);
11583        let original_text = diff
11584            .read(cx)
11585            .base_text()
11586            .as_rope()
11587            .slice(hunk.diff_base_byte_range.start.0..hunk.diff_base_byte_range.end.0);
11588        let buffer_snapshot = buffer.snapshot();
11589        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11590        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11591            probe
11592                .0
11593                .start
11594                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11595                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11596        }) {
11597            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11598            Some(())
11599        } else {
11600            None
11601        }
11602    }
11603
11604    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11605        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11606    }
11607
11608    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11609        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11610    }
11611
11612    pub fn rotate_selections_forward(
11613        &mut self,
11614        _: &RotateSelectionsForward,
11615        window: &mut Window,
11616        cx: &mut Context<Self>,
11617    ) {
11618        self.rotate_selections(window, cx, false)
11619    }
11620
11621    pub fn rotate_selections_backward(
11622        &mut self,
11623        _: &RotateSelectionsBackward,
11624        window: &mut Window,
11625        cx: &mut Context<Self>,
11626    ) {
11627        self.rotate_selections(window, cx, true)
11628    }
11629
11630    fn rotate_selections(&mut self, window: &mut Window, cx: &mut Context<Self>, reverse: bool) {
11631        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11632        let display_snapshot = self.display_snapshot(cx);
11633        let selections = self.selections.all::<MultiBufferOffset>(&display_snapshot);
11634
11635        if selections.len() < 2 {
11636            return;
11637        }
11638
11639        let (edits, new_selections) = {
11640            let buffer = self.buffer.read(cx).read(cx);
11641            let has_selections = selections.iter().any(|s| !s.is_empty());
11642            if has_selections {
11643                let mut selected_texts: Vec<String> = selections
11644                    .iter()
11645                    .map(|selection| {
11646                        buffer
11647                            .text_for_range(selection.start..selection.end)
11648                            .collect()
11649                    })
11650                    .collect();
11651
11652                if reverse {
11653                    selected_texts.rotate_left(1);
11654                } else {
11655                    selected_texts.rotate_right(1);
11656                }
11657
11658                let mut offset_delta: i64 = 0;
11659                let mut new_selections = Vec::new();
11660                let edits: Vec<_> = selections
11661                    .iter()
11662                    .zip(selected_texts.iter())
11663                    .map(|(selection, new_text)| {
11664                        let old_len = (selection.end.0 - selection.start.0) as i64;
11665                        let new_len = new_text.len() as i64;
11666                        let adjusted_start =
11667                            MultiBufferOffset((selection.start.0 as i64 + offset_delta) as usize);
11668                        let adjusted_end =
11669                            MultiBufferOffset((adjusted_start.0 as i64 + new_len) as usize);
11670
11671                        new_selections.push(Selection {
11672                            id: selection.id,
11673                            start: adjusted_start,
11674                            end: adjusted_end,
11675                            reversed: selection.reversed,
11676                            goal: selection.goal,
11677                        });
11678
11679                        offset_delta += new_len - old_len;
11680                        (selection.start..selection.end, new_text.clone())
11681                    })
11682                    .collect();
11683                (edits, new_selections)
11684            } else {
11685                let mut all_rows: Vec<u32> = selections
11686                    .iter()
11687                    .map(|selection| buffer.offset_to_point(selection.start).row)
11688                    .collect();
11689                all_rows.sort_unstable();
11690                all_rows.dedup();
11691
11692                if all_rows.len() < 2 {
11693                    return;
11694                }
11695
11696                let line_ranges: Vec<Range<MultiBufferOffset>> = all_rows
11697                    .iter()
11698                    .map(|&row| {
11699                        let start = Point::new(row, 0);
11700                        let end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
11701                        buffer.point_to_offset(start)..buffer.point_to_offset(end)
11702                    })
11703                    .collect();
11704
11705                let mut line_texts: Vec<String> = line_ranges
11706                    .iter()
11707                    .map(|range| buffer.text_for_range(range.clone()).collect())
11708                    .collect();
11709
11710                if reverse {
11711                    line_texts.rotate_left(1);
11712                } else {
11713                    line_texts.rotate_right(1);
11714                }
11715
11716                let edits = line_ranges
11717                    .iter()
11718                    .zip(line_texts.iter())
11719                    .map(|(range, new_text)| (range.clone(), new_text.clone()))
11720                    .collect();
11721
11722                let num_rows = all_rows.len();
11723                let row_to_index: std::collections::HashMap<u32, usize> = all_rows
11724                    .iter()
11725                    .enumerate()
11726                    .map(|(i, &row)| (row, i))
11727                    .collect();
11728
11729                // Compute new line start offsets after rotation (handles CRLF)
11730                let newline_len = line_ranges[1].start.0 - line_ranges[0].end.0;
11731                let first_line_start = line_ranges[0].start.0;
11732                let mut new_line_starts: Vec<usize> = vec![first_line_start];
11733                for text in line_texts.iter().take(num_rows - 1) {
11734                    let prev_start = *new_line_starts.last().unwrap();
11735                    new_line_starts.push(prev_start + text.len() + newline_len);
11736                }
11737
11738                let new_selections = selections
11739                    .iter()
11740                    .map(|selection| {
11741                        let point = buffer.offset_to_point(selection.start);
11742                        let old_index = row_to_index[&point.row];
11743                        let new_index = if reverse {
11744                            (old_index + num_rows - 1) % num_rows
11745                        } else {
11746                            (old_index + 1) % num_rows
11747                        };
11748                        let new_offset =
11749                            MultiBufferOffset(new_line_starts[new_index] + point.column as usize);
11750                        Selection {
11751                            id: selection.id,
11752                            start: new_offset,
11753                            end: new_offset,
11754                            reversed: selection.reversed,
11755                            goal: selection.goal,
11756                        }
11757                    })
11758                    .collect();
11759
11760                (edits, new_selections)
11761            }
11762        };
11763
11764        self.transact(window, cx, |this, window, cx| {
11765            this.buffer.update(cx, |buffer, cx| {
11766                buffer.edit(edits, None, cx);
11767            });
11768            this.change_selections(Default::default(), window, cx, |s| {
11769                s.select(new_selections);
11770            });
11771        });
11772    }
11773
11774    fn manipulate_lines<M>(
11775        &mut self,
11776        window: &mut Window,
11777        cx: &mut Context<Self>,
11778        mut manipulate: M,
11779    ) where
11780        M: FnMut(&str) -> LineManipulationResult,
11781    {
11782        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11783
11784        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11785        let buffer = self.buffer.read(cx).snapshot(cx);
11786
11787        let mut edits = Vec::new();
11788
11789        let selections = self.selections.all::<Point>(&display_map);
11790        let mut selections = selections.iter().peekable();
11791        let mut contiguous_row_selections = Vec::new();
11792        let mut new_selections = Vec::new();
11793        let mut added_lines = 0;
11794        let mut removed_lines = 0;
11795
11796        while let Some(selection) = selections.next() {
11797            let (start_row, end_row) = consume_contiguous_rows(
11798                &mut contiguous_row_selections,
11799                selection,
11800                &display_map,
11801                &mut selections,
11802            );
11803
11804            let start_point = Point::new(start_row.0, 0);
11805            let end_point = Point::new(
11806                end_row.previous_row().0,
11807                buffer.line_len(end_row.previous_row()),
11808            );
11809            let text = buffer
11810                .text_for_range(start_point..end_point)
11811                .collect::<String>();
11812
11813            let LineManipulationResult {
11814                new_text,
11815                line_count_before,
11816                line_count_after,
11817            } = manipulate(&text);
11818
11819            edits.push((start_point..end_point, new_text));
11820
11821            // Selections must change based on added and removed line count
11822            let start_row =
11823                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
11824            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
11825            new_selections.push(Selection {
11826                id: selection.id,
11827                start: start_row,
11828                end: end_row,
11829                goal: SelectionGoal::None,
11830                reversed: selection.reversed,
11831            });
11832
11833            if line_count_after > line_count_before {
11834                added_lines += line_count_after - line_count_before;
11835            } else if line_count_before > line_count_after {
11836                removed_lines += line_count_before - line_count_after;
11837            }
11838        }
11839
11840        self.transact(window, cx, |this, window, cx| {
11841            let buffer = this.buffer.update(cx, |buffer, cx| {
11842                buffer.edit(edits, None, cx);
11843                buffer.snapshot(cx)
11844            });
11845
11846            // Recalculate offsets on newly edited buffer
11847            let new_selections = new_selections
11848                .iter()
11849                .map(|s| {
11850                    let start_point = Point::new(s.start.0, 0);
11851                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
11852                    Selection {
11853                        id: s.id,
11854                        start: buffer.point_to_offset(start_point),
11855                        end: buffer.point_to_offset(end_point),
11856                        goal: s.goal,
11857                        reversed: s.reversed,
11858                    }
11859                })
11860                .collect();
11861
11862            this.change_selections(Default::default(), window, cx, |s| {
11863                s.select(new_selections);
11864            });
11865
11866            this.request_autoscroll(Autoscroll::fit(), cx);
11867        });
11868    }
11869
11870    fn manipulate_immutable_lines<Fn>(
11871        &mut self,
11872        window: &mut Window,
11873        cx: &mut Context<Self>,
11874        mut callback: Fn,
11875    ) where
11876        Fn: FnMut(&mut Vec<&str>),
11877    {
11878        self.manipulate_lines(window, cx, |text| {
11879            let mut lines: Vec<&str> = text.split('\n').collect();
11880            let line_count_before = lines.len();
11881
11882            callback(&mut lines);
11883
11884            LineManipulationResult {
11885                new_text: lines.join("\n"),
11886                line_count_before,
11887                line_count_after: lines.len(),
11888            }
11889        });
11890    }
11891
11892    fn manipulate_mutable_lines<Fn>(
11893        &mut self,
11894        window: &mut Window,
11895        cx: &mut Context<Self>,
11896        mut callback: Fn,
11897    ) where
11898        Fn: FnMut(&mut Vec<Cow<'_, str>>),
11899    {
11900        self.manipulate_lines(window, cx, |text| {
11901            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
11902            let line_count_before = lines.len();
11903
11904            callback(&mut lines);
11905
11906            LineManipulationResult {
11907                new_text: lines.join("\n"),
11908                line_count_before,
11909                line_count_after: lines.len(),
11910            }
11911        });
11912    }
11913
11914    pub fn convert_indentation_to_spaces(
11915        &mut self,
11916        _: &ConvertIndentationToSpaces,
11917        window: &mut Window,
11918        cx: &mut Context<Self>,
11919    ) {
11920        let settings = self.buffer.read(cx).language_settings(cx);
11921        let tab_size = settings.tab_size.get() as usize;
11922
11923        self.manipulate_mutable_lines(window, cx, |lines| {
11924            // Allocates a reasonably sized scratch buffer once for the whole loop
11925            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11926            // Avoids recomputing spaces that could be inserted many times
11927            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11928                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11929                .collect();
11930
11931            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11932                let mut chars = line.as_ref().chars();
11933                let mut col = 0;
11934                let mut changed = false;
11935
11936                for ch in chars.by_ref() {
11937                    match ch {
11938                        ' ' => {
11939                            reindented_line.push(' ');
11940                            col += 1;
11941                        }
11942                        '\t' => {
11943                            // \t are converted to spaces depending on the current column
11944                            let spaces_len = tab_size - (col % tab_size);
11945                            reindented_line.extend(&space_cache[spaces_len - 1]);
11946                            col += spaces_len;
11947                            changed = true;
11948                        }
11949                        _ => {
11950                            // If we dont append before break, the character is consumed
11951                            reindented_line.push(ch);
11952                            break;
11953                        }
11954                    }
11955                }
11956
11957                if !changed {
11958                    reindented_line.clear();
11959                    continue;
11960                }
11961                // Append the rest of the line and replace old reference with new one
11962                reindented_line.extend(chars);
11963                *line = Cow::Owned(reindented_line.clone());
11964                reindented_line.clear();
11965            }
11966        });
11967    }
11968
11969    pub fn convert_indentation_to_tabs(
11970        &mut self,
11971        _: &ConvertIndentationToTabs,
11972        window: &mut Window,
11973        cx: &mut Context<Self>,
11974    ) {
11975        let settings = self.buffer.read(cx).language_settings(cx);
11976        let tab_size = settings.tab_size.get() as usize;
11977
11978        self.manipulate_mutable_lines(window, cx, |lines| {
11979            // Allocates a reasonably sized buffer once for the whole loop
11980            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
11981            // Avoids recomputing spaces that could be inserted many times
11982            let space_cache: Vec<Vec<char>> = (1..=tab_size)
11983                .map(|n| IndentSize::spaces(n as u32).chars().collect())
11984                .collect();
11985
11986            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
11987                let mut chars = line.chars();
11988                let mut spaces_count = 0;
11989                let mut first_non_indent_char = None;
11990                let mut changed = false;
11991
11992                for ch in chars.by_ref() {
11993                    match ch {
11994                        ' ' => {
11995                            // Keep track of spaces. Append \t when we reach tab_size
11996                            spaces_count += 1;
11997                            changed = true;
11998                            if spaces_count == tab_size {
11999                                reindented_line.push('\t');
12000                                spaces_count = 0;
12001                            }
12002                        }
12003                        '\t' => {
12004                            reindented_line.push('\t');
12005                            spaces_count = 0;
12006                        }
12007                        _ => {
12008                            // Dont append it yet, we might have remaining spaces
12009                            first_non_indent_char = Some(ch);
12010                            break;
12011                        }
12012                    }
12013                }
12014
12015                if !changed {
12016                    reindented_line.clear();
12017                    continue;
12018                }
12019                // Remaining spaces that didn't make a full tab stop
12020                if spaces_count > 0 {
12021                    reindented_line.extend(&space_cache[spaces_count - 1]);
12022                }
12023                // If we consume an extra character that was not indentation, add it back
12024                if let Some(extra_char) = first_non_indent_char {
12025                    reindented_line.push(extra_char);
12026                }
12027                // Append the rest of the line and replace old reference with new one
12028                reindented_line.extend(chars);
12029                *line = Cow::Owned(reindented_line.clone());
12030                reindented_line.clear();
12031            }
12032        });
12033    }
12034
12035    pub fn convert_to_upper_case(
12036        &mut self,
12037        _: &ConvertToUpperCase,
12038        window: &mut Window,
12039        cx: &mut Context<Self>,
12040    ) {
12041        self.manipulate_text(window, cx, |text| text.to_uppercase())
12042    }
12043
12044    pub fn convert_to_lower_case(
12045        &mut self,
12046        _: &ConvertToLowerCase,
12047        window: &mut Window,
12048        cx: &mut Context<Self>,
12049    ) {
12050        self.manipulate_text(window, cx, |text| text.to_lowercase())
12051    }
12052
12053    pub fn convert_to_title_case(
12054        &mut self,
12055        _: &ConvertToTitleCase,
12056        window: &mut Window,
12057        cx: &mut Context<Self>,
12058    ) {
12059        self.manipulate_text(window, cx, |text| {
12060            text.split('\n')
12061                .map(|line| line.to_case(Case::Title))
12062                .join("\n")
12063        })
12064    }
12065
12066    pub fn convert_to_snake_case(
12067        &mut self,
12068        _: &ConvertToSnakeCase,
12069        window: &mut Window,
12070        cx: &mut Context<Self>,
12071    ) {
12072        self.manipulate_text(window, cx, |text| text.to_case(Case::Snake))
12073    }
12074
12075    pub fn convert_to_kebab_case(
12076        &mut self,
12077        _: &ConvertToKebabCase,
12078        window: &mut Window,
12079        cx: &mut Context<Self>,
12080    ) {
12081        self.manipulate_text(window, cx, |text| text.to_case(Case::Kebab))
12082    }
12083
12084    pub fn convert_to_upper_camel_case(
12085        &mut self,
12086        _: &ConvertToUpperCamelCase,
12087        window: &mut Window,
12088        cx: &mut Context<Self>,
12089    ) {
12090        self.manipulate_text(window, cx, |text| {
12091            text.split('\n')
12092                .map(|line| line.to_case(Case::UpperCamel))
12093                .join("\n")
12094        })
12095    }
12096
12097    pub fn convert_to_lower_camel_case(
12098        &mut self,
12099        _: &ConvertToLowerCamelCase,
12100        window: &mut Window,
12101        cx: &mut Context<Self>,
12102    ) {
12103        self.manipulate_text(window, cx, |text| text.to_case(Case::Camel))
12104    }
12105
12106    pub fn convert_to_opposite_case(
12107        &mut self,
12108        _: &ConvertToOppositeCase,
12109        window: &mut Window,
12110        cx: &mut Context<Self>,
12111    ) {
12112        self.manipulate_text(window, cx, |text| {
12113            text.chars()
12114                .fold(String::with_capacity(text.len()), |mut t, c| {
12115                    if c.is_uppercase() {
12116                        t.extend(c.to_lowercase());
12117                    } else {
12118                        t.extend(c.to_uppercase());
12119                    }
12120                    t
12121                })
12122        })
12123    }
12124
12125    pub fn convert_to_sentence_case(
12126        &mut self,
12127        _: &ConvertToSentenceCase,
12128        window: &mut Window,
12129        cx: &mut Context<Self>,
12130    ) {
12131        self.manipulate_text(window, cx, |text| text.to_case(Case::Sentence))
12132    }
12133
12134    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
12135        self.manipulate_text(window, cx, |text| {
12136            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
12137            if has_upper_case_characters {
12138                text.to_lowercase()
12139            } else {
12140                text.to_uppercase()
12141            }
12142        })
12143    }
12144
12145    pub fn convert_to_rot13(
12146        &mut self,
12147        _: &ConvertToRot13,
12148        window: &mut Window,
12149        cx: &mut Context<Self>,
12150    ) {
12151        self.manipulate_text(window, cx, |text| {
12152            text.chars()
12153                .map(|c| match c {
12154                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
12155                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
12156                    _ => c,
12157                })
12158                .collect()
12159        })
12160    }
12161
12162    pub fn convert_to_rot47(
12163        &mut self,
12164        _: &ConvertToRot47,
12165        window: &mut Window,
12166        cx: &mut Context<Self>,
12167    ) {
12168        self.manipulate_text(window, cx, |text| {
12169            text.chars()
12170                .map(|c| {
12171                    let code_point = c as u32;
12172                    if code_point >= 33 && code_point <= 126 {
12173                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
12174                    }
12175                    c
12176                })
12177                .collect()
12178        })
12179    }
12180
12181    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
12182    where
12183        Fn: FnMut(&str) -> String,
12184    {
12185        let buffer = self.buffer.read(cx).snapshot(cx);
12186
12187        let mut new_selections = Vec::new();
12188        let mut edits = Vec::new();
12189        let mut selection_adjustment = 0isize;
12190
12191        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
12192            let selection_is_empty = selection.is_empty();
12193
12194            let (start, end) = if selection_is_empty {
12195                let (word_range, _) = buffer.surrounding_word(selection.start, None);
12196                (word_range.start, word_range.end)
12197            } else {
12198                (
12199                    buffer.point_to_offset(selection.start),
12200                    buffer.point_to_offset(selection.end),
12201                )
12202            };
12203
12204            let text = buffer.text_for_range(start..end).collect::<String>();
12205            let old_length = text.len() as isize;
12206            let text = callback(&text);
12207
12208            new_selections.push(Selection {
12209                start: MultiBufferOffset((start.0 as isize - selection_adjustment) as usize),
12210                end: MultiBufferOffset(
12211                    ((start.0 + text.len()) as isize - selection_adjustment) as usize,
12212                ),
12213                goal: SelectionGoal::None,
12214                id: selection.id,
12215                reversed: selection.reversed,
12216            });
12217
12218            selection_adjustment += old_length - text.len() as isize;
12219
12220            edits.push((start..end, text));
12221        }
12222
12223        self.transact(window, cx, |this, window, cx| {
12224            this.buffer.update(cx, |buffer, cx| {
12225                buffer.edit(edits, None, cx);
12226            });
12227
12228            this.change_selections(Default::default(), window, cx, |s| {
12229                s.select(new_selections);
12230            });
12231
12232            this.request_autoscroll(Autoscroll::fit(), cx);
12233        });
12234    }
12235
12236    pub fn move_selection_on_drop(
12237        &mut self,
12238        selection: &Selection<Anchor>,
12239        target: DisplayPoint,
12240        is_cut: bool,
12241        window: &mut Window,
12242        cx: &mut Context<Self>,
12243    ) {
12244        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12245        let buffer = display_map.buffer_snapshot();
12246        let mut edits = Vec::new();
12247        let insert_point = display_map
12248            .clip_point(target, Bias::Left)
12249            .to_point(&display_map);
12250        let text = buffer
12251            .text_for_range(selection.start..selection.end)
12252            .collect::<String>();
12253        if is_cut {
12254            edits.push(((selection.start..selection.end), String::new()));
12255        }
12256        let insert_anchor = buffer.anchor_before(insert_point);
12257        edits.push(((insert_anchor..insert_anchor), text));
12258        let last_edit_start = insert_anchor.bias_left(buffer);
12259        let last_edit_end = insert_anchor.bias_right(buffer);
12260        self.transact(window, cx, |this, window, cx| {
12261            this.buffer.update(cx, |buffer, cx| {
12262                buffer.edit(edits, None, cx);
12263            });
12264            this.change_selections(Default::default(), window, cx, |s| {
12265                s.select_anchor_ranges([last_edit_start..last_edit_end]);
12266            });
12267        });
12268    }
12269
12270    pub fn clear_selection_drag_state(&mut self) {
12271        self.selection_drag_state = SelectionDragState::None;
12272    }
12273
12274    pub fn duplicate(
12275        &mut self,
12276        upwards: bool,
12277        whole_lines: bool,
12278        window: &mut Window,
12279        cx: &mut Context<Self>,
12280    ) {
12281        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12282
12283        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12284        let buffer = display_map.buffer_snapshot();
12285        let selections = self.selections.all::<Point>(&display_map);
12286
12287        let mut edits = Vec::new();
12288        let mut selections_iter = selections.iter().peekable();
12289        while let Some(selection) = selections_iter.next() {
12290            let mut rows = selection.spanned_rows(false, &display_map);
12291            // duplicate line-wise
12292            if whole_lines || selection.start == selection.end {
12293                // Avoid duplicating the same lines twice.
12294                while let Some(next_selection) = selections_iter.peek() {
12295                    let next_rows = next_selection.spanned_rows(false, &display_map);
12296                    if next_rows.start < rows.end {
12297                        rows.end = next_rows.end;
12298                        selections_iter.next().unwrap();
12299                    } else {
12300                        break;
12301                    }
12302                }
12303
12304                // Copy the text from the selected row region and splice it either at the start
12305                // or end of the region.
12306                let start = Point::new(rows.start.0, 0);
12307                let end = Point::new(
12308                    rows.end.previous_row().0,
12309                    buffer.line_len(rows.end.previous_row()),
12310                );
12311
12312                let mut text = buffer.text_for_range(start..end).collect::<String>();
12313
12314                let insert_location = if upwards {
12315                    // When duplicating upward, we need to insert before the current line.
12316                    // If we're on the last line and it doesn't end with a newline,
12317                    // we need to add a newline before the duplicated content.
12318                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
12319                        && buffer.max_point().column > 0
12320                        && !text.ends_with('\n');
12321
12322                    if needs_leading_newline {
12323                        text.insert(0, '\n');
12324                        end
12325                    } else {
12326                        text.push('\n');
12327                        Point::new(rows.start.0, 0)
12328                    }
12329                } else {
12330                    text.push('\n');
12331                    start
12332                };
12333                edits.push((insert_location..insert_location, text));
12334            } else {
12335                // duplicate character-wise
12336                let start = selection.start;
12337                let end = selection.end;
12338                let text = buffer.text_for_range(start..end).collect::<String>();
12339                edits.push((selection.end..selection.end, text));
12340            }
12341        }
12342
12343        self.transact(window, cx, |this, window, cx| {
12344            this.buffer.update(cx, |buffer, cx| {
12345                buffer.edit(edits, None, cx);
12346            });
12347
12348            // When duplicating upward with whole lines, move the cursor to the duplicated line
12349            if upwards && whole_lines {
12350                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
12351
12352                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12353                    let mut new_ranges = Vec::new();
12354                    let selections = s.all::<Point>(&display_map);
12355                    let mut selections_iter = selections.iter().peekable();
12356
12357                    while let Some(first_selection) = selections_iter.next() {
12358                        // Group contiguous selections together to find the total row span
12359                        let mut group_selections = vec![first_selection];
12360                        let mut rows = first_selection.spanned_rows(false, &display_map);
12361
12362                        while let Some(next_selection) = selections_iter.peek() {
12363                            let next_rows = next_selection.spanned_rows(false, &display_map);
12364                            if next_rows.start < rows.end {
12365                                rows.end = next_rows.end;
12366                                group_selections.push(selections_iter.next().unwrap());
12367                            } else {
12368                                break;
12369                            }
12370                        }
12371
12372                        let row_count = rows.end.0 - rows.start.0;
12373
12374                        // Move all selections in this group up by the total number of duplicated rows
12375                        for selection in group_selections {
12376                            let new_start = Point::new(
12377                                selection.start.row.saturating_sub(row_count),
12378                                selection.start.column,
12379                            );
12380
12381                            let new_end = Point::new(
12382                                selection.end.row.saturating_sub(row_count),
12383                                selection.end.column,
12384                            );
12385
12386                            new_ranges.push(new_start..new_end);
12387                        }
12388                    }
12389
12390                    s.select_ranges(new_ranges);
12391                });
12392            }
12393
12394            this.request_autoscroll(Autoscroll::fit(), cx);
12395        });
12396    }
12397
12398    pub fn duplicate_line_up(
12399        &mut self,
12400        _: &DuplicateLineUp,
12401        window: &mut Window,
12402        cx: &mut Context<Self>,
12403    ) {
12404        self.duplicate(true, true, window, cx);
12405    }
12406
12407    pub fn duplicate_line_down(
12408        &mut self,
12409        _: &DuplicateLineDown,
12410        window: &mut Window,
12411        cx: &mut Context<Self>,
12412    ) {
12413        self.duplicate(false, true, window, cx);
12414    }
12415
12416    pub fn duplicate_selection(
12417        &mut self,
12418        _: &DuplicateSelection,
12419        window: &mut Window,
12420        cx: &mut Context<Self>,
12421    ) {
12422        self.duplicate(false, false, window, cx);
12423    }
12424
12425    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
12426        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12427        if self.mode.is_single_line() {
12428            cx.propagate();
12429            return;
12430        }
12431
12432        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12433        let buffer = self.buffer.read(cx).snapshot(cx);
12434
12435        let mut edits = Vec::new();
12436        let mut unfold_ranges = Vec::new();
12437        let mut refold_creases = Vec::new();
12438
12439        let selections = self.selections.all::<Point>(&display_map);
12440        let mut selections = selections.iter().peekable();
12441        let mut contiguous_row_selections = Vec::new();
12442        let mut new_selections = Vec::new();
12443
12444        while let Some(selection) = selections.next() {
12445            // Find all the selections that span a contiguous row range
12446            let (start_row, end_row) = consume_contiguous_rows(
12447                &mut contiguous_row_selections,
12448                selection,
12449                &display_map,
12450                &mut selections,
12451            );
12452
12453            // Move the text spanned by the row range to be before the line preceding the row range
12454            if start_row.0 > 0 {
12455                let range_to_move = Point::new(
12456                    start_row.previous_row().0,
12457                    buffer.line_len(start_row.previous_row()),
12458                )
12459                    ..Point::new(
12460                        end_row.previous_row().0,
12461                        buffer.line_len(end_row.previous_row()),
12462                    );
12463                let insertion_point = display_map
12464                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
12465                    .0;
12466
12467                // Don't move lines across excerpts
12468                if buffer
12469                    .excerpt_containing(insertion_point..range_to_move.end)
12470                    .is_some()
12471                {
12472                    let text = buffer
12473                        .text_for_range(range_to_move.clone())
12474                        .flat_map(|s| s.chars())
12475                        .skip(1)
12476                        .chain(['\n'])
12477                        .collect::<String>();
12478
12479                    edits.push((
12480                        buffer.anchor_after(range_to_move.start)
12481                            ..buffer.anchor_before(range_to_move.end),
12482                        String::new(),
12483                    ));
12484                    let insertion_anchor = buffer.anchor_after(insertion_point);
12485                    edits.push((insertion_anchor..insertion_anchor, text));
12486
12487                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
12488
12489                    // Move selections up
12490                    new_selections.extend(contiguous_row_selections.drain(..).map(
12491                        |mut selection| {
12492                            selection.start.row -= row_delta;
12493                            selection.end.row -= row_delta;
12494                            selection
12495                        },
12496                    ));
12497
12498                    // Move folds up
12499                    unfold_ranges.push(range_to_move.clone());
12500                    for fold in display_map.folds_in_range(
12501                        buffer.anchor_before(range_to_move.start)
12502                            ..buffer.anchor_after(range_to_move.end),
12503                    ) {
12504                        let mut start = fold.range.start.to_point(&buffer);
12505                        let mut end = fold.range.end.to_point(&buffer);
12506                        start.row -= row_delta;
12507                        end.row -= row_delta;
12508                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12509                    }
12510                }
12511            }
12512
12513            // If we didn't move line(s), preserve the existing selections
12514            new_selections.append(&mut contiguous_row_selections);
12515        }
12516
12517        self.transact(window, cx, |this, window, cx| {
12518            this.unfold_ranges(&unfold_ranges, true, true, cx);
12519            this.buffer.update(cx, |buffer, cx| {
12520                for (range, text) in edits {
12521                    buffer.edit([(range, text)], None, cx);
12522                }
12523            });
12524            this.fold_creases(refold_creases, true, window, cx);
12525            this.change_selections(Default::default(), window, cx, |s| {
12526                s.select(new_selections);
12527            })
12528        });
12529    }
12530
12531    pub fn move_line_down(
12532        &mut self,
12533        _: &MoveLineDown,
12534        window: &mut Window,
12535        cx: &mut Context<Self>,
12536    ) {
12537        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12538        if self.mode.is_single_line() {
12539            cx.propagate();
12540            return;
12541        }
12542
12543        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12544        let buffer = self.buffer.read(cx).snapshot(cx);
12545
12546        let mut edits = Vec::new();
12547        let mut unfold_ranges = Vec::new();
12548        let mut refold_creases = Vec::new();
12549
12550        let selections = self.selections.all::<Point>(&display_map);
12551        let mut selections = selections.iter().peekable();
12552        let mut contiguous_row_selections = Vec::new();
12553        let mut new_selections = Vec::new();
12554
12555        while let Some(selection) = selections.next() {
12556            // Find all the selections that span a contiguous row range
12557            let (start_row, end_row) = consume_contiguous_rows(
12558                &mut contiguous_row_selections,
12559                selection,
12560                &display_map,
12561                &mut selections,
12562            );
12563
12564            // Move the text spanned by the row range to be after the last line of the row range
12565            if end_row.0 <= buffer.max_point().row {
12566                let range_to_move =
12567                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
12568                let insertion_point = display_map
12569                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
12570                    .0;
12571
12572                // Don't move lines across excerpt boundaries
12573                if buffer
12574                    .excerpt_containing(range_to_move.start..insertion_point)
12575                    .is_some()
12576                {
12577                    let mut text = String::from("\n");
12578                    text.extend(buffer.text_for_range(range_to_move.clone()));
12579                    text.pop(); // Drop trailing newline
12580                    edits.push((
12581                        buffer.anchor_after(range_to_move.start)
12582                            ..buffer.anchor_before(range_to_move.end),
12583                        String::new(),
12584                    ));
12585                    let insertion_anchor = buffer.anchor_after(insertion_point);
12586                    edits.push((insertion_anchor..insertion_anchor, text));
12587
12588                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12589
12590                    // Move selections down
12591                    new_selections.extend(contiguous_row_selections.drain(..).map(
12592                        |mut selection| {
12593                            selection.start.row += row_delta;
12594                            selection.end.row += row_delta;
12595                            selection
12596                        },
12597                    ));
12598
12599                    // Move folds down
12600                    unfold_ranges.push(range_to_move.clone());
12601                    for fold in display_map.folds_in_range(
12602                        buffer.anchor_before(range_to_move.start)
12603                            ..buffer.anchor_after(range_to_move.end),
12604                    ) {
12605                        let mut start = fold.range.start.to_point(&buffer);
12606                        let mut end = fold.range.end.to_point(&buffer);
12607                        start.row += row_delta;
12608                        end.row += row_delta;
12609                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12610                    }
12611                }
12612            }
12613
12614            // If we didn't move line(s), preserve the existing selections
12615            new_selections.append(&mut contiguous_row_selections);
12616        }
12617
12618        self.transact(window, cx, |this, window, cx| {
12619            this.unfold_ranges(&unfold_ranges, true, true, cx);
12620            this.buffer.update(cx, |buffer, cx| {
12621                for (range, text) in edits {
12622                    buffer.edit([(range, text)], None, cx);
12623                }
12624            });
12625            this.fold_creases(refold_creases, true, window, cx);
12626            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
12627        });
12628    }
12629
12630    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
12631        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12632        let text_layout_details = &self.text_layout_details(window);
12633        self.transact(window, cx, |this, window, cx| {
12634            let edits = this.change_selections(Default::default(), window, cx, |s| {
12635                let mut edits: Vec<(Range<MultiBufferOffset>, String)> = Default::default();
12636                s.move_with(|display_map, selection| {
12637                    if !selection.is_empty() {
12638                        return;
12639                    }
12640
12641                    let mut head = selection.head();
12642                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
12643                    if head.column() == display_map.line_len(head.row()) {
12644                        transpose_offset = display_map
12645                            .buffer_snapshot()
12646                            .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12647                    }
12648
12649                    if transpose_offset == MultiBufferOffset(0) {
12650                        return;
12651                    }
12652
12653                    *head.column_mut() += 1;
12654                    head = display_map.clip_point(head, Bias::Right);
12655                    let goal = SelectionGoal::HorizontalPosition(
12656                        display_map
12657                            .x_for_display_point(head, text_layout_details)
12658                            .into(),
12659                    );
12660                    selection.collapse_to(head, goal);
12661
12662                    let transpose_start = display_map
12663                        .buffer_snapshot()
12664                        .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
12665                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
12666                        let transpose_end = display_map
12667                            .buffer_snapshot()
12668                            .clip_offset(transpose_offset + 1usize, Bias::Right);
12669                        if let Some(ch) = display_map
12670                            .buffer_snapshot()
12671                            .chars_at(transpose_start)
12672                            .next()
12673                        {
12674                            edits.push((transpose_start..transpose_offset, String::new()));
12675                            edits.push((transpose_end..transpose_end, ch.to_string()));
12676                        }
12677                    }
12678                });
12679                edits
12680            });
12681            this.buffer
12682                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
12683            let selections = this
12684                .selections
12685                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
12686            this.change_selections(Default::default(), window, cx, |s| {
12687                s.select(selections);
12688            });
12689        });
12690    }
12691
12692    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
12693        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12694        if self.mode.is_single_line() {
12695            cx.propagate();
12696            return;
12697        }
12698
12699        self.rewrap_impl(RewrapOptions::default(), cx)
12700    }
12701
12702    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
12703        let buffer = self.buffer.read(cx).snapshot(cx);
12704        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
12705
12706        #[derive(Clone, Debug, PartialEq)]
12707        enum CommentFormat {
12708            /// single line comment, with prefix for line
12709            Line(String),
12710            /// single line within a block comment, with prefix for line
12711            BlockLine(String),
12712            /// a single line of a block comment that includes the initial delimiter
12713            BlockCommentWithStart(BlockCommentConfig),
12714            /// a single line of a block comment that includes the ending delimiter
12715            BlockCommentWithEnd(BlockCommentConfig),
12716        }
12717
12718        // Split selections to respect paragraph, indent, and comment prefix boundaries.
12719        let wrap_ranges = selections.into_iter().flat_map(|selection| {
12720            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
12721                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
12722                .peekable();
12723
12724            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
12725                row
12726            } else {
12727                return Vec::new();
12728            };
12729
12730            let language_settings = buffer.language_settings_at(selection.head(), cx);
12731            let language_scope = buffer.language_scope_at(selection.head());
12732
12733            let indent_and_prefix_for_row =
12734                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
12735                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
12736                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
12737                        &language_scope
12738                    {
12739                        let indent_end = Point::new(row, indent.len);
12740                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12741                        let line_text_after_indent = buffer
12742                            .text_for_range(indent_end..line_end)
12743                            .collect::<String>();
12744
12745                        let is_within_comment_override = buffer
12746                            .language_scope_at(indent_end)
12747                            .is_some_and(|scope| scope.override_name() == Some("comment"));
12748                        let comment_delimiters = if is_within_comment_override {
12749                            // we are within a comment syntax node, but we don't
12750                            // yet know what kind of comment: block, doc or line
12751                            match (
12752                                language_scope.documentation_comment(),
12753                                language_scope.block_comment(),
12754                            ) {
12755                                (Some(config), _) | (_, Some(config))
12756                                    if buffer.contains_str_at(indent_end, &config.start) =>
12757                                {
12758                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
12759                                }
12760                                (Some(config), _) | (_, Some(config))
12761                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
12762                                {
12763                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
12764                                }
12765                                (Some(config), _) | (_, Some(config))
12766                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
12767                                {
12768                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
12769                                }
12770                                (_, _) => language_scope
12771                                    .line_comment_prefixes()
12772                                    .iter()
12773                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12774                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
12775                            }
12776                        } else {
12777                            // we not in an overridden comment node, but we may
12778                            // be within a non-overridden line comment node
12779                            language_scope
12780                                .line_comment_prefixes()
12781                                .iter()
12782                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
12783                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
12784                        };
12785
12786                        let rewrap_prefix = language_scope
12787                            .rewrap_prefixes()
12788                            .iter()
12789                            .find_map(|prefix_regex| {
12790                                prefix_regex.find(&line_text_after_indent).map(|mat| {
12791                                    if mat.start() == 0 {
12792                                        Some(mat.as_str().to_string())
12793                                    } else {
12794                                        None
12795                                    }
12796                                })
12797                            })
12798                            .flatten();
12799                        (comment_delimiters, rewrap_prefix)
12800                    } else {
12801                        (None, None)
12802                    };
12803                    (indent, comment_prefix, rewrap_prefix)
12804                };
12805
12806            let mut ranges = Vec::new();
12807            let from_empty_selection = selection.is_empty();
12808
12809            let mut current_range_start = first_row;
12810            let mut prev_row = first_row;
12811            let (
12812                mut current_range_indent,
12813                mut current_range_comment_delimiters,
12814                mut current_range_rewrap_prefix,
12815            ) = indent_and_prefix_for_row(first_row);
12816
12817            for row in non_blank_rows_iter.skip(1) {
12818                let has_paragraph_break = row > prev_row + 1;
12819
12820                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
12821                    indent_and_prefix_for_row(row);
12822
12823                let has_indent_change = row_indent != current_range_indent;
12824                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
12825
12826                let has_boundary_change = has_comment_change
12827                    || row_rewrap_prefix.is_some()
12828                    || (has_indent_change && current_range_comment_delimiters.is_some());
12829
12830                if has_paragraph_break || has_boundary_change {
12831                    ranges.push((
12832                        language_settings.clone(),
12833                        Point::new(current_range_start, 0)
12834                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12835                        current_range_indent,
12836                        current_range_comment_delimiters.clone(),
12837                        current_range_rewrap_prefix.clone(),
12838                        from_empty_selection,
12839                    ));
12840                    current_range_start = row;
12841                    current_range_indent = row_indent;
12842                    current_range_comment_delimiters = row_comment_delimiters;
12843                    current_range_rewrap_prefix = row_rewrap_prefix;
12844                }
12845                prev_row = row;
12846            }
12847
12848            ranges.push((
12849                language_settings.clone(),
12850                Point::new(current_range_start, 0)
12851                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
12852                current_range_indent,
12853                current_range_comment_delimiters,
12854                current_range_rewrap_prefix,
12855                from_empty_selection,
12856            ));
12857
12858            ranges
12859        });
12860
12861        let mut edits = Vec::new();
12862        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
12863
12864        for (
12865            language_settings,
12866            wrap_range,
12867            mut indent_size,
12868            comment_prefix,
12869            rewrap_prefix,
12870            from_empty_selection,
12871        ) in wrap_ranges
12872        {
12873            let mut start_row = wrap_range.start.row;
12874            let mut end_row = wrap_range.end.row;
12875
12876            // Skip selections that overlap with a range that has already been rewrapped.
12877            let selection_range = start_row..end_row;
12878            if rewrapped_row_ranges
12879                .iter()
12880                .any(|range| range.overlaps(&selection_range))
12881            {
12882                continue;
12883            }
12884
12885            let tab_size = language_settings.tab_size;
12886
12887            let (line_prefix, inside_comment) = match &comment_prefix {
12888                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
12889                    (Some(prefix.as_str()), true)
12890                }
12891                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
12892                    (Some(prefix.as_ref()), true)
12893                }
12894                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12895                    start: _,
12896                    end: _,
12897                    prefix,
12898                    tab_size,
12899                })) => {
12900                    indent_size.len += tab_size;
12901                    (Some(prefix.as_ref()), true)
12902                }
12903                None => (None, false),
12904            };
12905            let indent_prefix = indent_size.chars().collect::<String>();
12906            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
12907
12908            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
12909                RewrapBehavior::InComments => inside_comment,
12910                RewrapBehavior::InSelections => !wrap_range.is_empty(),
12911                RewrapBehavior::Anywhere => true,
12912            };
12913
12914            let should_rewrap = options.override_language_settings
12915                || allow_rewrap_based_on_language
12916                || self.hard_wrap.is_some();
12917            if !should_rewrap {
12918                continue;
12919            }
12920
12921            if from_empty_selection {
12922                'expand_upwards: while start_row > 0 {
12923                    let prev_row = start_row - 1;
12924                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
12925                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
12926                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
12927                    {
12928                        start_row = prev_row;
12929                    } else {
12930                        break 'expand_upwards;
12931                    }
12932                }
12933
12934                'expand_downwards: while end_row < buffer.max_point().row {
12935                    let next_row = end_row + 1;
12936                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
12937                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
12938                        && !buffer.is_line_blank(MultiBufferRow(next_row))
12939                    {
12940                        end_row = next_row;
12941                    } else {
12942                        break 'expand_downwards;
12943                    }
12944                }
12945            }
12946
12947            let start = Point::new(start_row, 0);
12948            let start_offset = ToOffset::to_offset(&start, &buffer);
12949            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
12950            let selection_text = buffer.text_for_range(start..end).collect::<String>();
12951            let mut first_line_delimiter = None;
12952            let mut last_line_delimiter = None;
12953            let Some(lines_without_prefixes) = selection_text
12954                .lines()
12955                .enumerate()
12956                .map(|(ix, line)| {
12957                    let line_trimmed = line.trim_start();
12958                    if rewrap_prefix.is_some() && ix > 0 {
12959                        Ok(line_trimmed)
12960                    } else if let Some(
12961                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
12962                            start,
12963                            prefix,
12964                            end,
12965                            tab_size,
12966                        })
12967                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
12968                            start,
12969                            prefix,
12970                            end,
12971                            tab_size,
12972                        }),
12973                    ) = &comment_prefix
12974                    {
12975                        let line_trimmed = line_trimmed
12976                            .strip_prefix(start.as_ref())
12977                            .map(|s| {
12978                                let mut indent_size = indent_size;
12979                                indent_size.len -= tab_size;
12980                                let indent_prefix: String = indent_size.chars().collect();
12981                                first_line_delimiter = Some((indent_prefix, start));
12982                                s.trim_start()
12983                            })
12984                            .unwrap_or(line_trimmed);
12985                        let line_trimmed = line_trimmed
12986                            .strip_suffix(end.as_ref())
12987                            .map(|s| {
12988                                last_line_delimiter = Some(end);
12989                                s.trim_end()
12990                            })
12991                            .unwrap_or(line_trimmed);
12992                        let line_trimmed = line_trimmed
12993                            .strip_prefix(prefix.as_ref())
12994                            .unwrap_or(line_trimmed);
12995                        Ok(line_trimmed)
12996                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
12997                        line_trimmed.strip_prefix(prefix).with_context(|| {
12998                            format!("line did not start with prefix {prefix:?}: {line:?}")
12999                        })
13000                    } else {
13001                        line_trimmed
13002                            .strip_prefix(&line_prefix.trim_start())
13003                            .with_context(|| {
13004                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
13005                            })
13006                    }
13007                })
13008                .collect::<Result<Vec<_>, _>>()
13009                .log_err()
13010            else {
13011                continue;
13012            };
13013
13014            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
13015                buffer
13016                    .language_settings_at(Point::new(start_row, 0), cx)
13017                    .preferred_line_length as usize
13018            });
13019
13020            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
13021                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
13022            } else {
13023                line_prefix.clone()
13024            };
13025
13026            let wrapped_text = {
13027                let mut wrapped_text = wrap_with_prefix(
13028                    line_prefix,
13029                    subsequent_lines_prefix,
13030                    lines_without_prefixes.join("\n"),
13031                    wrap_column,
13032                    tab_size,
13033                    options.preserve_existing_whitespace,
13034                );
13035
13036                if let Some((indent, delimiter)) = first_line_delimiter {
13037                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
13038                }
13039                if let Some(last_line) = last_line_delimiter {
13040                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
13041                }
13042
13043                wrapped_text
13044            };
13045
13046            // TODO: should always use char-based diff while still supporting cursor behavior that
13047            // matches vim.
13048            let mut diff_options = DiffOptions::default();
13049            if options.override_language_settings {
13050                diff_options.max_word_diff_len = 0;
13051                diff_options.max_word_diff_line_count = 0;
13052            } else {
13053                diff_options.max_word_diff_len = usize::MAX;
13054                diff_options.max_word_diff_line_count = usize::MAX;
13055            }
13056
13057            for (old_range, new_text) in
13058                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
13059            {
13060                let edit_start = buffer.anchor_after(start_offset + old_range.start);
13061                let edit_end = buffer.anchor_after(start_offset + old_range.end);
13062                edits.push((edit_start..edit_end, new_text));
13063            }
13064
13065            rewrapped_row_ranges.push(start_row..=end_row);
13066        }
13067
13068        self.buffer
13069            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
13070    }
13071
13072    pub fn cut_common(
13073        &mut self,
13074        cut_no_selection_line: bool,
13075        window: &mut Window,
13076        cx: &mut Context<Self>,
13077    ) -> ClipboardItem {
13078        let mut text = String::new();
13079        let buffer = self.buffer.read(cx).snapshot(cx);
13080        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13081        let mut clipboard_selections = Vec::with_capacity(selections.len());
13082        {
13083            let max_point = buffer.max_point();
13084            let mut is_first = true;
13085            let mut prev_selection_was_entire_line = false;
13086            for selection in &mut selections {
13087                let is_entire_line =
13088                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
13089                if is_entire_line {
13090                    selection.start = Point::new(selection.start.row, 0);
13091                    if !selection.is_empty() && selection.end.column == 0 {
13092                        selection.end = cmp::min(max_point, selection.end);
13093                    } else {
13094                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
13095                    }
13096                    selection.goal = SelectionGoal::None;
13097                }
13098                if is_first {
13099                    is_first = false;
13100                } else if !prev_selection_was_entire_line {
13101                    text += "\n";
13102                }
13103                prev_selection_was_entire_line = is_entire_line;
13104                let mut len = 0;
13105                for chunk in buffer.text_for_range(selection.start..selection.end) {
13106                    text.push_str(chunk);
13107                    len += chunk.len();
13108                }
13109
13110                clipboard_selections.push(ClipboardSelection::for_buffer(
13111                    len,
13112                    is_entire_line,
13113                    selection.range(),
13114                    &buffer,
13115                    self.project.as_ref(),
13116                    cx,
13117                ));
13118            }
13119        }
13120
13121        self.transact(window, cx, |this, window, cx| {
13122            this.change_selections(Default::default(), window, cx, |s| {
13123                s.select(selections);
13124            });
13125            this.insert("", window, cx);
13126        });
13127        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
13128    }
13129
13130    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
13131        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13132        let item = self.cut_common(true, window, cx);
13133        cx.write_to_clipboard(item);
13134    }
13135
13136    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
13137        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13138        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13139            s.move_with(|snapshot, sel| {
13140                if sel.is_empty() {
13141                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
13142                }
13143                if sel.is_empty() {
13144                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13145                }
13146            });
13147        });
13148        let item = self.cut_common(false, window, cx);
13149        cx.set_global(KillRing(item))
13150    }
13151
13152    pub fn kill_ring_yank(
13153        &mut self,
13154        _: &KillRingYank,
13155        window: &mut Window,
13156        cx: &mut Context<Self>,
13157    ) {
13158        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13159        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
13160            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
13161                (kill_ring.text().to_string(), kill_ring.metadata_json())
13162            } else {
13163                return;
13164            }
13165        } else {
13166            return;
13167        };
13168        self.do_paste(&text, metadata, false, window, cx);
13169    }
13170
13171    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
13172        self.do_copy(true, cx);
13173    }
13174
13175    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
13176        self.do_copy(false, cx);
13177    }
13178
13179    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
13180        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13181        let buffer = self.buffer.read(cx).read(cx);
13182        let mut text = String::new();
13183
13184        let mut clipboard_selections = Vec::with_capacity(selections.len());
13185        {
13186            let max_point = buffer.max_point();
13187            let mut is_first = true;
13188            let mut prev_selection_was_entire_line = false;
13189            for selection in &selections {
13190                let mut start = selection.start;
13191                let mut end = selection.end;
13192                let is_entire_line = selection.is_empty() || self.selections.line_mode();
13193                let mut add_trailing_newline = false;
13194                if is_entire_line {
13195                    start = Point::new(start.row, 0);
13196                    let next_line_start = Point::new(end.row + 1, 0);
13197                    if next_line_start <= max_point {
13198                        end = next_line_start;
13199                    } else {
13200                        // We're on the last line without a trailing newline.
13201                        // Copy to the end of the line and add a newline afterwards.
13202                        end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
13203                        add_trailing_newline = true;
13204                    }
13205                }
13206
13207                let mut trimmed_selections = Vec::new();
13208                if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
13209                    let row = MultiBufferRow(start.row);
13210                    let first_indent = buffer.indent_size_for_line(row);
13211                    if first_indent.len == 0 || start.column > first_indent.len {
13212                        trimmed_selections.push(start..end);
13213                    } else {
13214                        trimmed_selections.push(
13215                            Point::new(row.0, first_indent.len)
13216                                ..Point::new(row.0, buffer.line_len(row)),
13217                        );
13218                        for row in start.row + 1..=end.row {
13219                            let mut line_len = buffer.line_len(MultiBufferRow(row));
13220                            if row == end.row {
13221                                line_len = end.column;
13222                            }
13223                            if line_len == 0 {
13224                                trimmed_selections
13225                                    .push(Point::new(row, 0)..Point::new(row, line_len));
13226                                continue;
13227                            }
13228                            let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
13229                            if row_indent_size.len >= first_indent.len {
13230                                trimmed_selections.push(
13231                                    Point::new(row, first_indent.len)..Point::new(row, line_len),
13232                                );
13233                            } else {
13234                                trimmed_selections.clear();
13235                                trimmed_selections.push(start..end);
13236                                break;
13237                            }
13238                        }
13239                    }
13240                } else {
13241                    trimmed_selections.push(start..end);
13242                }
13243
13244                for trimmed_range in trimmed_selections {
13245                    if is_first {
13246                        is_first = false;
13247                    } else if !prev_selection_was_entire_line {
13248                        text += "\n";
13249                    }
13250                    prev_selection_was_entire_line = is_entire_line;
13251                    let mut len = 0;
13252                    for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
13253                        text.push_str(chunk);
13254                        len += chunk.len();
13255                    }
13256                    if add_trailing_newline {
13257                        text.push('\n');
13258                        len += 1;
13259                    }
13260                    clipboard_selections.push(ClipboardSelection::for_buffer(
13261                        len,
13262                        is_entire_line,
13263                        trimmed_range,
13264                        &buffer,
13265                        self.project.as_ref(),
13266                        cx,
13267                    ));
13268                }
13269            }
13270        }
13271
13272        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
13273            text,
13274            clipboard_selections,
13275        ));
13276    }
13277
13278    pub fn do_paste(
13279        &mut self,
13280        text: &String,
13281        clipboard_selections: Option<Vec<ClipboardSelection>>,
13282        handle_entire_lines: bool,
13283        window: &mut Window,
13284        cx: &mut Context<Self>,
13285    ) {
13286        if self.read_only(cx) {
13287            return;
13288        }
13289
13290        let clipboard_text = Cow::Borrowed(text.as_str());
13291
13292        self.transact(window, cx, |this, window, cx| {
13293            let had_active_edit_prediction = this.has_active_edit_prediction();
13294            let display_map = this.display_snapshot(cx);
13295            let old_selections = this.selections.all::<MultiBufferOffset>(&display_map);
13296            let cursor_offset = this
13297                .selections
13298                .last::<MultiBufferOffset>(&display_map)
13299                .head();
13300
13301            if let Some(mut clipboard_selections) = clipboard_selections {
13302                let all_selections_were_entire_line =
13303                    clipboard_selections.iter().all(|s| s.is_entire_line);
13304                let first_selection_indent_column =
13305                    clipboard_selections.first().map(|s| s.first_line_indent);
13306                if clipboard_selections.len() != old_selections.len() {
13307                    clipboard_selections.drain(..);
13308                }
13309                let mut auto_indent_on_paste = true;
13310
13311                this.buffer.update(cx, |buffer, cx| {
13312                    let snapshot = buffer.read(cx);
13313                    auto_indent_on_paste = snapshot
13314                        .language_settings_at(cursor_offset, cx)
13315                        .auto_indent_on_paste;
13316
13317                    let mut start_offset = 0;
13318                    let mut edits = Vec::new();
13319                    let mut original_indent_columns = Vec::new();
13320                    for (ix, selection) in old_selections.iter().enumerate() {
13321                        let to_insert;
13322                        let entire_line;
13323                        let original_indent_column;
13324                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
13325                            let end_offset = start_offset + clipboard_selection.len;
13326                            to_insert = &clipboard_text[start_offset..end_offset];
13327                            entire_line = clipboard_selection.is_entire_line;
13328                            start_offset = if entire_line {
13329                                end_offset
13330                            } else {
13331                                end_offset + 1
13332                            };
13333                            original_indent_column = Some(clipboard_selection.first_line_indent);
13334                        } else {
13335                            to_insert = &*clipboard_text;
13336                            entire_line = all_selections_were_entire_line;
13337                            original_indent_column = first_selection_indent_column
13338                        }
13339
13340                        let (range, to_insert) =
13341                            if selection.is_empty() && handle_entire_lines && entire_line {
13342                                // If the corresponding selection was empty when this slice of the
13343                                // clipboard text was written, then the entire line containing the
13344                                // selection was copied. If this selection is also currently empty,
13345                                // then paste the line before the current line of the buffer.
13346                                let column = selection.start.to_point(&snapshot).column as usize;
13347                                let line_start = selection.start - column;
13348                                (line_start..line_start, Cow::Borrowed(to_insert))
13349                            } else {
13350                                let language = snapshot.language_at(selection.head());
13351                                let range = selection.range();
13352                                if let Some(language) = language
13353                                    && language.name() == "Markdown".into()
13354                                {
13355                                    edit_for_markdown_paste(
13356                                        &snapshot,
13357                                        range,
13358                                        to_insert,
13359                                        url::Url::parse(to_insert).ok(),
13360                                    )
13361                                } else {
13362                                    (range, Cow::Borrowed(to_insert))
13363                                }
13364                            };
13365
13366                        edits.push((range, to_insert));
13367                        original_indent_columns.push(original_indent_column);
13368                    }
13369                    drop(snapshot);
13370
13371                    buffer.edit(
13372                        edits,
13373                        if auto_indent_on_paste {
13374                            Some(AutoindentMode::Block {
13375                                original_indent_columns,
13376                            })
13377                        } else {
13378                            None
13379                        },
13380                        cx,
13381                    );
13382                });
13383
13384                let selections = this
13385                    .selections
13386                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
13387                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
13388            } else {
13389                let url = url::Url::parse(&clipboard_text).ok();
13390
13391                let auto_indent_mode = if !clipboard_text.is_empty() {
13392                    Some(AutoindentMode::Block {
13393                        original_indent_columns: Vec::new(),
13394                    })
13395                } else {
13396                    None
13397                };
13398
13399                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
13400                    let snapshot = buffer.snapshot(cx);
13401
13402                    let anchors = old_selections
13403                        .iter()
13404                        .map(|s| {
13405                            let anchor = snapshot.anchor_after(s.head());
13406                            s.map(|_| anchor)
13407                        })
13408                        .collect::<Vec<_>>();
13409
13410                    let mut edits = Vec::new();
13411
13412                    for selection in old_selections.iter() {
13413                        let language = snapshot.language_at(selection.head());
13414                        let range = selection.range();
13415
13416                        let (edit_range, edit_text) = if let Some(language) = language
13417                            && language.name() == "Markdown".into()
13418                        {
13419                            edit_for_markdown_paste(&snapshot, range, &clipboard_text, url.clone())
13420                        } else {
13421                            (range, clipboard_text.clone())
13422                        };
13423
13424                        edits.push((edit_range, edit_text));
13425                    }
13426
13427                    drop(snapshot);
13428                    buffer.edit(edits, auto_indent_mode, cx);
13429
13430                    anchors
13431                });
13432
13433                this.change_selections(Default::default(), window, cx, |s| {
13434                    s.select_anchors(selection_anchors);
13435                });
13436            }
13437
13438            //   🤔                 |    ..     | show_in_menu |
13439            // | ..                  |   true        true
13440            // | had_edit_prediction |   false       true
13441
13442            let trigger_in_words =
13443                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
13444
13445            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
13446        });
13447    }
13448
13449    pub fn diff_clipboard_with_selection(
13450        &mut self,
13451        _: &DiffClipboardWithSelection,
13452        window: &mut Window,
13453        cx: &mut Context<Self>,
13454    ) {
13455        let selections = self
13456            .selections
13457            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
13458
13459        if selections.is_empty() {
13460            log::warn!("There should always be at least one selection in Zed. This is a bug.");
13461            return;
13462        };
13463
13464        let clipboard_text = match cx.read_from_clipboard() {
13465            Some(item) => match item.entries().first() {
13466                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
13467                _ => None,
13468            },
13469            None => None,
13470        };
13471
13472        let Some(clipboard_text) = clipboard_text else {
13473            log::warn!("Clipboard doesn't contain text.");
13474            return;
13475        };
13476
13477        window.dispatch_action(
13478            Box::new(DiffClipboardWithSelectionData {
13479                clipboard_text,
13480                editor: cx.entity(),
13481            }),
13482            cx,
13483        );
13484    }
13485
13486    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
13487        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13488        if let Some(item) = cx.read_from_clipboard() {
13489            let entries = item.entries();
13490
13491            match entries.first() {
13492                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
13493                // of all the pasted entries.
13494                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
13495                    .do_paste(
13496                        clipboard_string.text(),
13497                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
13498                        true,
13499                        window,
13500                        cx,
13501                    ),
13502                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
13503            }
13504        }
13505    }
13506
13507    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
13508        if self.read_only(cx) {
13509            return;
13510        }
13511
13512        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13513
13514        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
13515            if let Some((selections, _)) =
13516                self.selection_history.transaction(transaction_id).cloned()
13517            {
13518                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13519                    s.select_anchors(selections.to_vec());
13520                });
13521            } else {
13522                log::error!(
13523                    "No entry in selection_history found for undo. \
13524                     This may correspond to a bug where undo does not update the selection. \
13525                     If this is occurring, please add details to \
13526                     https://github.com/zed-industries/zed/issues/22692"
13527                );
13528            }
13529            self.request_autoscroll(Autoscroll::fit(), cx);
13530            self.unmark_text(window, cx);
13531            self.refresh_edit_prediction(true, false, window, cx);
13532            cx.emit(EditorEvent::Edited { transaction_id });
13533            cx.emit(EditorEvent::TransactionUndone { transaction_id });
13534        }
13535    }
13536
13537    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
13538        if self.read_only(cx) {
13539            return;
13540        }
13541
13542        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13543
13544        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
13545            if let Some((_, Some(selections))) =
13546                self.selection_history.transaction(transaction_id).cloned()
13547            {
13548                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13549                    s.select_anchors(selections.to_vec());
13550                });
13551            } else {
13552                log::error!(
13553                    "No entry in selection_history found for redo. \
13554                     This may correspond to a bug where undo does not update the selection. \
13555                     If this is occurring, please add details to \
13556                     https://github.com/zed-industries/zed/issues/22692"
13557                );
13558            }
13559            self.request_autoscroll(Autoscroll::fit(), cx);
13560            self.unmark_text(window, cx);
13561            self.refresh_edit_prediction(true, false, window, cx);
13562            cx.emit(EditorEvent::Edited { transaction_id });
13563        }
13564    }
13565
13566    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
13567        self.buffer
13568            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
13569    }
13570
13571    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
13572        self.buffer
13573            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
13574    }
13575
13576    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
13577        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13578        self.change_selections(Default::default(), window, cx, |s| {
13579            s.move_with(|map, selection| {
13580                let cursor = if selection.is_empty() {
13581                    movement::left(map, selection.start)
13582                } else {
13583                    selection.start
13584                };
13585                selection.collapse_to(cursor, SelectionGoal::None);
13586            });
13587        })
13588    }
13589
13590    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
13591        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13592        self.change_selections(Default::default(), window, cx, |s| {
13593            s.move_heads_with(|map, head, _| (movement::left(map, head), SelectionGoal::None));
13594        })
13595    }
13596
13597    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
13598        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13599        self.change_selections(Default::default(), window, cx, |s| {
13600            s.move_with(|map, selection| {
13601                let cursor = if selection.is_empty() {
13602                    movement::right(map, selection.end)
13603                } else {
13604                    selection.end
13605                };
13606                selection.collapse_to(cursor, SelectionGoal::None)
13607            });
13608        })
13609    }
13610
13611    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
13612        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13613        self.change_selections(Default::default(), window, cx, |s| {
13614            s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
13615        });
13616    }
13617
13618    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
13619        if self.take_rename(true, window, cx).is_some() {
13620            return;
13621        }
13622
13623        if self.mode.is_single_line() {
13624            cx.propagate();
13625            return;
13626        }
13627
13628        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13629
13630        let text_layout_details = &self.text_layout_details(window);
13631        let selection_count = self.selections.count();
13632        let first_selection = self.selections.first_anchor();
13633
13634        self.change_selections(Default::default(), window, cx, |s| {
13635            s.move_with(|map, selection| {
13636                if !selection.is_empty() {
13637                    selection.goal = SelectionGoal::None;
13638                }
13639                let (cursor, goal) = movement::up(
13640                    map,
13641                    selection.start,
13642                    selection.goal,
13643                    false,
13644                    text_layout_details,
13645                );
13646                selection.collapse_to(cursor, goal);
13647            });
13648        });
13649
13650        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13651        {
13652            cx.propagate();
13653        }
13654    }
13655
13656    pub fn move_up_by_lines(
13657        &mut self,
13658        action: &MoveUpByLines,
13659        window: &mut Window,
13660        cx: &mut Context<Self>,
13661    ) {
13662        if self.take_rename(true, window, cx).is_some() {
13663            return;
13664        }
13665
13666        if self.mode.is_single_line() {
13667            cx.propagate();
13668            return;
13669        }
13670
13671        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13672
13673        let text_layout_details = &self.text_layout_details(window);
13674
13675        self.change_selections(Default::default(), window, cx, |s| {
13676            s.move_with(|map, selection| {
13677                if !selection.is_empty() {
13678                    selection.goal = SelectionGoal::None;
13679                }
13680                let (cursor, goal) = movement::up_by_rows(
13681                    map,
13682                    selection.start,
13683                    action.lines,
13684                    selection.goal,
13685                    false,
13686                    text_layout_details,
13687                );
13688                selection.collapse_to(cursor, goal);
13689            });
13690        })
13691    }
13692
13693    pub fn move_down_by_lines(
13694        &mut self,
13695        action: &MoveDownByLines,
13696        window: &mut Window,
13697        cx: &mut Context<Self>,
13698    ) {
13699        if self.take_rename(true, window, cx).is_some() {
13700            return;
13701        }
13702
13703        if self.mode.is_single_line() {
13704            cx.propagate();
13705            return;
13706        }
13707
13708        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13709
13710        let text_layout_details = &self.text_layout_details(window);
13711
13712        self.change_selections(Default::default(), window, cx, |s| {
13713            s.move_with(|map, selection| {
13714                if !selection.is_empty() {
13715                    selection.goal = SelectionGoal::None;
13716                }
13717                let (cursor, goal) = movement::down_by_rows(
13718                    map,
13719                    selection.start,
13720                    action.lines,
13721                    selection.goal,
13722                    false,
13723                    text_layout_details,
13724                );
13725                selection.collapse_to(cursor, goal);
13726            });
13727        })
13728    }
13729
13730    pub fn select_down_by_lines(
13731        &mut self,
13732        action: &SelectDownByLines,
13733        window: &mut Window,
13734        cx: &mut Context<Self>,
13735    ) {
13736        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13737        let text_layout_details = &self.text_layout_details(window);
13738        self.change_selections(Default::default(), window, cx, |s| {
13739            s.move_heads_with(|map, head, goal| {
13740                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
13741            })
13742        })
13743    }
13744
13745    pub fn select_up_by_lines(
13746        &mut self,
13747        action: &SelectUpByLines,
13748        window: &mut Window,
13749        cx: &mut Context<Self>,
13750    ) {
13751        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13752        let text_layout_details = &self.text_layout_details(window);
13753        self.change_selections(Default::default(), window, cx, |s| {
13754            s.move_heads_with(|map, head, goal| {
13755                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
13756            })
13757        })
13758    }
13759
13760    pub fn select_page_up(
13761        &mut self,
13762        _: &SelectPageUp,
13763        window: &mut Window,
13764        cx: &mut Context<Self>,
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 text_layout_details = &self.text_layout_details(window);
13773
13774        self.change_selections(Default::default(), window, cx, |s| {
13775            s.move_heads_with(|map, head, goal| {
13776                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
13777            })
13778        })
13779    }
13780
13781    pub fn move_page_up(
13782        &mut self,
13783        action: &MovePageUp,
13784        window: &mut Window,
13785        cx: &mut Context<Self>,
13786    ) {
13787        if self.take_rename(true, window, cx).is_some() {
13788            return;
13789        }
13790
13791        if self
13792            .context_menu
13793            .borrow_mut()
13794            .as_mut()
13795            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
13796            .unwrap_or(false)
13797        {
13798            return;
13799        }
13800
13801        if matches!(self.mode, EditorMode::SingleLine) {
13802            cx.propagate();
13803            return;
13804        }
13805
13806        let Some(row_count) = self.visible_row_count() else {
13807            return;
13808        };
13809
13810        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13811
13812        let effects = if action.center_cursor {
13813            SelectionEffects::scroll(Autoscroll::center())
13814        } else {
13815            SelectionEffects::default()
13816        };
13817
13818        let text_layout_details = &self.text_layout_details(window);
13819
13820        self.change_selections(effects, window, cx, |s| {
13821            s.move_with(|map, selection| {
13822                if !selection.is_empty() {
13823                    selection.goal = SelectionGoal::None;
13824                }
13825                let (cursor, goal) = movement::up_by_rows(
13826                    map,
13827                    selection.end,
13828                    row_count,
13829                    selection.goal,
13830                    false,
13831                    text_layout_details,
13832                );
13833                selection.collapse_to(cursor, goal);
13834            });
13835        });
13836    }
13837
13838    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
13839        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13840        let text_layout_details = &self.text_layout_details(window);
13841        self.change_selections(Default::default(), window, cx, |s| {
13842            s.move_heads_with(|map, head, goal| {
13843                movement::up(map, head, goal, false, text_layout_details)
13844            })
13845        })
13846    }
13847
13848    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
13849        self.take_rename(true, window, cx);
13850
13851        if self.mode.is_single_line() {
13852            cx.propagate();
13853            return;
13854        }
13855
13856        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13857
13858        let text_layout_details = &self.text_layout_details(window);
13859        let selection_count = self.selections.count();
13860        let first_selection = self.selections.first_anchor();
13861
13862        self.change_selections(Default::default(), window, cx, |s| {
13863            s.move_with(|map, selection| {
13864                if !selection.is_empty() {
13865                    selection.goal = SelectionGoal::None;
13866                }
13867                let (cursor, goal) = movement::down(
13868                    map,
13869                    selection.end,
13870                    selection.goal,
13871                    false,
13872                    text_layout_details,
13873                );
13874                selection.collapse_to(cursor, goal);
13875            });
13876        });
13877
13878        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
13879        {
13880            cx.propagate();
13881        }
13882    }
13883
13884    pub fn select_page_down(
13885        &mut self,
13886        _: &SelectPageDown,
13887        window: &mut Window,
13888        cx: &mut Context<Self>,
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 text_layout_details = &self.text_layout_details(window);
13897
13898        self.change_selections(Default::default(), window, cx, |s| {
13899            s.move_heads_with(|map, head, goal| {
13900                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
13901            })
13902        })
13903    }
13904
13905    pub fn move_page_down(
13906        &mut self,
13907        action: &MovePageDown,
13908        window: &mut Window,
13909        cx: &mut Context<Self>,
13910    ) {
13911        if self.take_rename(true, window, cx).is_some() {
13912            return;
13913        }
13914
13915        if self
13916            .context_menu
13917            .borrow_mut()
13918            .as_mut()
13919            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
13920            .unwrap_or(false)
13921        {
13922            return;
13923        }
13924
13925        if matches!(self.mode, EditorMode::SingleLine) {
13926            cx.propagate();
13927            return;
13928        }
13929
13930        let Some(row_count) = self.visible_row_count() else {
13931            return;
13932        };
13933
13934        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13935
13936        let effects = if action.center_cursor {
13937            SelectionEffects::scroll(Autoscroll::center())
13938        } else {
13939            SelectionEffects::default()
13940        };
13941
13942        let text_layout_details = &self.text_layout_details(window);
13943        self.change_selections(effects, window, cx, |s| {
13944            s.move_with(|map, selection| {
13945                if !selection.is_empty() {
13946                    selection.goal = SelectionGoal::None;
13947                }
13948                let (cursor, goal) = movement::down_by_rows(
13949                    map,
13950                    selection.end,
13951                    row_count,
13952                    selection.goal,
13953                    false,
13954                    text_layout_details,
13955                );
13956                selection.collapse_to(cursor, goal);
13957            });
13958        });
13959    }
13960
13961    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
13962        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13963        let text_layout_details = &self.text_layout_details(window);
13964        self.change_selections(Default::default(), window, cx, |s| {
13965            s.move_heads_with(|map, head, goal| {
13966                movement::down(map, head, goal, false, text_layout_details)
13967            })
13968        });
13969    }
13970
13971    pub fn context_menu_first(
13972        &mut self,
13973        _: &ContextMenuFirst,
13974        window: &mut Window,
13975        cx: &mut Context<Self>,
13976    ) {
13977        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13978            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
13979        }
13980    }
13981
13982    pub fn context_menu_prev(
13983        &mut self,
13984        _: &ContextMenuPrevious,
13985        window: &mut Window,
13986        cx: &mut Context<Self>,
13987    ) {
13988        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
13989            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
13990        }
13991    }
13992
13993    pub fn context_menu_next(
13994        &mut self,
13995        _: &ContextMenuNext,
13996        window: &mut Window,
13997        cx: &mut Context<Self>,
13998    ) {
13999        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14000            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
14001        }
14002    }
14003
14004    pub fn context_menu_last(
14005        &mut self,
14006        _: &ContextMenuLast,
14007        window: &mut Window,
14008        cx: &mut Context<Self>,
14009    ) {
14010        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14011            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
14012        }
14013    }
14014
14015    pub fn signature_help_prev(
14016        &mut self,
14017        _: &SignatureHelpPrevious,
14018        _: &mut Window,
14019        cx: &mut Context<Self>,
14020    ) {
14021        if let Some(popover) = self.signature_help_state.popover_mut() {
14022            if popover.current_signature == 0 {
14023                popover.current_signature = popover.signatures.len() - 1;
14024            } else {
14025                popover.current_signature -= 1;
14026            }
14027            cx.notify();
14028        }
14029    }
14030
14031    pub fn signature_help_next(
14032        &mut self,
14033        _: &SignatureHelpNext,
14034        _: &mut Window,
14035        cx: &mut Context<Self>,
14036    ) {
14037        if let Some(popover) = self.signature_help_state.popover_mut() {
14038            if popover.current_signature + 1 == popover.signatures.len() {
14039                popover.current_signature = 0;
14040            } else {
14041                popover.current_signature += 1;
14042            }
14043            cx.notify();
14044        }
14045    }
14046
14047    pub fn move_to_previous_word_start(
14048        &mut self,
14049        _: &MoveToPreviousWordStart,
14050        window: &mut Window,
14051        cx: &mut Context<Self>,
14052    ) {
14053        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14054        self.change_selections(Default::default(), window, cx, |s| {
14055            s.move_cursors_with(|map, head, _| {
14056                (
14057                    movement::previous_word_start(map, head),
14058                    SelectionGoal::None,
14059                )
14060            });
14061        })
14062    }
14063
14064    pub fn move_to_previous_subword_start(
14065        &mut self,
14066        _: &MoveToPreviousSubwordStart,
14067        window: &mut Window,
14068        cx: &mut Context<Self>,
14069    ) {
14070        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14071        self.change_selections(Default::default(), window, cx, |s| {
14072            s.move_cursors_with(|map, head, _| {
14073                (
14074                    movement::previous_subword_start(map, head),
14075                    SelectionGoal::None,
14076                )
14077            });
14078        })
14079    }
14080
14081    pub fn select_to_previous_word_start(
14082        &mut self,
14083        _: &SelectToPreviousWordStart,
14084        window: &mut Window,
14085        cx: &mut Context<Self>,
14086    ) {
14087        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14088        self.change_selections(Default::default(), window, cx, |s| {
14089            s.move_heads_with(|map, head, _| {
14090                (
14091                    movement::previous_word_start(map, head),
14092                    SelectionGoal::None,
14093                )
14094            });
14095        })
14096    }
14097
14098    pub fn select_to_previous_subword_start(
14099        &mut self,
14100        _: &SelectToPreviousSubwordStart,
14101        window: &mut Window,
14102        cx: &mut Context<Self>,
14103    ) {
14104        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14105        self.change_selections(Default::default(), window, cx, |s| {
14106            s.move_heads_with(|map, head, _| {
14107                (
14108                    movement::previous_subword_start(map, head),
14109                    SelectionGoal::None,
14110                )
14111            });
14112        })
14113    }
14114
14115    pub fn delete_to_previous_word_start(
14116        &mut self,
14117        action: &DeleteToPreviousWordStart,
14118        window: &mut Window,
14119        cx: &mut Context<Self>,
14120    ) {
14121        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14122        self.transact(window, cx, |this, window, cx| {
14123            this.select_autoclose_pair(window, cx);
14124            this.change_selections(Default::default(), window, cx, |s| {
14125                s.move_with(|map, selection| {
14126                    if selection.is_empty() {
14127                        let mut cursor = if action.ignore_newlines {
14128                            movement::previous_word_start(map, selection.head())
14129                        } else {
14130                            movement::previous_word_start_or_newline(map, selection.head())
14131                        };
14132                        cursor = movement::adjust_greedy_deletion(
14133                            map,
14134                            selection.head(),
14135                            cursor,
14136                            action.ignore_brackets,
14137                        );
14138                        selection.set_head(cursor, SelectionGoal::None);
14139                    }
14140                });
14141            });
14142            this.insert("", window, cx);
14143        });
14144    }
14145
14146    pub fn delete_to_previous_subword_start(
14147        &mut self,
14148        _: &DeleteToPreviousSubwordStart,
14149        window: &mut Window,
14150        cx: &mut Context<Self>,
14151    ) {
14152        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14153        self.transact(window, cx, |this, window, cx| {
14154            this.select_autoclose_pair(window, cx);
14155            this.change_selections(Default::default(), window, cx, |s| {
14156                s.move_with(|map, selection| {
14157                    if selection.is_empty() {
14158                        let mut cursor = movement::previous_subword_start(map, selection.head());
14159                        cursor =
14160                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
14161                        selection.set_head(cursor, SelectionGoal::None);
14162                    }
14163                });
14164            });
14165            this.insert("", window, cx);
14166        });
14167    }
14168
14169    pub fn move_to_next_word_end(
14170        &mut self,
14171        _: &MoveToNextWordEnd,
14172        window: &mut Window,
14173        cx: &mut Context<Self>,
14174    ) {
14175        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14176        self.change_selections(Default::default(), window, cx, |s| {
14177            s.move_cursors_with(|map, head, _| {
14178                (movement::next_word_end(map, head), SelectionGoal::None)
14179            });
14180        })
14181    }
14182
14183    pub fn move_to_next_subword_end(
14184        &mut self,
14185        _: &MoveToNextSubwordEnd,
14186        window: &mut Window,
14187        cx: &mut Context<Self>,
14188    ) {
14189        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14190        self.change_selections(Default::default(), window, cx, |s| {
14191            s.move_cursors_with(|map, head, _| {
14192                (movement::next_subword_end(map, head), SelectionGoal::None)
14193            });
14194        })
14195    }
14196
14197    pub fn select_to_next_word_end(
14198        &mut self,
14199        _: &SelectToNextWordEnd,
14200        window: &mut Window,
14201        cx: &mut Context<Self>,
14202    ) {
14203        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14204        self.change_selections(Default::default(), window, cx, |s| {
14205            s.move_heads_with(|map, head, _| {
14206                (movement::next_word_end(map, head), SelectionGoal::None)
14207            });
14208        })
14209    }
14210
14211    pub fn select_to_next_subword_end(
14212        &mut self,
14213        _: &SelectToNextSubwordEnd,
14214        window: &mut Window,
14215        cx: &mut Context<Self>,
14216    ) {
14217        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14218        self.change_selections(Default::default(), window, cx, |s| {
14219            s.move_heads_with(|map, head, _| {
14220                (movement::next_subword_end(map, head), SelectionGoal::None)
14221            });
14222        })
14223    }
14224
14225    pub fn delete_to_next_word_end(
14226        &mut self,
14227        action: &DeleteToNextWordEnd,
14228        window: &mut Window,
14229        cx: &mut Context<Self>,
14230    ) {
14231        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14232        self.transact(window, cx, |this, window, cx| {
14233            this.change_selections(Default::default(), window, cx, |s| {
14234                s.move_with(|map, selection| {
14235                    if selection.is_empty() {
14236                        let mut cursor = if action.ignore_newlines {
14237                            movement::next_word_end(map, selection.head())
14238                        } else {
14239                            movement::next_word_end_or_newline(map, selection.head())
14240                        };
14241                        cursor = movement::adjust_greedy_deletion(
14242                            map,
14243                            selection.head(),
14244                            cursor,
14245                            action.ignore_brackets,
14246                        );
14247                        selection.set_head(cursor, SelectionGoal::None);
14248                    }
14249                });
14250            });
14251            this.insert("", window, cx);
14252        });
14253    }
14254
14255    pub fn delete_to_next_subword_end(
14256        &mut self,
14257        _: &DeleteToNextSubwordEnd,
14258        window: &mut Window,
14259        cx: &mut Context<Self>,
14260    ) {
14261        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14262        self.transact(window, cx, |this, window, cx| {
14263            this.change_selections(Default::default(), window, cx, |s| {
14264                s.move_with(|map, selection| {
14265                    if selection.is_empty() {
14266                        let mut cursor = movement::next_subword_end(map, selection.head());
14267                        cursor =
14268                            movement::adjust_greedy_deletion(map, selection.head(), cursor, false);
14269                        selection.set_head(cursor, SelectionGoal::None);
14270                    }
14271                });
14272            });
14273            this.insert("", window, cx);
14274        });
14275    }
14276
14277    pub fn move_to_beginning_of_line(
14278        &mut self,
14279        action: &MoveToBeginningOfLine,
14280        window: &mut Window,
14281        cx: &mut Context<Self>,
14282    ) {
14283        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14284        self.change_selections(Default::default(), window, cx, |s| {
14285            s.move_cursors_with(|map, head, _| {
14286                (
14287                    movement::indented_line_beginning(
14288                        map,
14289                        head,
14290                        action.stop_at_soft_wraps,
14291                        action.stop_at_indent,
14292                    ),
14293                    SelectionGoal::None,
14294                )
14295            });
14296        })
14297    }
14298
14299    pub fn select_to_beginning_of_line(
14300        &mut self,
14301        action: &SelectToBeginningOfLine,
14302        window: &mut Window,
14303        cx: &mut Context<Self>,
14304    ) {
14305        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14306        self.change_selections(Default::default(), window, cx, |s| {
14307            s.move_heads_with(|map, head, _| {
14308                (
14309                    movement::indented_line_beginning(
14310                        map,
14311                        head,
14312                        action.stop_at_soft_wraps,
14313                        action.stop_at_indent,
14314                    ),
14315                    SelectionGoal::None,
14316                )
14317            });
14318        });
14319    }
14320
14321    pub fn delete_to_beginning_of_line(
14322        &mut self,
14323        action: &DeleteToBeginningOfLine,
14324        window: &mut Window,
14325        cx: &mut Context<Self>,
14326    ) {
14327        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14328        self.transact(window, cx, |this, window, cx| {
14329            this.change_selections(Default::default(), window, cx, |s| {
14330                s.move_with(|_, selection| {
14331                    selection.reversed = true;
14332                });
14333            });
14334
14335            this.select_to_beginning_of_line(
14336                &SelectToBeginningOfLine {
14337                    stop_at_soft_wraps: false,
14338                    stop_at_indent: action.stop_at_indent,
14339                },
14340                window,
14341                cx,
14342            );
14343            this.backspace(&Backspace, window, cx);
14344        });
14345    }
14346
14347    pub fn move_to_end_of_line(
14348        &mut self,
14349        action: &MoveToEndOfLine,
14350        window: &mut Window,
14351        cx: &mut Context<Self>,
14352    ) {
14353        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14354        self.change_selections(Default::default(), window, cx, |s| {
14355            s.move_cursors_with(|map, head, _| {
14356                (
14357                    movement::line_end(map, head, action.stop_at_soft_wraps),
14358                    SelectionGoal::None,
14359                )
14360            });
14361        })
14362    }
14363
14364    pub fn select_to_end_of_line(
14365        &mut self,
14366        action: &SelectToEndOfLine,
14367        window: &mut Window,
14368        cx: &mut Context<Self>,
14369    ) {
14370        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14371        self.change_selections(Default::default(), window, cx, |s| {
14372            s.move_heads_with(|map, head, _| {
14373                (
14374                    movement::line_end(map, head, action.stop_at_soft_wraps),
14375                    SelectionGoal::None,
14376                )
14377            });
14378        })
14379    }
14380
14381    pub fn delete_to_end_of_line(
14382        &mut self,
14383        _: &DeleteToEndOfLine,
14384        window: &mut Window,
14385        cx: &mut Context<Self>,
14386    ) {
14387        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14388        self.transact(window, cx, |this, window, cx| {
14389            this.select_to_end_of_line(
14390                &SelectToEndOfLine {
14391                    stop_at_soft_wraps: false,
14392                },
14393                window,
14394                cx,
14395            );
14396            this.delete(&Delete, window, cx);
14397        });
14398    }
14399
14400    pub fn cut_to_end_of_line(
14401        &mut self,
14402        action: &CutToEndOfLine,
14403        window: &mut Window,
14404        cx: &mut Context<Self>,
14405    ) {
14406        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14407        self.transact(window, cx, |this, window, cx| {
14408            this.select_to_end_of_line(
14409                &SelectToEndOfLine {
14410                    stop_at_soft_wraps: false,
14411                },
14412                window,
14413                cx,
14414            );
14415            if !action.stop_at_newlines {
14416                this.change_selections(Default::default(), window, cx, |s| {
14417                    s.move_with(|_, sel| {
14418                        if sel.is_empty() {
14419                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
14420                        }
14421                    });
14422                });
14423            }
14424            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14425            let item = this.cut_common(false, window, cx);
14426            cx.write_to_clipboard(item);
14427        });
14428    }
14429
14430    pub fn move_to_start_of_paragraph(
14431        &mut self,
14432        _: &MoveToStartOfParagraph,
14433        window: &mut Window,
14434        cx: &mut Context<Self>,
14435    ) {
14436        if matches!(self.mode, EditorMode::SingleLine) {
14437            cx.propagate();
14438            return;
14439        }
14440        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14441        self.change_selections(Default::default(), window, cx, |s| {
14442            s.move_with(|map, selection| {
14443                selection.collapse_to(
14444                    movement::start_of_paragraph(map, selection.head(), 1),
14445                    SelectionGoal::None,
14446                )
14447            });
14448        })
14449    }
14450
14451    pub fn move_to_end_of_paragraph(
14452        &mut self,
14453        _: &MoveToEndOfParagraph,
14454        window: &mut Window,
14455        cx: &mut Context<Self>,
14456    ) {
14457        if matches!(self.mode, EditorMode::SingleLine) {
14458            cx.propagate();
14459            return;
14460        }
14461        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14462        self.change_selections(Default::default(), window, cx, |s| {
14463            s.move_with(|map, selection| {
14464                selection.collapse_to(
14465                    movement::end_of_paragraph(map, selection.head(), 1),
14466                    SelectionGoal::None,
14467                )
14468            });
14469        })
14470    }
14471
14472    pub fn select_to_start_of_paragraph(
14473        &mut self,
14474        _: &SelectToStartOfParagraph,
14475        window: &mut Window,
14476        cx: &mut Context<Self>,
14477    ) {
14478        if matches!(self.mode, EditorMode::SingleLine) {
14479            cx.propagate();
14480            return;
14481        }
14482        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14483        self.change_selections(Default::default(), window, cx, |s| {
14484            s.move_heads_with(|map, head, _| {
14485                (
14486                    movement::start_of_paragraph(map, head, 1),
14487                    SelectionGoal::None,
14488                )
14489            });
14490        })
14491    }
14492
14493    pub fn select_to_end_of_paragraph(
14494        &mut self,
14495        _: &SelectToEndOfParagraph,
14496        window: &mut Window,
14497        cx: &mut Context<Self>,
14498    ) {
14499        if matches!(self.mode, EditorMode::SingleLine) {
14500            cx.propagate();
14501            return;
14502        }
14503        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14504        self.change_selections(Default::default(), window, cx, |s| {
14505            s.move_heads_with(|map, head, _| {
14506                (
14507                    movement::end_of_paragraph(map, head, 1),
14508                    SelectionGoal::None,
14509                )
14510            });
14511        })
14512    }
14513
14514    pub fn move_to_start_of_excerpt(
14515        &mut self,
14516        _: &MoveToStartOfExcerpt,
14517        window: &mut Window,
14518        cx: &mut Context<Self>,
14519    ) {
14520        if matches!(self.mode, EditorMode::SingleLine) {
14521            cx.propagate();
14522            return;
14523        }
14524        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14525        self.change_selections(Default::default(), window, cx, |s| {
14526            s.move_with(|map, selection| {
14527                selection.collapse_to(
14528                    movement::start_of_excerpt(
14529                        map,
14530                        selection.head(),
14531                        workspace::searchable::Direction::Prev,
14532                    ),
14533                    SelectionGoal::None,
14534                )
14535            });
14536        })
14537    }
14538
14539    pub fn move_to_start_of_next_excerpt(
14540        &mut self,
14541        _: &MoveToStartOfNextExcerpt,
14542        window: &mut Window,
14543        cx: &mut Context<Self>,
14544    ) {
14545        if matches!(self.mode, EditorMode::SingleLine) {
14546            cx.propagate();
14547            return;
14548        }
14549
14550        self.change_selections(Default::default(), window, cx, |s| {
14551            s.move_with(|map, selection| {
14552                selection.collapse_to(
14553                    movement::start_of_excerpt(
14554                        map,
14555                        selection.head(),
14556                        workspace::searchable::Direction::Next,
14557                    ),
14558                    SelectionGoal::None,
14559                )
14560            });
14561        })
14562    }
14563
14564    pub fn move_to_end_of_excerpt(
14565        &mut self,
14566        _: &MoveToEndOfExcerpt,
14567        window: &mut Window,
14568        cx: &mut Context<Self>,
14569    ) {
14570        if matches!(self.mode, EditorMode::SingleLine) {
14571            cx.propagate();
14572            return;
14573        }
14574        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14575        self.change_selections(Default::default(), window, cx, |s| {
14576            s.move_with(|map, selection| {
14577                selection.collapse_to(
14578                    movement::end_of_excerpt(
14579                        map,
14580                        selection.head(),
14581                        workspace::searchable::Direction::Next,
14582                    ),
14583                    SelectionGoal::None,
14584                )
14585            });
14586        })
14587    }
14588
14589    pub fn move_to_end_of_previous_excerpt(
14590        &mut self,
14591        _: &MoveToEndOfPreviousExcerpt,
14592        window: &mut Window,
14593        cx: &mut Context<Self>,
14594    ) {
14595        if matches!(self.mode, EditorMode::SingleLine) {
14596            cx.propagate();
14597            return;
14598        }
14599        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14600        self.change_selections(Default::default(), window, cx, |s| {
14601            s.move_with(|map, selection| {
14602                selection.collapse_to(
14603                    movement::end_of_excerpt(
14604                        map,
14605                        selection.head(),
14606                        workspace::searchable::Direction::Prev,
14607                    ),
14608                    SelectionGoal::None,
14609                )
14610            });
14611        })
14612    }
14613
14614    pub fn select_to_start_of_excerpt(
14615        &mut self,
14616        _: &SelectToStartOfExcerpt,
14617        window: &mut Window,
14618        cx: &mut Context<Self>,
14619    ) {
14620        if matches!(self.mode, EditorMode::SingleLine) {
14621            cx.propagate();
14622            return;
14623        }
14624        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14625        self.change_selections(Default::default(), window, cx, |s| {
14626            s.move_heads_with(|map, head, _| {
14627                (
14628                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14629                    SelectionGoal::None,
14630                )
14631            });
14632        })
14633    }
14634
14635    pub fn select_to_start_of_next_excerpt(
14636        &mut self,
14637        _: &SelectToStartOfNextExcerpt,
14638        window: &mut Window,
14639        cx: &mut Context<Self>,
14640    ) {
14641        if matches!(self.mode, EditorMode::SingleLine) {
14642            cx.propagate();
14643            return;
14644        }
14645        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14646        self.change_selections(Default::default(), window, cx, |s| {
14647            s.move_heads_with(|map, head, _| {
14648                (
14649                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
14650                    SelectionGoal::None,
14651                )
14652            });
14653        })
14654    }
14655
14656    pub fn select_to_end_of_excerpt(
14657        &mut self,
14658        _: &SelectToEndOfExcerpt,
14659        window: &mut Window,
14660        cx: &mut Context<Self>,
14661    ) {
14662        if matches!(self.mode, EditorMode::SingleLine) {
14663            cx.propagate();
14664            return;
14665        }
14666        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14667        self.change_selections(Default::default(), window, cx, |s| {
14668            s.move_heads_with(|map, head, _| {
14669                (
14670                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
14671                    SelectionGoal::None,
14672                )
14673            });
14674        })
14675    }
14676
14677    pub fn select_to_end_of_previous_excerpt(
14678        &mut self,
14679        _: &SelectToEndOfPreviousExcerpt,
14680        window: &mut Window,
14681        cx: &mut Context<Self>,
14682    ) {
14683        if matches!(self.mode, EditorMode::SingleLine) {
14684            cx.propagate();
14685            return;
14686        }
14687        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14688        self.change_selections(Default::default(), window, cx, |s| {
14689            s.move_heads_with(|map, head, _| {
14690                (
14691                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
14692                    SelectionGoal::None,
14693                )
14694            });
14695        })
14696    }
14697
14698    pub fn move_to_beginning(
14699        &mut self,
14700        _: &MoveToBeginning,
14701        window: &mut Window,
14702        cx: &mut Context<Self>,
14703    ) {
14704        if matches!(self.mode, EditorMode::SingleLine) {
14705            cx.propagate();
14706            return;
14707        }
14708        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14709        self.change_selections(Default::default(), window, cx, |s| {
14710            s.select_ranges(vec![Anchor::min()..Anchor::min()]);
14711        });
14712    }
14713
14714    pub fn select_to_beginning(
14715        &mut self,
14716        _: &SelectToBeginning,
14717        window: &mut Window,
14718        cx: &mut Context<Self>,
14719    ) {
14720        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
14721        selection.set_head(Point::zero(), SelectionGoal::None);
14722        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14723        self.change_selections(Default::default(), window, cx, |s| {
14724            s.select(vec![selection]);
14725        });
14726    }
14727
14728    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
14729        if matches!(self.mode, EditorMode::SingleLine) {
14730            cx.propagate();
14731            return;
14732        }
14733        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14734        let cursor = self.buffer.read(cx).read(cx).len();
14735        self.change_selections(Default::default(), window, cx, |s| {
14736            s.select_ranges(vec![cursor..cursor])
14737        });
14738    }
14739
14740    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
14741        self.nav_history = nav_history;
14742    }
14743
14744    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
14745        self.nav_history.as_ref()
14746    }
14747
14748    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
14749        self.push_to_nav_history(
14750            self.selections.newest_anchor().head(),
14751            None,
14752            false,
14753            true,
14754            cx,
14755        );
14756    }
14757
14758    fn push_to_nav_history(
14759        &mut self,
14760        cursor_anchor: Anchor,
14761        new_position: Option<Point>,
14762        is_deactivate: bool,
14763        always: bool,
14764        cx: &mut Context<Self>,
14765    ) {
14766        if let Some(nav_history) = self.nav_history.as_mut() {
14767            let buffer = self.buffer.read(cx).read(cx);
14768            let cursor_position = cursor_anchor.to_point(&buffer);
14769            let scroll_state = self.scroll_manager.anchor();
14770            let scroll_top_row = scroll_state.top_row(&buffer);
14771            drop(buffer);
14772
14773            if let Some(new_position) = new_position {
14774                let row_delta = (new_position.row as i64 - cursor_position.row as i64).abs();
14775                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
14776                    return;
14777                }
14778            }
14779
14780            nav_history.push(
14781                Some(NavigationData {
14782                    cursor_anchor,
14783                    cursor_position,
14784                    scroll_anchor: scroll_state,
14785                    scroll_top_row,
14786                }),
14787                cx,
14788            );
14789            cx.emit(EditorEvent::PushedToNavHistory {
14790                anchor: cursor_anchor,
14791                is_deactivate,
14792            })
14793        }
14794    }
14795
14796    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
14797        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14798        let buffer = self.buffer.read(cx).snapshot(cx);
14799        let mut selection = self
14800            .selections
14801            .first::<MultiBufferOffset>(&self.display_snapshot(cx));
14802        selection.set_head(buffer.len(), SelectionGoal::None);
14803        self.change_selections(Default::default(), window, cx, |s| {
14804            s.select(vec![selection]);
14805        });
14806    }
14807
14808    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
14809        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14810        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14811            s.select_ranges(vec![Anchor::min()..Anchor::max()]);
14812        });
14813    }
14814
14815    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
14816        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14817        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14818        let mut selections = self.selections.all::<Point>(&display_map);
14819        let max_point = display_map.buffer_snapshot().max_point();
14820        for selection in &mut selections {
14821            let rows = selection.spanned_rows(true, &display_map);
14822            selection.start = Point::new(rows.start.0, 0);
14823            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
14824            selection.reversed = false;
14825        }
14826        self.change_selections(Default::default(), window, cx, |s| {
14827            s.select(selections);
14828        });
14829    }
14830
14831    pub fn split_selection_into_lines(
14832        &mut self,
14833        action: &SplitSelectionIntoLines,
14834        window: &mut Window,
14835        cx: &mut Context<Self>,
14836    ) {
14837        let selections = self
14838            .selections
14839            .all::<Point>(&self.display_snapshot(cx))
14840            .into_iter()
14841            .map(|selection| selection.start..selection.end)
14842            .collect::<Vec<_>>();
14843        self.unfold_ranges(&selections, true, true, cx);
14844
14845        let mut new_selection_ranges = Vec::new();
14846        {
14847            let buffer = self.buffer.read(cx).read(cx);
14848            for selection in selections {
14849                for row in selection.start.row..selection.end.row {
14850                    let line_start = Point::new(row, 0);
14851                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
14852
14853                    if action.keep_selections {
14854                        // Keep the selection range for each line
14855                        let selection_start = if row == selection.start.row {
14856                            selection.start
14857                        } else {
14858                            line_start
14859                        };
14860                        new_selection_ranges.push(selection_start..line_end);
14861                    } else {
14862                        // Collapse to cursor at end of line
14863                        new_selection_ranges.push(line_end..line_end);
14864                    }
14865                }
14866
14867                let is_multiline_selection = selection.start.row != selection.end.row;
14868                // Don't insert last one if it's a multi-line selection ending at the start of a line,
14869                // so this action feels more ergonomic when paired with other selection operations
14870                let should_skip_last = is_multiline_selection && selection.end.column == 0;
14871                if !should_skip_last {
14872                    if action.keep_selections {
14873                        if is_multiline_selection {
14874                            let line_start = Point::new(selection.end.row, 0);
14875                            new_selection_ranges.push(line_start..selection.end);
14876                        } else {
14877                            new_selection_ranges.push(selection.start..selection.end);
14878                        }
14879                    } else {
14880                        new_selection_ranges.push(selection.end..selection.end);
14881                    }
14882                }
14883            }
14884        }
14885        self.change_selections(Default::default(), window, cx, |s| {
14886            s.select_ranges(new_selection_ranges);
14887        });
14888    }
14889
14890    pub fn add_selection_above(
14891        &mut self,
14892        action: &AddSelectionAbove,
14893        window: &mut Window,
14894        cx: &mut Context<Self>,
14895    ) {
14896        self.add_selection(true, action.skip_soft_wrap, window, cx);
14897    }
14898
14899    pub fn add_selection_below(
14900        &mut self,
14901        action: &AddSelectionBelow,
14902        window: &mut Window,
14903        cx: &mut Context<Self>,
14904    ) {
14905        self.add_selection(false, action.skip_soft_wrap, window, cx);
14906    }
14907
14908    fn add_selection(
14909        &mut self,
14910        above: bool,
14911        skip_soft_wrap: bool,
14912        window: &mut Window,
14913        cx: &mut Context<Self>,
14914    ) {
14915        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14916
14917        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
14918        let all_selections = self.selections.all::<Point>(&display_map);
14919        let text_layout_details = self.text_layout_details(window);
14920
14921        let (mut columnar_selections, new_selections_to_columnarize) = {
14922            if let Some(state) = self.add_selections_state.as_ref() {
14923                let columnar_selection_ids: HashSet<_> = state
14924                    .groups
14925                    .iter()
14926                    .flat_map(|group| group.stack.iter())
14927                    .copied()
14928                    .collect();
14929
14930                all_selections
14931                    .into_iter()
14932                    .partition(|s| columnar_selection_ids.contains(&s.id))
14933            } else {
14934                (Vec::new(), all_selections)
14935            }
14936        };
14937
14938        let mut state = self
14939            .add_selections_state
14940            .take()
14941            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
14942
14943        for selection in new_selections_to_columnarize {
14944            let range = selection.display_range(&display_map).sorted();
14945            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
14946            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
14947            let positions = start_x.min(end_x)..start_x.max(end_x);
14948            let mut stack = Vec::new();
14949            for row in range.start.row().0..=range.end.row().0 {
14950                if let Some(selection) = self.selections.build_columnar_selection(
14951                    &display_map,
14952                    DisplayRow(row),
14953                    &positions,
14954                    selection.reversed,
14955                    &text_layout_details,
14956                ) {
14957                    stack.push(selection.id);
14958                    columnar_selections.push(selection);
14959                }
14960            }
14961            if !stack.is_empty() {
14962                if above {
14963                    stack.reverse();
14964                }
14965                state.groups.push(AddSelectionsGroup { above, stack });
14966            }
14967        }
14968
14969        let mut final_selections = Vec::new();
14970        let end_row = if above {
14971            DisplayRow(0)
14972        } else {
14973            display_map.max_point().row()
14974        };
14975
14976        let mut last_added_item_per_group = HashMap::default();
14977        for group in state.groups.iter_mut() {
14978            if let Some(last_id) = group.stack.last() {
14979                last_added_item_per_group.insert(*last_id, group);
14980            }
14981        }
14982
14983        for selection in columnar_selections {
14984            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
14985                if above == group.above {
14986                    let range = selection.display_range(&display_map).sorted();
14987                    debug_assert_eq!(range.start.row(), range.end.row());
14988                    let mut row = range.start.row();
14989                    let positions =
14990                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
14991                            Pixels::from(start)..Pixels::from(end)
14992                        } else {
14993                            let start_x =
14994                                display_map.x_for_display_point(range.start, &text_layout_details);
14995                            let end_x =
14996                                display_map.x_for_display_point(range.end, &text_layout_details);
14997                            start_x.min(end_x)..start_x.max(end_x)
14998                        };
14999
15000                    let mut maybe_new_selection = None;
15001                    let direction = if above { -1 } else { 1 };
15002
15003                    while row != end_row {
15004                        if skip_soft_wrap {
15005                            row = display_map
15006                                .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction)
15007                                .row();
15008                        } else if above {
15009                            row.0 -= 1;
15010                        } else {
15011                            row.0 += 1;
15012                        }
15013
15014                        if let Some(new_selection) = self.selections.build_columnar_selection(
15015                            &display_map,
15016                            row,
15017                            &positions,
15018                            selection.reversed,
15019                            &text_layout_details,
15020                        ) {
15021                            maybe_new_selection = Some(new_selection);
15022                            break;
15023                        }
15024                    }
15025
15026                    if let Some(new_selection) = maybe_new_selection {
15027                        group.stack.push(new_selection.id);
15028                        if above {
15029                            final_selections.push(new_selection);
15030                            final_selections.push(selection);
15031                        } else {
15032                            final_selections.push(selection);
15033                            final_selections.push(new_selection);
15034                        }
15035                    } else {
15036                        final_selections.push(selection);
15037                    }
15038                } else {
15039                    group.stack.pop();
15040                }
15041            } else {
15042                final_selections.push(selection);
15043            }
15044        }
15045
15046        self.change_selections(Default::default(), window, cx, |s| {
15047            s.select(final_selections);
15048        });
15049
15050        let final_selection_ids: HashSet<_> = self
15051            .selections
15052            .all::<Point>(&display_map)
15053            .iter()
15054            .map(|s| s.id)
15055            .collect();
15056        state.groups.retain_mut(|group| {
15057            // selections might get merged above so we remove invalid items from stacks
15058            group.stack.retain(|id| final_selection_ids.contains(id));
15059
15060            // single selection in stack can be treated as initial state
15061            group.stack.len() > 1
15062        });
15063
15064        if !state.groups.is_empty() {
15065            self.add_selections_state = Some(state);
15066        }
15067    }
15068
15069    pub fn insert_snippet_at_selections(
15070        &mut self,
15071        action: &InsertSnippet,
15072        window: &mut Window,
15073        cx: &mut Context<Self>,
15074    ) {
15075        self.try_insert_snippet_at_selections(action, window, cx)
15076            .log_err();
15077    }
15078
15079    fn try_insert_snippet_at_selections(
15080        &mut self,
15081        action: &InsertSnippet,
15082        window: &mut Window,
15083        cx: &mut Context<Self>,
15084    ) -> Result<()> {
15085        let insertion_ranges = self
15086            .selections
15087            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15088            .into_iter()
15089            .map(|selection| selection.range())
15090            .collect_vec();
15091
15092        let snippet = if let Some(snippet_body) = &action.snippet {
15093            if action.language.is_none() && action.name.is_none() {
15094                Snippet::parse(snippet_body)?
15095            } else {
15096                bail!("`snippet` is mutually exclusive with `language` and `name`")
15097            }
15098        } else if let Some(name) = &action.name {
15099            let project = self.project().context("no project")?;
15100            let snippet_store = project.read(cx).snippets().read(cx);
15101            let snippet = snippet_store
15102                .snippets_for(action.language.clone(), cx)
15103                .into_iter()
15104                .find(|snippet| snippet.name == *name)
15105                .context("snippet not found")?;
15106            Snippet::parse(&snippet.body)?
15107        } else {
15108            // todo(andrew): open modal to select snippet
15109            bail!("`name` or `snippet` is required")
15110        };
15111
15112        self.insert_snippet(&insertion_ranges, snippet, window, cx)
15113    }
15114
15115    fn select_match_ranges(
15116        &mut self,
15117        range: Range<MultiBufferOffset>,
15118        reversed: bool,
15119        replace_newest: bool,
15120        auto_scroll: Option<Autoscroll>,
15121        window: &mut Window,
15122        cx: &mut Context<Editor>,
15123    ) {
15124        self.unfold_ranges(
15125            std::slice::from_ref(&range),
15126            false,
15127            auto_scroll.is_some(),
15128            cx,
15129        );
15130        let effects = if let Some(scroll) = auto_scroll {
15131            SelectionEffects::scroll(scroll)
15132        } else {
15133            SelectionEffects::no_scroll()
15134        };
15135        self.change_selections(effects, window, cx, |s| {
15136            if replace_newest {
15137                s.delete(s.newest_anchor().id);
15138            }
15139            if reversed {
15140                s.insert_range(range.end..range.start);
15141            } else {
15142                s.insert_range(range);
15143            }
15144        });
15145    }
15146
15147    pub fn select_next_match_internal(
15148        &mut self,
15149        display_map: &DisplaySnapshot,
15150        replace_newest: bool,
15151        autoscroll: Option<Autoscroll>,
15152        window: &mut Window,
15153        cx: &mut Context<Self>,
15154    ) -> Result<()> {
15155        let buffer = display_map.buffer_snapshot();
15156        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15157        if let Some(mut select_next_state) = self.select_next_state.take() {
15158            let query = &select_next_state.query;
15159            if !select_next_state.done {
15160                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15161                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15162                let mut next_selected_range = None;
15163
15164                let bytes_after_last_selection =
15165                    buffer.bytes_in_range(last_selection.end..buffer.len());
15166                let bytes_before_first_selection =
15167                    buffer.bytes_in_range(MultiBufferOffset(0)..first_selection.start);
15168                let query_matches = query
15169                    .stream_find_iter(bytes_after_last_selection)
15170                    .map(|result| (last_selection.end, result))
15171                    .chain(
15172                        query
15173                            .stream_find_iter(bytes_before_first_selection)
15174                            .map(|result| (MultiBufferOffset(0), result)),
15175                    );
15176
15177                for (start_offset, query_match) in query_matches {
15178                    let query_match = query_match.unwrap(); // can only fail due to I/O
15179                    let offset_range =
15180                        start_offset + query_match.start()..start_offset + query_match.end();
15181
15182                    if !select_next_state.wordwise
15183                        || (!buffer.is_inside_word(offset_range.start, None)
15184                            && !buffer.is_inside_word(offset_range.end, None))
15185                    {
15186                        let idx = selections
15187                            .partition_point(|selection| selection.end <= offset_range.start);
15188                        let overlaps = selections
15189                            .get(idx)
15190                            .map_or(false, |selection| selection.start < offset_range.end);
15191
15192                        if !overlaps {
15193                            next_selected_range = Some(offset_range);
15194                            break;
15195                        }
15196                    }
15197                }
15198
15199                if let Some(next_selected_range) = next_selected_range {
15200                    self.select_match_ranges(
15201                        next_selected_range,
15202                        last_selection.reversed,
15203                        replace_newest,
15204                        autoscroll,
15205                        window,
15206                        cx,
15207                    );
15208                } else {
15209                    select_next_state.done = true;
15210                }
15211            }
15212
15213            self.select_next_state = Some(select_next_state);
15214        } else {
15215            let mut only_carets = true;
15216            let mut same_text_selected = true;
15217            let mut selected_text = None;
15218
15219            let mut selections_iter = selections.iter().peekable();
15220            while let Some(selection) = selections_iter.next() {
15221                if selection.start != selection.end {
15222                    only_carets = false;
15223                }
15224
15225                if same_text_selected {
15226                    if selected_text.is_none() {
15227                        selected_text =
15228                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15229                    }
15230
15231                    if let Some(next_selection) = selections_iter.peek() {
15232                        if next_selection.len() == selection.len() {
15233                            let next_selected_text = buffer
15234                                .text_for_range(next_selection.range())
15235                                .collect::<String>();
15236                            if Some(next_selected_text) != selected_text {
15237                                same_text_selected = false;
15238                                selected_text = None;
15239                            }
15240                        } else {
15241                            same_text_selected = false;
15242                            selected_text = None;
15243                        }
15244                    }
15245                }
15246            }
15247
15248            if only_carets {
15249                for selection in &mut selections {
15250                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15251                    selection.start = word_range.start;
15252                    selection.end = word_range.end;
15253                    selection.goal = SelectionGoal::None;
15254                    selection.reversed = false;
15255                    self.select_match_ranges(
15256                        selection.start..selection.end,
15257                        selection.reversed,
15258                        replace_newest,
15259                        autoscroll,
15260                        window,
15261                        cx,
15262                    );
15263                }
15264
15265                if selections.len() == 1 {
15266                    let selection = selections
15267                        .last()
15268                        .expect("ensured that there's only one selection");
15269                    let query = buffer
15270                        .text_for_range(selection.start..selection.end)
15271                        .collect::<String>();
15272                    let is_empty = query.is_empty();
15273                    let select_state = SelectNextState {
15274                        query: self.build_query(&[query], cx)?,
15275                        wordwise: true,
15276                        done: is_empty,
15277                    };
15278                    self.select_next_state = Some(select_state);
15279                } else {
15280                    self.select_next_state = None;
15281                }
15282            } else if let Some(selected_text) = selected_text {
15283                self.select_next_state = Some(SelectNextState {
15284                    query: self.build_query(&[selected_text], cx)?,
15285                    wordwise: false,
15286                    done: false,
15287                });
15288                self.select_next_match_internal(
15289                    display_map,
15290                    replace_newest,
15291                    autoscroll,
15292                    window,
15293                    cx,
15294                )?;
15295            }
15296        }
15297        Ok(())
15298    }
15299
15300    pub fn select_all_matches(
15301        &mut self,
15302        _action: &SelectAllMatches,
15303        window: &mut Window,
15304        cx: &mut Context<Self>,
15305    ) -> Result<()> {
15306        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15307
15308        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15309
15310        self.select_next_match_internal(&display_map, false, None, window, cx)?;
15311        let Some(select_next_state) = self.select_next_state.as_mut() else {
15312            return Ok(());
15313        };
15314        if select_next_state.done {
15315            return Ok(());
15316        }
15317
15318        let mut new_selections = Vec::new();
15319
15320        let reversed = self
15321            .selections
15322            .oldest::<MultiBufferOffset>(&display_map)
15323            .reversed;
15324        let buffer = display_map.buffer_snapshot();
15325        let query_matches = select_next_state
15326            .query
15327            .stream_find_iter(buffer.bytes_in_range(MultiBufferOffset(0)..buffer.len()));
15328
15329        for query_match in query_matches.into_iter() {
15330            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
15331            let offset_range = if reversed {
15332                MultiBufferOffset(query_match.end())..MultiBufferOffset(query_match.start())
15333            } else {
15334                MultiBufferOffset(query_match.start())..MultiBufferOffset(query_match.end())
15335            };
15336
15337            if !select_next_state.wordwise
15338                || (!buffer.is_inside_word(offset_range.start, None)
15339                    && !buffer.is_inside_word(offset_range.end, None))
15340            {
15341                new_selections.push(offset_range.start..offset_range.end);
15342            }
15343        }
15344
15345        select_next_state.done = true;
15346
15347        if new_selections.is_empty() {
15348            log::error!("bug: new_selections is empty in select_all_matches");
15349            return Ok(());
15350        }
15351
15352        self.unfold_ranges(&new_selections.clone(), false, false, cx);
15353        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
15354            selections.select_ranges(new_selections)
15355        });
15356
15357        Ok(())
15358    }
15359
15360    pub fn select_next(
15361        &mut self,
15362        action: &SelectNext,
15363        window: &mut Window,
15364        cx: &mut Context<Self>,
15365    ) -> Result<()> {
15366        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15367        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15368        self.select_next_match_internal(
15369            &display_map,
15370            action.replace_newest,
15371            Some(Autoscroll::newest()),
15372            window,
15373            cx,
15374        )?;
15375        Ok(())
15376    }
15377
15378    pub fn select_previous(
15379        &mut self,
15380        action: &SelectPrevious,
15381        window: &mut Window,
15382        cx: &mut Context<Self>,
15383    ) -> Result<()> {
15384        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15385        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15386        let buffer = display_map.buffer_snapshot();
15387        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15388        if let Some(mut select_prev_state) = self.select_prev_state.take() {
15389            let query = &select_prev_state.query;
15390            if !select_prev_state.done {
15391                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15392                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15393                let mut next_selected_range = None;
15394                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
15395                let bytes_before_last_selection =
15396                    buffer.reversed_bytes_in_range(MultiBufferOffset(0)..last_selection.start);
15397                let bytes_after_first_selection =
15398                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
15399                let query_matches = query
15400                    .stream_find_iter(bytes_before_last_selection)
15401                    .map(|result| (last_selection.start, result))
15402                    .chain(
15403                        query
15404                            .stream_find_iter(bytes_after_first_selection)
15405                            .map(|result| (buffer.len(), result)),
15406                    );
15407                for (end_offset, query_match) in query_matches {
15408                    let query_match = query_match.unwrap(); // can only fail due to I/O
15409                    let offset_range =
15410                        end_offset - query_match.end()..end_offset - query_match.start();
15411
15412                    if !select_prev_state.wordwise
15413                        || (!buffer.is_inside_word(offset_range.start, None)
15414                            && !buffer.is_inside_word(offset_range.end, None))
15415                    {
15416                        next_selected_range = Some(offset_range);
15417                        break;
15418                    }
15419                }
15420
15421                if let Some(next_selected_range) = next_selected_range {
15422                    self.select_match_ranges(
15423                        next_selected_range,
15424                        last_selection.reversed,
15425                        action.replace_newest,
15426                        Some(Autoscroll::newest()),
15427                        window,
15428                        cx,
15429                    );
15430                } else {
15431                    select_prev_state.done = true;
15432                }
15433            }
15434
15435            self.select_prev_state = Some(select_prev_state);
15436        } else {
15437            let mut only_carets = true;
15438            let mut same_text_selected = true;
15439            let mut selected_text = None;
15440
15441            let mut selections_iter = selections.iter().peekable();
15442            while let Some(selection) = selections_iter.next() {
15443                if selection.start != selection.end {
15444                    only_carets = false;
15445                }
15446
15447                if same_text_selected {
15448                    if selected_text.is_none() {
15449                        selected_text =
15450                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15451                    }
15452
15453                    if let Some(next_selection) = selections_iter.peek() {
15454                        if next_selection.len() == selection.len() {
15455                            let next_selected_text = buffer
15456                                .text_for_range(next_selection.range())
15457                                .collect::<String>();
15458                            if Some(next_selected_text) != selected_text {
15459                                same_text_selected = false;
15460                                selected_text = None;
15461                            }
15462                        } else {
15463                            same_text_selected = false;
15464                            selected_text = None;
15465                        }
15466                    }
15467                }
15468            }
15469
15470            if only_carets {
15471                for selection in &mut selections {
15472                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15473                    selection.start = word_range.start;
15474                    selection.end = word_range.end;
15475                    selection.goal = SelectionGoal::None;
15476                    selection.reversed = false;
15477                    self.select_match_ranges(
15478                        selection.start..selection.end,
15479                        selection.reversed,
15480                        action.replace_newest,
15481                        Some(Autoscroll::newest()),
15482                        window,
15483                        cx,
15484                    );
15485                }
15486                if selections.len() == 1 {
15487                    let selection = selections
15488                        .last()
15489                        .expect("ensured that there's only one selection");
15490                    let query = buffer
15491                        .text_for_range(selection.start..selection.end)
15492                        .collect::<String>();
15493                    let is_empty = query.is_empty();
15494                    let select_state = SelectNextState {
15495                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
15496                        wordwise: true,
15497                        done: is_empty,
15498                    };
15499                    self.select_prev_state = Some(select_state);
15500                } else {
15501                    self.select_prev_state = None;
15502                }
15503            } else if let Some(selected_text) = selected_text {
15504                self.select_prev_state = Some(SelectNextState {
15505                    query: self
15506                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
15507                    wordwise: false,
15508                    done: false,
15509                });
15510                self.select_previous(action, window, cx)?;
15511            }
15512        }
15513        Ok(())
15514    }
15515
15516    /// Builds an `AhoCorasick` automaton from the provided patterns, while
15517    /// setting the case sensitivity based on the global
15518    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
15519    /// editor's settings.
15520    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
15521    where
15522        I: IntoIterator<Item = P>,
15523        P: AsRef<[u8]>,
15524    {
15525        let case_sensitive = self.select_next_is_case_sensitive.map_or_else(
15526            || EditorSettings::get_global(cx).search.case_sensitive,
15527            |value| value,
15528        );
15529
15530        let mut builder = AhoCorasickBuilder::new();
15531        builder.ascii_case_insensitive(!case_sensitive);
15532        builder.build(patterns)
15533    }
15534
15535    pub fn find_next_match(
15536        &mut self,
15537        _: &FindNextMatch,
15538        window: &mut Window,
15539        cx: &mut Context<Self>,
15540    ) -> Result<()> {
15541        let selections = self.selections.disjoint_anchors_arc();
15542        match selections.first() {
15543            Some(first) if selections.len() >= 2 => {
15544                self.change_selections(Default::default(), window, cx, |s| {
15545                    s.select_ranges([first.range()]);
15546                });
15547            }
15548            _ => self.select_next(
15549                &SelectNext {
15550                    replace_newest: true,
15551                },
15552                window,
15553                cx,
15554            )?,
15555        }
15556        Ok(())
15557    }
15558
15559    pub fn find_previous_match(
15560        &mut self,
15561        _: &FindPreviousMatch,
15562        window: &mut Window,
15563        cx: &mut Context<Self>,
15564    ) -> Result<()> {
15565        let selections = self.selections.disjoint_anchors_arc();
15566        match selections.last() {
15567            Some(last) if selections.len() >= 2 => {
15568                self.change_selections(Default::default(), window, cx, |s| {
15569                    s.select_ranges([last.range()]);
15570                });
15571            }
15572            _ => self.select_previous(
15573                &SelectPrevious {
15574                    replace_newest: true,
15575                },
15576                window,
15577                cx,
15578            )?,
15579        }
15580        Ok(())
15581    }
15582
15583    pub fn toggle_comments(
15584        &mut self,
15585        action: &ToggleComments,
15586        window: &mut Window,
15587        cx: &mut Context<Self>,
15588    ) {
15589        if self.read_only(cx) {
15590            return;
15591        }
15592        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15593        let text_layout_details = &self.text_layout_details(window);
15594        self.transact(window, cx, |this, window, cx| {
15595            let mut selections = this
15596                .selections
15597                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
15598            let mut edits = Vec::new();
15599            let mut selection_edit_ranges = Vec::new();
15600            let mut last_toggled_row = None;
15601            let snapshot = this.buffer.read(cx).read(cx);
15602            let empty_str: Arc<str> = Arc::default();
15603            let mut suffixes_inserted = Vec::new();
15604            let ignore_indent = action.ignore_indent;
15605
15606            fn comment_prefix_range(
15607                snapshot: &MultiBufferSnapshot,
15608                row: MultiBufferRow,
15609                comment_prefix: &str,
15610                comment_prefix_whitespace: &str,
15611                ignore_indent: bool,
15612            ) -> Range<Point> {
15613                let indent_size = if ignore_indent {
15614                    0
15615                } else {
15616                    snapshot.indent_size_for_line(row).len
15617                };
15618
15619                let start = Point::new(row.0, indent_size);
15620
15621                let mut line_bytes = snapshot
15622                    .bytes_in_range(start..snapshot.max_point())
15623                    .flatten()
15624                    .copied();
15625
15626                // If this line currently begins with the line comment prefix, then record
15627                // the range containing the prefix.
15628                if line_bytes
15629                    .by_ref()
15630                    .take(comment_prefix.len())
15631                    .eq(comment_prefix.bytes())
15632                {
15633                    // Include any whitespace that matches the comment prefix.
15634                    let matching_whitespace_len = line_bytes
15635                        .zip(comment_prefix_whitespace.bytes())
15636                        .take_while(|(a, b)| a == b)
15637                        .count() as u32;
15638                    let end = Point::new(
15639                        start.row,
15640                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
15641                    );
15642                    start..end
15643                } else {
15644                    start..start
15645                }
15646            }
15647
15648            fn comment_suffix_range(
15649                snapshot: &MultiBufferSnapshot,
15650                row: MultiBufferRow,
15651                comment_suffix: &str,
15652                comment_suffix_has_leading_space: bool,
15653            ) -> Range<Point> {
15654                let end = Point::new(row.0, snapshot.line_len(row));
15655                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
15656
15657                let mut line_end_bytes = snapshot
15658                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
15659                    .flatten()
15660                    .copied();
15661
15662                let leading_space_len = if suffix_start_column > 0
15663                    && line_end_bytes.next() == Some(b' ')
15664                    && comment_suffix_has_leading_space
15665                {
15666                    1
15667                } else {
15668                    0
15669                };
15670
15671                // If this line currently begins with the line comment prefix, then record
15672                // the range containing the prefix.
15673                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
15674                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
15675                    start..end
15676                } else {
15677                    end..end
15678                }
15679            }
15680
15681            // TODO: Handle selections that cross excerpts
15682            for selection in &mut selections {
15683                let start_column = snapshot
15684                    .indent_size_for_line(MultiBufferRow(selection.start.row))
15685                    .len;
15686                let language = if let Some(language) =
15687                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
15688                {
15689                    language
15690                } else {
15691                    continue;
15692                };
15693
15694                selection_edit_ranges.clear();
15695
15696                // If multiple selections contain a given row, avoid processing that
15697                // row more than once.
15698                let mut start_row = MultiBufferRow(selection.start.row);
15699                if last_toggled_row == Some(start_row) {
15700                    start_row = start_row.next_row();
15701                }
15702                let end_row =
15703                    if selection.end.row > selection.start.row && selection.end.column == 0 {
15704                        MultiBufferRow(selection.end.row - 1)
15705                    } else {
15706                        MultiBufferRow(selection.end.row)
15707                    };
15708                last_toggled_row = Some(end_row);
15709
15710                if start_row > end_row {
15711                    continue;
15712                }
15713
15714                // If the language has line comments, toggle those.
15715                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
15716
15717                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
15718                if ignore_indent {
15719                    full_comment_prefixes = full_comment_prefixes
15720                        .into_iter()
15721                        .map(|s| Arc::from(s.trim_end()))
15722                        .collect();
15723                }
15724
15725                if !full_comment_prefixes.is_empty() {
15726                    let first_prefix = full_comment_prefixes
15727                        .first()
15728                        .expect("prefixes is non-empty");
15729                    let prefix_trimmed_lengths = full_comment_prefixes
15730                        .iter()
15731                        .map(|p| p.trim_end_matches(' ').len())
15732                        .collect::<SmallVec<[usize; 4]>>();
15733
15734                    let mut all_selection_lines_are_comments = true;
15735
15736                    for row in start_row.0..=end_row.0 {
15737                        let row = MultiBufferRow(row);
15738                        if start_row < end_row && snapshot.is_line_blank(row) {
15739                            continue;
15740                        }
15741
15742                        let prefix_range = full_comment_prefixes
15743                            .iter()
15744                            .zip(prefix_trimmed_lengths.iter().copied())
15745                            .map(|(prefix, trimmed_prefix_len)| {
15746                                comment_prefix_range(
15747                                    snapshot.deref(),
15748                                    row,
15749                                    &prefix[..trimmed_prefix_len],
15750                                    &prefix[trimmed_prefix_len..],
15751                                    ignore_indent,
15752                                )
15753                            })
15754                            .max_by_key(|range| range.end.column - range.start.column)
15755                            .expect("prefixes is non-empty");
15756
15757                        if prefix_range.is_empty() {
15758                            all_selection_lines_are_comments = false;
15759                        }
15760
15761                        selection_edit_ranges.push(prefix_range);
15762                    }
15763
15764                    if all_selection_lines_are_comments {
15765                        edits.extend(
15766                            selection_edit_ranges
15767                                .iter()
15768                                .cloned()
15769                                .map(|range| (range, empty_str.clone())),
15770                        );
15771                    } else {
15772                        let min_column = selection_edit_ranges
15773                            .iter()
15774                            .map(|range| range.start.column)
15775                            .min()
15776                            .unwrap_or(0);
15777                        edits.extend(selection_edit_ranges.iter().map(|range| {
15778                            let position = Point::new(range.start.row, min_column);
15779                            (position..position, first_prefix.clone())
15780                        }));
15781                    }
15782                } else if let Some(BlockCommentConfig {
15783                    start: full_comment_prefix,
15784                    end: comment_suffix,
15785                    ..
15786                }) = language.block_comment()
15787                {
15788                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
15789                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
15790                    let prefix_range = comment_prefix_range(
15791                        snapshot.deref(),
15792                        start_row,
15793                        comment_prefix,
15794                        comment_prefix_whitespace,
15795                        ignore_indent,
15796                    );
15797                    let suffix_range = comment_suffix_range(
15798                        snapshot.deref(),
15799                        end_row,
15800                        comment_suffix.trim_start_matches(' '),
15801                        comment_suffix.starts_with(' '),
15802                    );
15803
15804                    if prefix_range.is_empty() || suffix_range.is_empty() {
15805                        edits.push((
15806                            prefix_range.start..prefix_range.start,
15807                            full_comment_prefix.clone(),
15808                        ));
15809                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
15810                        suffixes_inserted.push((end_row, comment_suffix.len()));
15811                    } else {
15812                        edits.push((prefix_range, empty_str.clone()));
15813                        edits.push((suffix_range, empty_str.clone()));
15814                    }
15815                } else {
15816                    continue;
15817                }
15818            }
15819
15820            drop(snapshot);
15821            this.buffer.update(cx, |buffer, cx| {
15822                buffer.edit(edits, None, cx);
15823            });
15824
15825            // Adjust selections so that they end before any comment suffixes that
15826            // were inserted.
15827            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
15828            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15829            let snapshot = this.buffer.read(cx).read(cx);
15830            for selection in &mut selections {
15831                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
15832                    match row.cmp(&MultiBufferRow(selection.end.row)) {
15833                        Ordering::Less => {
15834                            suffixes_inserted.next();
15835                            continue;
15836                        }
15837                        Ordering::Greater => break,
15838                        Ordering::Equal => {
15839                            if selection.end.column == snapshot.line_len(row) {
15840                                if selection.is_empty() {
15841                                    selection.start.column -= suffix_len as u32;
15842                                }
15843                                selection.end.column -= suffix_len as u32;
15844                            }
15845                            break;
15846                        }
15847                    }
15848                }
15849            }
15850
15851            drop(snapshot);
15852            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
15853
15854            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
15855            let selections_on_single_row = selections.windows(2).all(|selections| {
15856                selections[0].start.row == selections[1].start.row
15857                    && selections[0].end.row == selections[1].end.row
15858                    && selections[0].start.row == selections[0].end.row
15859            });
15860            let selections_selecting = selections
15861                .iter()
15862                .any(|selection| selection.start != selection.end);
15863            let advance_downwards = action.advance_downwards
15864                && selections_on_single_row
15865                && !selections_selecting
15866                && !matches!(this.mode, EditorMode::SingleLine);
15867
15868            if advance_downwards {
15869                let snapshot = this.buffer.read(cx).snapshot(cx);
15870
15871                this.change_selections(Default::default(), window, cx, |s| {
15872                    s.move_cursors_with(|display_snapshot, display_point, _| {
15873                        let mut point = display_point.to_point(display_snapshot);
15874                        point.row += 1;
15875                        point = snapshot.clip_point(point, Bias::Left);
15876                        let display_point = point.to_display_point(display_snapshot);
15877                        let goal = SelectionGoal::HorizontalPosition(
15878                            display_snapshot
15879                                .x_for_display_point(display_point, text_layout_details)
15880                                .into(),
15881                        );
15882                        (display_point, goal)
15883                    })
15884                });
15885            }
15886        });
15887    }
15888
15889    pub fn select_enclosing_symbol(
15890        &mut self,
15891        _: &SelectEnclosingSymbol,
15892        window: &mut Window,
15893        cx: &mut Context<Self>,
15894    ) {
15895        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15896
15897        let buffer = self.buffer.read(cx).snapshot(cx);
15898        let old_selections = self
15899            .selections
15900            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15901            .into_boxed_slice();
15902
15903        fn update_selection(
15904            selection: &Selection<MultiBufferOffset>,
15905            buffer_snap: &MultiBufferSnapshot,
15906        ) -> Option<Selection<MultiBufferOffset>> {
15907            let cursor = selection.head();
15908            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
15909            for symbol in symbols.iter().rev() {
15910                let start = symbol.range.start.to_offset(buffer_snap);
15911                let end = symbol.range.end.to_offset(buffer_snap);
15912                let new_range = start..end;
15913                if start < selection.start || end > selection.end {
15914                    return Some(Selection {
15915                        id: selection.id,
15916                        start: new_range.start,
15917                        end: new_range.end,
15918                        goal: SelectionGoal::None,
15919                        reversed: selection.reversed,
15920                    });
15921                }
15922            }
15923            None
15924        }
15925
15926        let mut selected_larger_symbol = false;
15927        let new_selections = old_selections
15928            .iter()
15929            .map(|selection| match update_selection(selection, &buffer) {
15930                Some(new_selection) => {
15931                    if new_selection.range() != selection.range() {
15932                        selected_larger_symbol = true;
15933                    }
15934                    new_selection
15935                }
15936                None => selection.clone(),
15937            })
15938            .collect::<Vec<_>>();
15939
15940        if selected_larger_symbol {
15941            self.change_selections(Default::default(), window, cx, |s| {
15942                s.select(new_selections);
15943            });
15944        }
15945    }
15946
15947    pub fn select_larger_syntax_node(
15948        &mut self,
15949        _: &SelectLargerSyntaxNode,
15950        window: &mut Window,
15951        cx: &mut Context<Self>,
15952    ) {
15953        let Some(visible_row_count) = self.visible_row_count() else {
15954            return;
15955        };
15956        let old_selections: Box<[_]> = self
15957            .selections
15958            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15959            .into();
15960        if old_selections.is_empty() {
15961            return;
15962        }
15963
15964        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15965
15966        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15967        let buffer = self.buffer.read(cx).snapshot(cx);
15968
15969        let mut selected_larger_node = false;
15970        let mut new_selections = old_selections
15971            .iter()
15972            .map(|selection| {
15973                let old_range = selection.start..selection.end;
15974
15975                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
15976                    // manually select word at selection
15977                    if ["string_content", "inline"].contains(&node.kind()) {
15978                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
15979                        // ignore if word is already selected
15980                        if !word_range.is_empty() && old_range != word_range {
15981                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
15982                            // only select word if start and end point belongs to same word
15983                            if word_range == last_word_range {
15984                                selected_larger_node = true;
15985                                return Selection {
15986                                    id: selection.id,
15987                                    start: word_range.start,
15988                                    end: word_range.end,
15989                                    goal: SelectionGoal::None,
15990                                    reversed: selection.reversed,
15991                                };
15992                            }
15993                        }
15994                    }
15995                }
15996
15997                let mut new_range = old_range.clone();
15998                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
15999                    new_range = range;
16000                    if !node.is_named() {
16001                        continue;
16002                    }
16003                    if !display_map.intersects_fold(new_range.start)
16004                        && !display_map.intersects_fold(new_range.end)
16005                    {
16006                        break;
16007                    }
16008                }
16009
16010                selected_larger_node |= new_range != old_range;
16011                Selection {
16012                    id: selection.id,
16013                    start: new_range.start,
16014                    end: new_range.end,
16015                    goal: SelectionGoal::None,
16016                    reversed: selection.reversed,
16017                }
16018            })
16019            .collect::<Vec<_>>();
16020
16021        if !selected_larger_node {
16022            return; // don't put this call in the history
16023        }
16024
16025        // scroll based on transformation done to the last selection created by the user
16026        let (last_old, last_new) = old_selections
16027            .last()
16028            .zip(new_selections.last().cloned())
16029            .expect("old_selections isn't empty");
16030
16031        // revert selection
16032        let is_selection_reversed = {
16033            let should_newest_selection_be_reversed = last_old.start != last_new.start;
16034            new_selections.last_mut().expect("checked above").reversed =
16035                should_newest_selection_be_reversed;
16036            should_newest_selection_be_reversed
16037        };
16038
16039        if selected_larger_node {
16040            self.select_syntax_node_history.disable_clearing = true;
16041            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16042                s.select(new_selections.clone());
16043            });
16044            self.select_syntax_node_history.disable_clearing = false;
16045        }
16046
16047        let start_row = last_new.start.to_display_point(&display_map).row().0;
16048        let end_row = last_new.end.to_display_point(&display_map).row().0;
16049        let selection_height = end_row - start_row + 1;
16050        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
16051
16052        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
16053        let scroll_behavior = if fits_on_the_screen {
16054            self.request_autoscroll(Autoscroll::fit(), cx);
16055            SelectSyntaxNodeScrollBehavior::FitSelection
16056        } else if is_selection_reversed {
16057            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16058            SelectSyntaxNodeScrollBehavior::CursorTop
16059        } else {
16060            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16061            SelectSyntaxNodeScrollBehavior::CursorBottom
16062        };
16063
16064        self.select_syntax_node_history.push((
16065            old_selections,
16066            scroll_behavior,
16067            is_selection_reversed,
16068        ));
16069    }
16070
16071    pub fn select_smaller_syntax_node(
16072        &mut self,
16073        _: &SelectSmallerSyntaxNode,
16074        window: &mut Window,
16075        cx: &mut Context<Self>,
16076    ) {
16077        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16078
16079        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
16080            self.select_syntax_node_history.pop()
16081        {
16082            if let Some(selection) = selections.last_mut() {
16083                selection.reversed = is_selection_reversed;
16084            }
16085
16086            self.select_syntax_node_history.disable_clearing = true;
16087            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16088                s.select(selections.to_vec());
16089            });
16090            self.select_syntax_node_history.disable_clearing = false;
16091
16092            match scroll_behavior {
16093                SelectSyntaxNodeScrollBehavior::CursorTop => {
16094                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16095                }
16096                SelectSyntaxNodeScrollBehavior::FitSelection => {
16097                    self.request_autoscroll(Autoscroll::fit(), cx);
16098                }
16099                SelectSyntaxNodeScrollBehavior::CursorBottom => {
16100                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16101                }
16102            }
16103        }
16104    }
16105
16106    pub fn unwrap_syntax_node(
16107        &mut self,
16108        _: &UnwrapSyntaxNode,
16109        window: &mut Window,
16110        cx: &mut Context<Self>,
16111    ) {
16112        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16113
16114        let buffer = self.buffer.read(cx).snapshot(cx);
16115        let selections = self
16116            .selections
16117            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16118            .into_iter()
16119            // subtracting the offset requires sorting
16120            .sorted_by_key(|i| i.start);
16121
16122        let full_edits = selections
16123            .into_iter()
16124            .filter_map(|selection| {
16125                let child = if selection.is_empty()
16126                    && let Some((_, ancestor_range)) =
16127                        buffer.syntax_ancestor(selection.start..selection.end)
16128                {
16129                    ancestor_range
16130                } else {
16131                    selection.range()
16132                };
16133
16134                let mut parent = child.clone();
16135                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
16136                    parent = ancestor_range;
16137                    if parent.start < child.start || parent.end > child.end {
16138                        break;
16139                    }
16140                }
16141
16142                if parent == child {
16143                    return None;
16144                }
16145                let text = buffer.text_for_range(child).collect::<String>();
16146                Some((selection.id, parent, text))
16147            })
16148            .collect::<Vec<_>>();
16149        if full_edits.is_empty() {
16150            return;
16151        }
16152
16153        self.transact(window, cx, |this, window, cx| {
16154            this.buffer.update(cx, |buffer, cx| {
16155                buffer.edit(
16156                    full_edits
16157                        .iter()
16158                        .map(|(_, p, t)| (p.clone(), t.clone()))
16159                        .collect::<Vec<_>>(),
16160                    None,
16161                    cx,
16162                );
16163            });
16164            this.change_selections(Default::default(), window, cx, |s| {
16165                let mut offset = 0;
16166                let mut selections = vec![];
16167                for (id, parent, text) in full_edits {
16168                    let start = parent.start - offset;
16169                    offset += (parent.end - parent.start) - text.len();
16170                    selections.push(Selection {
16171                        id,
16172                        start,
16173                        end: start + text.len(),
16174                        reversed: false,
16175                        goal: Default::default(),
16176                    });
16177                }
16178                s.select(selections);
16179            });
16180        });
16181    }
16182
16183    pub fn select_next_syntax_node(
16184        &mut self,
16185        _: &SelectNextSyntaxNode,
16186        window: &mut Window,
16187        cx: &mut Context<Self>,
16188    ) {
16189        let old_selections: Box<[_]> = self
16190            .selections
16191            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16192            .into();
16193        if old_selections.is_empty() {
16194            return;
16195        }
16196
16197        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16198
16199        let buffer = self.buffer.read(cx).snapshot(cx);
16200        let mut selected_sibling = false;
16201
16202        let new_selections = old_selections
16203            .iter()
16204            .map(|selection| {
16205                let old_range = selection.start..selection.end;
16206
16207                let old_range =
16208                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16209                let excerpt = buffer.excerpt_containing(old_range.clone());
16210
16211                if let Some(mut excerpt) = excerpt
16212                    && let Some(node) = excerpt
16213                        .buffer()
16214                        .syntax_next_sibling(excerpt.map_range_to_buffer(old_range))
16215                {
16216                    let new_range = excerpt.map_range_from_buffer(
16217                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16218                    );
16219                    selected_sibling = true;
16220                    Selection {
16221                        id: selection.id,
16222                        start: new_range.start,
16223                        end: new_range.end,
16224                        goal: SelectionGoal::None,
16225                        reversed: selection.reversed,
16226                    }
16227                } else {
16228                    selection.clone()
16229                }
16230            })
16231            .collect::<Vec<_>>();
16232
16233        if selected_sibling {
16234            self.change_selections(
16235                SelectionEffects::scroll(Autoscroll::fit()),
16236                window,
16237                cx,
16238                |s| {
16239                    s.select(new_selections);
16240                },
16241            );
16242        }
16243    }
16244
16245    pub fn select_prev_syntax_node(
16246        &mut self,
16247        _: &SelectPreviousSyntaxNode,
16248        window: &mut Window,
16249        cx: &mut Context<Self>,
16250    ) {
16251        let old_selections: Box<[_]> = self
16252            .selections
16253            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16254            .into();
16255        if old_selections.is_empty() {
16256            return;
16257        }
16258
16259        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16260
16261        let buffer = self.buffer.read(cx).snapshot(cx);
16262        let mut selected_sibling = false;
16263
16264        let new_selections = old_selections
16265            .iter()
16266            .map(|selection| {
16267                let old_range = selection.start..selection.end;
16268                let old_range =
16269                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16270                let excerpt = buffer.excerpt_containing(old_range.clone());
16271
16272                if let Some(mut excerpt) = excerpt
16273                    && let Some(node) = excerpt
16274                        .buffer()
16275                        .syntax_prev_sibling(excerpt.map_range_to_buffer(old_range))
16276                {
16277                    let new_range = excerpt.map_range_from_buffer(
16278                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16279                    );
16280                    selected_sibling = true;
16281                    Selection {
16282                        id: selection.id,
16283                        start: new_range.start,
16284                        end: new_range.end,
16285                        goal: SelectionGoal::None,
16286                        reversed: selection.reversed,
16287                    }
16288                } else {
16289                    selection.clone()
16290                }
16291            })
16292            .collect::<Vec<_>>();
16293
16294        if selected_sibling {
16295            self.change_selections(
16296                SelectionEffects::scroll(Autoscroll::fit()),
16297                window,
16298                cx,
16299                |s| {
16300                    s.select(new_selections);
16301                },
16302            );
16303        }
16304    }
16305
16306    fn refresh_runnables(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Task<()> {
16307        if !EditorSettings::get_global(cx).gutter.runnables {
16308            self.clear_tasks();
16309            return Task::ready(());
16310        }
16311        let project = self.project().map(Entity::downgrade);
16312        let task_sources = self.lsp_task_sources(cx);
16313        let multi_buffer = self.buffer.downgrade();
16314        cx.spawn_in(window, async move |editor, cx| {
16315            cx.background_executor().timer(UPDATE_DEBOUNCE).await;
16316            let Some(project) = project.and_then(|p| p.upgrade()) else {
16317                return;
16318            };
16319            let Ok(display_snapshot) = editor.update(cx, |this, cx| {
16320                this.display_map.update(cx, |map, cx| map.snapshot(cx))
16321            }) else {
16322                return;
16323            };
16324
16325            let hide_runnables = project
16326                .update(cx, |project, _| project.is_via_collab())
16327                .unwrap_or(true);
16328            if hide_runnables {
16329                return;
16330            }
16331            let new_rows =
16332                cx.background_spawn({
16333                    let snapshot = display_snapshot.clone();
16334                    async move {
16335                        Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
16336                    }
16337                })
16338                    .await;
16339            let Ok(lsp_tasks) =
16340                cx.update(|_, cx| crate::lsp_tasks(project.clone(), &task_sources, None, cx))
16341            else {
16342                return;
16343            };
16344            let lsp_tasks = lsp_tasks.await;
16345
16346            let Ok(mut lsp_tasks_by_rows) = cx.update(|_, cx| {
16347                lsp_tasks
16348                    .into_iter()
16349                    .flat_map(|(kind, tasks)| {
16350                        tasks.into_iter().filter_map(move |(location, task)| {
16351                            Some((kind.clone(), location?, task))
16352                        })
16353                    })
16354                    .fold(HashMap::default(), |mut acc, (kind, location, task)| {
16355                        let buffer = location.target.buffer;
16356                        let buffer_snapshot = buffer.read(cx).snapshot();
16357                        let offset = display_snapshot.buffer_snapshot().excerpts().find_map(
16358                            |(excerpt_id, snapshot, _)| {
16359                                if snapshot.remote_id() == buffer_snapshot.remote_id() {
16360                                    display_snapshot
16361                                        .buffer_snapshot()
16362                                        .anchor_in_excerpt(excerpt_id, location.target.range.start)
16363                                } else {
16364                                    None
16365                                }
16366                            },
16367                        );
16368                        if let Some(offset) = offset {
16369                            let task_buffer_range =
16370                                location.target.range.to_point(&buffer_snapshot);
16371                            let context_buffer_range =
16372                                task_buffer_range.to_offset(&buffer_snapshot);
16373                            let context_range = BufferOffset(context_buffer_range.start)
16374                                ..BufferOffset(context_buffer_range.end);
16375
16376                            acc.entry((buffer_snapshot.remote_id(), task_buffer_range.start.row))
16377                                .or_insert_with(|| RunnableTasks {
16378                                    templates: Vec::new(),
16379                                    offset,
16380                                    column: task_buffer_range.start.column,
16381                                    extra_variables: HashMap::default(),
16382                                    context_range,
16383                                })
16384                                .templates
16385                                .push((kind, task.original_task().clone()));
16386                        }
16387
16388                        acc
16389                    })
16390            }) else {
16391                return;
16392            };
16393
16394            let Ok(prefer_lsp) = multi_buffer.update(cx, |buffer, cx| {
16395                buffer.language_settings(cx).tasks.prefer_lsp
16396            }) else {
16397                return;
16398            };
16399
16400            let rows = Self::runnable_rows(
16401                project,
16402                display_snapshot,
16403                prefer_lsp && !lsp_tasks_by_rows.is_empty(),
16404                new_rows,
16405                cx.clone(),
16406            )
16407            .await;
16408            editor
16409                .update(cx, |editor, _| {
16410                    editor.clear_tasks();
16411                    for (key, mut value) in rows {
16412                        if let Some(lsp_tasks) = lsp_tasks_by_rows.remove(&key) {
16413                            value.templates.extend(lsp_tasks.templates);
16414                        }
16415
16416                        editor.insert_tasks(key, value);
16417                    }
16418                    for (key, value) in lsp_tasks_by_rows {
16419                        editor.insert_tasks(key, value);
16420                    }
16421                })
16422                .ok();
16423        })
16424    }
16425    fn fetch_runnable_ranges(
16426        snapshot: &DisplaySnapshot,
16427        range: Range<Anchor>,
16428    ) -> Vec<(Range<MultiBufferOffset>, language::RunnableRange)> {
16429        snapshot.buffer_snapshot().runnable_ranges(range).collect()
16430    }
16431
16432    fn runnable_rows(
16433        project: Entity<Project>,
16434        snapshot: DisplaySnapshot,
16435        prefer_lsp: bool,
16436        runnable_ranges: Vec<(Range<MultiBufferOffset>, language::RunnableRange)>,
16437        cx: AsyncWindowContext,
16438    ) -> Task<Vec<((BufferId, BufferRow), RunnableTasks)>> {
16439        cx.spawn(async move |cx| {
16440            let mut runnable_rows = Vec::with_capacity(runnable_ranges.len());
16441            for (run_range, mut runnable) in runnable_ranges {
16442                let Some(tasks) = cx
16443                    .update(|_, cx| Self::templates_with_tags(&project, &mut runnable.runnable, cx))
16444                    .ok()
16445                else {
16446                    continue;
16447                };
16448                let mut tasks = tasks.await;
16449
16450                if prefer_lsp {
16451                    tasks.retain(|(task_kind, _)| {
16452                        !matches!(task_kind, TaskSourceKind::Language { .. })
16453                    });
16454                }
16455                if tasks.is_empty() {
16456                    continue;
16457                }
16458
16459                let point = run_range.start.to_point(&snapshot.buffer_snapshot());
16460                let Some(row) = snapshot
16461                    .buffer_snapshot()
16462                    .buffer_line_for_row(MultiBufferRow(point.row))
16463                    .map(|(_, range)| range.start.row)
16464                else {
16465                    continue;
16466                };
16467
16468                let context_range =
16469                    BufferOffset(runnable.full_range.start)..BufferOffset(runnable.full_range.end);
16470                runnable_rows.push((
16471                    (runnable.buffer_id, row),
16472                    RunnableTasks {
16473                        templates: tasks,
16474                        offset: snapshot.buffer_snapshot().anchor_before(run_range.start),
16475                        context_range,
16476                        column: point.column,
16477                        extra_variables: runnable.extra_captures,
16478                    },
16479                ));
16480            }
16481            runnable_rows
16482        })
16483    }
16484
16485    fn templates_with_tags(
16486        project: &Entity<Project>,
16487        runnable: &mut Runnable,
16488        cx: &mut App,
16489    ) -> Task<Vec<(TaskSourceKind, TaskTemplate)>> {
16490        let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
16491            let (worktree_id, file) = project
16492                .buffer_for_id(runnable.buffer, cx)
16493                .and_then(|buffer| buffer.read(cx).file())
16494                .map(|file| (file.worktree_id(cx), file.clone()))
16495                .unzip();
16496
16497            (
16498                project.task_store().read(cx).task_inventory().cloned(),
16499                worktree_id,
16500                file,
16501            )
16502        });
16503
16504        let tags = mem::take(&mut runnable.tags);
16505        let language = runnable.language.clone();
16506        cx.spawn(async move |cx| {
16507            let mut templates_with_tags = Vec::new();
16508            if let Some(inventory) = inventory {
16509                for RunnableTag(tag) in tags {
16510                    let Ok(new_tasks) = inventory.update(cx, |inventory, cx| {
16511                        inventory.list_tasks(file.clone(), Some(language.clone()), worktree_id, cx)
16512                    }) else {
16513                        return templates_with_tags;
16514                    };
16515                    templates_with_tags.extend(new_tasks.await.into_iter().filter(
16516                        move |(_, template)| {
16517                            template.tags.iter().any(|source_tag| source_tag == &tag)
16518                        },
16519                    ));
16520                }
16521            }
16522            templates_with_tags.sort_by_key(|(kind, _)| kind.to_owned());
16523
16524            if let Some((leading_tag_source, _)) = templates_with_tags.first() {
16525                // Strongest source wins; if we have worktree tag binding, prefer that to
16526                // global and language bindings;
16527                // if we have a global binding, prefer that to language binding.
16528                let first_mismatch = templates_with_tags
16529                    .iter()
16530                    .position(|(tag_source, _)| tag_source != leading_tag_source);
16531                if let Some(index) = first_mismatch {
16532                    templates_with_tags.truncate(index);
16533                }
16534            }
16535
16536            templates_with_tags
16537        })
16538    }
16539
16540    pub fn move_to_enclosing_bracket(
16541        &mut self,
16542        _: &MoveToEnclosingBracket,
16543        window: &mut Window,
16544        cx: &mut Context<Self>,
16545    ) {
16546        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16547        self.change_selections(Default::default(), window, cx, |s| {
16548            s.move_offsets_with(|snapshot, selection| {
16549                let Some(enclosing_bracket_ranges) =
16550                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
16551                else {
16552                    return;
16553                };
16554
16555                let mut best_length = usize::MAX;
16556                let mut best_inside = false;
16557                let mut best_in_bracket_range = false;
16558                let mut best_destination = None;
16559                for (open, close) in enclosing_bracket_ranges {
16560                    let close = close.to_inclusive();
16561                    let length = *close.end() - open.start;
16562                    let inside = selection.start >= open.end && selection.end <= *close.start();
16563                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
16564                        || close.contains(&selection.head());
16565
16566                    // If best is next to a bracket and current isn't, skip
16567                    if !in_bracket_range && best_in_bracket_range {
16568                        continue;
16569                    }
16570
16571                    // Prefer smaller lengths unless best is inside and current isn't
16572                    if length > best_length && (best_inside || !inside) {
16573                        continue;
16574                    }
16575
16576                    best_length = length;
16577                    best_inside = inside;
16578                    best_in_bracket_range = in_bracket_range;
16579                    best_destination = Some(
16580                        if close.contains(&selection.start) && close.contains(&selection.end) {
16581                            if inside { open.end } else { open.start }
16582                        } else if inside {
16583                            *close.start()
16584                        } else {
16585                            *close.end()
16586                        },
16587                    );
16588                }
16589
16590                if let Some(destination) = best_destination {
16591                    selection.collapse_to(destination, SelectionGoal::None);
16592                }
16593            })
16594        });
16595    }
16596
16597    pub fn undo_selection(
16598        &mut self,
16599        _: &UndoSelection,
16600        window: &mut Window,
16601        cx: &mut Context<Self>,
16602    ) {
16603        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16604        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
16605            self.selection_history.mode = SelectionHistoryMode::Undoing;
16606            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16607                this.end_selection(window, cx);
16608                this.change_selections(
16609                    SelectionEffects::scroll(Autoscroll::newest()),
16610                    window,
16611                    cx,
16612                    |s| s.select_anchors(entry.selections.to_vec()),
16613                );
16614            });
16615            self.selection_history.mode = SelectionHistoryMode::Normal;
16616
16617            self.select_next_state = entry.select_next_state;
16618            self.select_prev_state = entry.select_prev_state;
16619            self.add_selections_state = entry.add_selections_state;
16620        }
16621    }
16622
16623    pub fn redo_selection(
16624        &mut self,
16625        _: &RedoSelection,
16626        window: &mut Window,
16627        cx: &mut Context<Self>,
16628    ) {
16629        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16630        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
16631            self.selection_history.mode = SelectionHistoryMode::Redoing;
16632            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
16633                this.end_selection(window, cx);
16634                this.change_selections(
16635                    SelectionEffects::scroll(Autoscroll::newest()),
16636                    window,
16637                    cx,
16638                    |s| s.select_anchors(entry.selections.to_vec()),
16639                );
16640            });
16641            self.selection_history.mode = SelectionHistoryMode::Normal;
16642
16643            self.select_next_state = entry.select_next_state;
16644            self.select_prev_state = entry.select_prev_state;
16645            self.add_selections_state = entry.add_selections_state;
16646        }
16647    }
16648
16649    pub fn expand_excerpts(
16650        &mut self,
16651        action: &ExpandExcerpts,
16652        _: &mut Window,
16653        cx: &mut Context<Self>,
16654    ) {
16655        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
16656    }
16657
16658    pub fn expand_excerpts_down(
16659        &mut self,
16660        action: &ExpandExcerptsDown,
16661        _: &mut Window,
16662        cx: &mut Context<Self>,
16663    ) {
16664        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
16665    }
16666
16667    pub fn expand_excerpts_up(
16668        &mut self,
16669        action: &ExpandExcerptsUp,
16670        _: &mut Window,
16671        cx: &mut Context<Self>,
16672    ) {
16673        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
16674    }
16675
16676    pub fn expand_excerpts_for_direction(
16677        &mut self,
16678        lines: u32,
16679        direction: ExpandExcerptDirection,
16680
16681        cx: &mut Context<Self>,
16682    ) {
16683        let selections = self.selections.disjoint_anchors_arc();
16684
16685        let lines = if lines == 0 {
16686            EditorSettings::get_global(cx).expand_excerpt_lines
16687        } else {
16688            lines
16689        };
16690
16691        self.buffer.update(cx, |buffer, cx| {
16692            let snapshot = buffer.snapshot(cx);
16693            let mut excerpt_ids = selections
16694                .iter()
16695                .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
16696                .collect::<Vec<_>>();
16697            excerpt_ids.sort();
16698            excerpt_ids.dedup();
16699            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
16700        })
16701    }
16702
16703    pub fn expand_excerpt(
16704        &mut self,
16705        excerpt: ExcerptId,
16706        direction: ExpandExcerptDirection,
16707        window: &mut Window,
16708        cx: &mut Context<Self>,
16709    ) {
16710        let current_scroll_position = self.scroll_position(cx);
16711        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
16712        let mut scroll = None;
16713
16714        if direction == ExpandExcerptDirection::Down {
16715            let multi_buffer = self.buffer.read(cx);
16716            let snapshot = multi_buffer.snapshot(cx);
16717            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
16718                && let Some(buffer) = multi_buffer.buffer(buffer_id)
16719                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
16720            {
16721                let buffer_snapshot = buffer.read(cx).snapshot();
16722                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
16723                let last_row = buffer_snapshot.max_point().row;
16724                let lines_below = last_row.saturating_sub(excerpt_end_row);
16725                if lines_below >= lines_to_expand {
16726                    scroll = Some(
16727                        current_scroll_position
16728                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
16729                    );
16730                }
16731            }
16732        }
16733        if direction == ExpandExcerptDirection::Up
16734            && self
16735                .buffer
16736                .read(cx)
16737                .snapshot(cx)
16738                .excerpt_before(excerpt)
16739                .is_none()
16740        {
16741            scroll = Some(current_scroll_position);
16742        }
16743
16744        self.buffer.update(cx, |buffer, cx| {
16745            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
16746        });
16747
16748        if let Some(new_scroll_position) = scroll {
16749            self.set_scroll_position(new_scroll_position, window, cx);
16750        }
16751    }
16752
16753    pub fn go_to_singleton_buffer_point(
16754        &mut self,
16755        point: Point,
16756        window: &mut Window,
16757        cx: &mut Context<Self>,
16758    ) {
16759        self.go_to_singleton_buffer_range(point..point, window, cx);
16760    }
16761
16762    pub fn go_to_singleton_buffer_range(
16763        &mut self,
16764        range: Range<Point>,
16765        window: &mut Window,
16766        cx: &mut Context<Self>,
16767    ) {
16768        let multibuffer = self.buffer().read(cx);
16769        let Some(buffer) = multibuffer.as_singleton() else {
16770            return;
16771        };
16772        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
16773            return;
16774        };
16775        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
16776            return;
16777        };
16778        self.change_selections(
16779            SelectionEffects::default().nav_history(true),
16780            window,
16781            cx,
16782            |s| s.select_anchor_ranges([start..end]),
16783        );
16784    }
16785
16786    pub fn go_to_diagnostic(
16787        &mut self,
16788        action: &GoToDiagnostic,
16789        window: &mut Window,
16790        cx: &mut Context<Self>,
16791    ) {
16792        if !self.diagnostics_enabled() {
16793            return;
16794        }
16795        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16796        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
16797    }
16798
16799    pub fn go_to_prev_diagnostic(
16800        &mut self,
16801        action: &GoToPreviousDiagnostic,
16802        window: &mut Window,
16803        cx: &mut Context<Self>,
16804    ) {
16805        if !self.diagnostics_enabled() {
16806            return;
16807        }
16808        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16809        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
16810    }
16811
16812    pub fn go_to_diagnostic_impl(
16813        &mut self,
16814        direction: Direction,
16815        severity: GoToDiagnosticSeverityFilter,
16816        window: &mut Window,
16817        cx: &mut Context<Self>,
16818    ) {
16819        let buffer = self.buffer.read(cx).snapshot(cx);
16820        let selection = self
16821            .selections
16822            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
16823
16824        let mut active_group_id = None;
16825        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
16826            && active_group.active_range.start.to_offset(&buffer) == selection.start
16827        {
16828            active_group_id = Some(active_group.group_id);
16829        }
16830
16831        fn filtered<'a>(
16832            severity: GoToDiagnosticSeverityFilter,
16833            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>>,
16834        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>> {
16835            diagnostics
16836                .filter(move |entry| severity.matches(entry.diagnostic.severity))
16837                .filter(|entry| entry.range.start != entry.range.end)
16838                .filter(|entry| !entry.diagnostic.is_unnecessary)
16839        }
16840
16841        let before = filtered(
16842            severity,
16843            buffer
16844                .diagnostics_in_range(MultiBufferOffset(0)..selection.start)
16845                .filter(|entry| entry.range.start <= selection.start),
16846        );
16847        let after = filtered(
16848            severity,
16849            buffer
16850                .diagnostics_in_range(selection.start..buffer.len())
16851                .filter(|entry| entry.range.start >= selection.start),
16852        );
16853
16854        let mut found: Option<DiagnosticEntryRef<MultiBufferOffset>> = None;
16855        if direction == Direction::Prev {
16856            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
16857            {
16858                for diagnostic in prev_diagnostics.into_iter().rev() {
16859                    if diagnostic.range.start != selection.start
16860                        || active_group_id
16861                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
16862                    {
16863                        found = Some(diagnostic);
16864                        break 'outer;
16865                    }
16866                }
16867            }
16868        } else {
16869            for diagnostic in after.chain(before) {
16870                if diagnostic.range.start != selection.start
16871                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
16872                {
16873                    found = Some(diagnostic);
16874                    break;
16875                }
16876            }
16877        }
16878        let Some(next_diagnostic) = found else {
16879            return;
16880        };
16881
16882        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
16883        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
16884            return;
16885        };
16886        let snapshot = self.snapshot(window, cx);
16887        if snapshot.intersects_fold(next_diagnostic.range.start) {
16888            self.unfold_ranges(
16889                std::slice::from_ref(&next_diagnostic.range),
16890                true,
16891                false,
16892                cx,
16893            );
16894        }
16895        self.change_selections(Default::default(), window, cx, |s| {
16896            s.select_ranges(vec![
16897                next_diagnostic.range.start..next_diagnostic.range.start,
16898            ])
16899        });
16900        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
16901        self.refresh_edit_prediction(false, true, window, cx);
16902    }
16903
16904    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
16905        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16906        let snapshot = self.snapshot(window, cx);
16907        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
16908        self.go_to_hunk_before_or_after_position(
16909            &snapshot,
16910            selection.head(),
16911            Direction::Next,
16912            window,
16913            cx,
16914        );
16915    }
16916
16917    pub fn go_to_hunk_before_or_after_position(
16918        &mut self,
16919        snapshot: &EditorSnapshot,
16920        position: Point,
16921        direction: Direction,
16922        window: &mut Window,
16923        cx: &mut Context<Editor>,
16924    ) {
16925        let row = if direction == Direction::Next {
16926            self.hunk_after_position(snapshot, position)
16927                .map(|hunk| hunk.row_range.start)
16928        } else {
16929            self.hunk_before_position(snapshot, position)
16930        };
16931
16932        if let Some(row) = row {
16933            let destination = Point::new(row.0, 0);
16934            let autoscroll = Autoscroll::center();
16935
16936            self.unfold_ranges(&[destination..destination], false, false, cx);
16937            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
16938                s.select_ranges([destination..destination]);
16939            });
16940        }
16941    }
16942
16943    fn hunk_after_position(
16944        &mut self,
16945        snapshot: &EditorSnapshot,
16946        position: Point,
16947    ) -> Option<MultiBufferDiffHunk> {
16948        snapshot
16949            .buffer_snapshot()
16950            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
16951            .find(|hunk| hunk.row_range.start.0 > position.row)
16952            .or_else(|| {
16953                snapshot
16954                    .buffer_snapshot()
16955                    .diff_hunks_in_range(Point::zero()..position)
16956                    .find(|hunk| hunk.row_range.end.0 < position.row)
16957            })
16958    }
16959
16960    fn go_to_prev_hunk(
16961        &mut self,
16962        _: &GoToPreviousHunk,
16963        window: &mut Window,
16964        cx: &mut Context<Self>,
16965    ) {
16966        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16967        let snapshot = self.snapshot(window, cx);
16968        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
16969        self.go_to_hunk_before_or_after_position(
16970            &snapshot,
16971            selection.head(),
16972            Direction::Prev,
16973            window,
16974            cx,
16975        );
16976    }
16977
16978    fn hunk_before_position(
16979        &mut self,
16980        snapshot: &EditorSnapshot,
16981        position: Point,
16982    ) -> Option<MultiBufferRow> {
16983        snapshot
16984            .buffer_snapshot()
16985            .diff_hunk_before(position)
16986            .or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
16987    }
16988
16989    fn go_to_next_change(
16990        &mut self,
16991        _: &GoToNextChange,
16992        window: &mut Window,
16993        cx: &mut Context<Self>,
16994    ) {
16995        if let Some(selections) = self
16996            .change_list
16997            .next_change(1, Direction::Next)
16998            .map(|s| s.to_vec())
16999        {
17000            self.change_selections(Default::default(), window, cx, |s| {
17001                let map = s.display_snapshot();
17002                s.select_display_ranges(selections.iter().map(|a| {
17003                    let point = a.to_display_point(&map);
17004                    point..point
17005                }))
17006            })
17007        }
17008    }
17009
17010    fn go_to_previous_change(
17011        &mut self,
17012        _: &GoToPreviousChange,
17013        window: &mut Window,
17014        cx: &mut Context<Self>,
17015    ) {
17016        if let Some(selections) = self
17017            .change_list
17018            .next_change(1, Direction::Prev)
17019            .map(|s| s.to_vec())
17020        {
17021            self.change_selections(Default::default(), window, cx, |s| {
17022                let map = s.display_snapshot();
17023                s.select_display_ranges(selections.iter().map(|a| {
17024                    let point = a.to_display_point(&map);
17025                    point..point
17026                }))
17027            })
17028        }
17029    }
17030
17031    pub fn go_to_next_document_highlight(
17032        &mut self,
17033        _: &GoToNextDocumentHighlight,
17034        window: &mut Window,
17035        cx: &mut Context<Self>,
17036    ) {
17037        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
17038    }
17039
17040    pub fn go_to_prev_document_highlight(
17041        &mut self,
17042        _: &GoToPreviousDocumentHighlight,
17043        window: &mut Window,
17044        cx: &mut Context<Self>,
17045    ) {
17046        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
17047    }
17048
17049    pub fn go_to_document_highlight_before_or_after_position(
17050        &mut self,
17051        direction: Direction,
17052        window: &mut Window,
17053        cx: &mut Context<Editor>,
17054    ) {
17055        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17056        let snapshot = self.snapshot(window, cx);
17057        let buffer = &snapshot.buffer_snapshot();
17058        let position = self
17059            .selections
17060            .newest::<Point>(&snapshot.display_snapshot)
17061            .head();
17062        let anchor_position = buffer.anchor_after(position);
17063
17064        // Get all document highlights (both read and write)
17065        let mut all_highlights = Vec::new();
17066
17067        if let Some((_, read_highlights)) = self
17068            .background_highlights
17069            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
17070        {
17071            all_highlights.extend(read_highlights.iter());
17072        }
17073
17074        if let Some((_, write_highlights)) = self
17075            .background_highlights
17076            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
17077        {
17078            all_highlights.extend(write_highlights.iter());
17079        }
17080
17081        if all_highlights.is_empty() {
17082            return;
17083        }
17084
17085        // Sort highlights by position
17086        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
17087
17088        let target_highlight = match direction {
17089            Direction::Next => {
17090                // Find the first highlight after the current position
17091                all_highlights
17092                    .iter()
17093                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
17094            }
17095            Direction::Prev => {
17096                // Find the last highlight before the current position
17097                all_highlights
17098                    .iter()
17099                    .rev()
17100                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
17101            }
17102        };
17103
17104        if let Some(highlight) = target_highlight {
17105            let destination = highlight.start.to_point(buffer);
17106            let autoscroll = Autoscroll::center();
17107
17108            self.unfold_ranges(&[destination..destination], false, false, cx);
17109            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17110                s.select_ranges([destination..destination]);
17111            });
17112        }
17113    }
17114
17115    fn go_to_line<T: 'static>(
17116        &mut self,
17117        position: Anchor,
17118        highlight_color: Option<Hsla>,
17119        window: &mut Window,
17120        cx: &mut Context<Self>,
17121    ) {
17122        let snapshot = self.snapshot(window, cx).display_snapshot;
17123        let position = position.to_point(&snapshot.buffer_snapshot());
17124        let start = snapshot
17125            .buffer_snapshot()
17126            .clip_point(Point::new(position.row, 0), Bias::Left);
17127        let end = start + Point::new(1, 0);
17128        let start = snapshot.buffer_snapshot().anchor_before(start);
17129        let end = snapshot.buffer_snapshot().anchor_before(end);
17130
17131        self.highlight_rows::<T>(
17132            start..end,
17133            highlight_color
17134                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
17135            Default::default(),
17136            cx,
17137        );
17138
17139        if self.buffer.read(cx).is_singleton() {
17140            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
17141        }
17142    }
17143
17144    pub fn go_to_definition(
17145        &mut self,
17146        _: &GoToDefinition,
17147        window: &mut Window,
17148        cx: &mut Context<Self>,
17149    ) -> Task<Result<Navigated>> {
17150        let definition =
17151            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
17152        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
17153        cx.spawn_in(window, async move |editor, cx| {
17154            if definition.await? == Navigated::Yes {
17155                return Ok(Navigated::Yes);
17156            }
17157            match fallback_strategy {
17158                GoToDefinitionFallback::None => Ok(Navigated::No),
17159                GoToDefinitionFallback::FindAllReferences => {
17160                    match editor.update_in(cx, |editor, window, cx| {
17161                        editor.find_all_references(&FindAllReferences::default(), window, cx)
17162                    })? {
17163                        Some(references) => references.await,
17164                        None => Ok(Navigated::No),
17165                    }
17166                }
17167            }
17168        })
17169    }
17170
17171    pub fn go_to_declaration(
17172        &mut self,
17173        _: &GoToDeclaration,
17174        window: &mut Window,
17175        cx: &mut Context<Self>,
17176    ) -> Task<Result<Navigated>> {
17177        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
17178    }
17179
17180    pub fn go_to_declaration_split(
17181        &mut self,
17182        _: &GoToDeclaration,
17183        window: &mut Window,
17184        cx: &mut Context<Self>,
17185    ) -> Task<Result<Navigated>> {
17186        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
17187    }
17188
17189    pub fn go_to_implementation(
17190        &mut self,
17191        _: &GoToImplementation,
17192        window: &mut Window,
17193        cx: &mut Context<Self>,
17194    ) -> Task<Result<Navigated>> {
17195        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
17196    }
17197
17198    pub fn go_to_implementation_split(
17199        &mut self,
17200        _: &GoToImplementationSplit,
17201        window: &mut Window,
17202        cx: &mut Context<Self>,
17203    ) -> Task<Result<Navigated>> {
17204        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
17205    }
17206
17207    pub fn go_to_type_definition(
17208        &mut self,
17209        _: &GoToTypeDefinition,
17210        window: &mut Window,
17211        cx: &mut Context<Self>,
17212    ) -> Task<Result<Navigated>> {
17213        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
17214    }
17215
17216    pub fn go_to_definition_split(
17217        &mut self,
17218        _: &GoToDefinitionSplit,
17219        window: &mut Window,
17220        cx: &mut Context<Self>,
17221    ) -> Task<Result<Navigated>> {
17222        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
17223    }
17224
17225    pub fn go_to_type_definition_split(
17226        &mut self,
17227        _: &GoToTypeDefinitionSplit,
17228        window: &mut Window,
17229        cx: &mut Context<Self>,
17230    ) -> Task<Result<Navigated>> {
17231        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
17232    }
17233
17234    fn go_to_definition_of_kind(
17235        &mut self,
17236        kind: GotoDefinitionKind,
17237        split: bool,
17238        window: &mut Window,
17239        cx: &mut Context<Self>,
17240    ) -> Task<Result<Navigated>> {
17241        let Some(provider) = self.semantics_provider.clone() else {
17242            return Task::ready(Ok(Navigated::No));
17243        };
17244        let head = self
17245            .selections
17246            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
17247            .head();
17248        let buffer = self.buffer.read(cx);
17249        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
17250            return Task::ready(Ok(Navigated::No));
17251        };
17252        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
17253            return Task::ready(Ok(Navigated::No));
17254        };
17255
17256        cx.spawn_in(window, async move |editor, cx| {
17257            let Some(definitions) = definitions.await? else {
17258                return Ok(Navigated::No);
17259            };
17260            let navigated = editor
17261                .update_in(cx, |editor, window, cx| {
17262                    editor.navigate_to_hover_links(
17263                        Some(kind),
17264                        definitions
17265                            .into_iter()
17266                            .filter(|location| {
17267                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
17268                            })
17269                            .map(HoverLink::Text)
17270                            .collect::<Vec<_>>(),
17271                        split,
17272                        window,
17273                        cx,
17274                    )
17275                })?
17276                .await?;
17277            anyhow::Ok(navigated)
17278        })
17279    }
17280
17281    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
17282        let selection = self.selections.newest_anchor();
17283        let head = selection.head();
17284        let tail = selection.tail();
17285
17286        let Some((buffer, start_position)) =
17287            self.buffer.read(cx).text_anchor_for_position(head, cx)
17288        else {
17289            return;
17290        };
17291
17292        let end_position = if head != tail {
17293            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
17294                return;
17295            };
17296            Some(pos)
17297        } else {
17298            None
17299        };
17300
17301        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
17302            let url = if let Some(end_pos) = end_position {
17303                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
17304            } else {
17305                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
17306            };
17307
17308            if let Some(url) = url {
17309                cx.update(|window, cx| {
17310                    if parse_zed_link(&url, cx).is_some() {
17311                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
17312                    } else {
17313                        cx.open_url(&url);
17314                    }
17315                })?;
17316            }
17317
17318            anyhow::Ok(())
17319        });
17320
17321        url_finder.detach();
17322    }
17323
17324    pub fn open_selected_filename(
17325        &mut self,
17326        _: &OpenSelectedFilename,
17327        window: &mut Window,
17328        cx: &mut Context<Self>,
17329    ) {
17330        let Some(workspace) = self.workspace() else {
17331            return;
17332        };
17333
17334        let position = self.selections.newest_anchor().head();
17335
17336        let Some((buffer, buffer_position)) =
17337            self.buffer.read(cx).text_anchor_for_position(position, cx)
17338        else {
17339            return;
17340        };
17341
17342        let project = self.project.clone();
17343
17344        cx.spawn_in(window, async move |_, cx| {
17345            let result = find_file(&buffer, project, buffer_position, cx).await;
17346
17347            if let Some((_, path)) = result {
17348                workspace
17349                    .update_in(cx, |workspace, window, cx| {
17350                        workspace.open_resolved_path(path, window, cx)
17351                    })?
17352                    .await?;
17353            }
17354            anyhow::Ok(())
17355        })
17356        .detach();
17357    }
17358
17359    pub(crate) fn navigate_to_hover_links(
17360        &mut self,
17361        kind: Option<GotoDefinitionKind>,
17362        definitions: Vec<HoverLink>,
17363        split: bool,
17364        window: &mut Window,
17365        cx: &mut Context<Editor>,
17366    ) -> Task<Result<Navigated>> {
17367        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
17368        let mut first_url_or_file = None;
17369        let definitions: Vec<_> = definitions
17370            .into_iter()
17371            .filter_map(|def| match def {
17372                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
17373                HoverLink::InlayHint(lsp_location, server_id) => {
17374                    let computation =
17375                        self.compute_target_location(lsp_location, server_id, window, cx);
17376                    Some(cx.background_spawn(computation))
17377                }
17378                HoverLink::Url(url) => {
17379                    first_url_or_file = Some(Either::Left(url));
17380                    None
17381                }
17382                HoverLink::File(path) => {
17383                    first_url_or_file = Some(Either::Right(path));
17384                    None
17385                }
17386            })
17387            .collect();
17388
17389        let workspace = self.workspace();
17390
17391        cx.spawn_in(window, async move |editor, cx| {
17392            let locations: Vec<Location> = future::join_all(definitions)
17393                .await
17394                .into_iter()
17395                .filter_map(|location| location.transpose())
17396                .collect::<Result<_>>()
17397                .context("location tasks")?;
17398            let mut locations = cx.update(|_, cx| {
17399                locations
17400                    .into_iter()
17401                    .map(|location| {
17402                        let buffer = location.buffer.read(cx);
17403                        (location.buffer, location.range.to_point(buffer))
17404                    })
17405                    .into_group_map()
17406            })?;
17407            let mut num_locations = 0;
17408            for ranges in locations.values_mut() {
17409                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17410                ranges.dedup();
17411                num_locations += ranges.len();
17412            }
17413
17414            if num_locations > 1 {
17415                let tab_kind = match kind {
17416                    Some(GotoDefinitionKind::Implementation) => "Implementations",
17417                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
17418                    Some(GotoDefinitionKind::Declaration) => "Declarations",
17419                    Some(GotoDefinitionKind::Type) => "Types",
17420                };
17421                let title = editor
17422                    .update_in(cx, |_, _, cx| {
17423                        let target = locations
17424                            .iter()
17425                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17426                            .map(|(buffer, location)| {
17427                                buffer
17428                                    .read(cx)
17429                                    .text_for_range(location.clone())
17430                                    .collect::<String>()
17431                            })
17432                            .filter(|text| !text.contains('\n'))
17433                            .unique()
17434                            .take(3)
17435                            .join(", ");
17436                        if target.is_empty() {
17437                            tab_kind.to_owned()
17438                        } else {
17439                            format!("{tab_kind} for {target}")
17440                        }
17441                    })
17442                    .context("buffer title")?;
17443
17444                let Some(workspace) = workspace else {
17445                    return Ok(Navigated::No);
17446                };
17447
17448                let opened = workspace
17449                    .update_in(cx, |workspace, window, cx| {
17450                        let allow_preview = PreviewTabsSettings::get_global(cx)
17451                            .enable_preview_multibuffer_from_code_navigation;
17452                        Self::open_locations_in_multibuffer(
17453                            workspace,
17454                            locations,
17455                            title,
17456                            split,
17457                            allow_preview,
17458                            MultibufferSelectionMode::First,
17459                            window,
17460                            cx,
17461                        )
17462                    })
17463                    .is_ok();
17464
17465                anyhow::Ok(Navigated::from_bool(opened))
17466            } else if num_locations == 0 {
17467                // If there is one url or file, open it directly
17468                match first_url_or_file {
17469                    Some(Either::Left(url)) => {
17470                        cx.update(|_, cx| cx.open_url(&url))?;
17471                        Ok(Navigated::Yes)
17472                    }
17473                    Some(Either::Right(path)) => {
17474                        // TODO(andrew): respect preview tab settings
17475                        //               `enable_keep_preview_on_code_navigation` and
17476                        //               `enable_preview_file_from_code_navigation`
17477                        let Some(workspace) = workspace else {
17478                            return Ok(Navigated::No);
17479                        };
17480                        workspace
17481                            .update_in(cx, |workspace, window, cx| {
17482                                workspace.open_resolved_path(path, window, cx)
17483                            })?
17484                            .await?;
17485                        Ok(Navigated::Yes)
17486                    }
17487                    None => Ok(Navigated::No),
17488                }
17489            } else {
17490                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17491                let target_range = target_ranges.first().unwrap().clone();
17492
17493                editor.update_in(cx, |editor, window, cx| {
17494                    let range = target_range.to_point(target_buffer.read(cx));
17495                    let range = editor.range_for_match(&range);
17496                    let range = collapse_multiline_range(range);
17497
17498                    if !split
17499                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
17500                    {
17501                        editor.go_to_singleton_buffer_range(range, window, cx);
17502                    } else {
17503                        let Some(workspace) = workspace else {
17504                            return Navigated::No;
17505                        };
17506                        let pane = workspace.read(cx).active_pane().clone();
17507                        window.defer(cx, move |window, cx| {
17508                            let target_editor: Entity<Self> =
17509                                workspace.update(cx, |workspace, cx| {
17510                                    let pane = if split {
17511                                        workspace.adjacent_pane(window, cx)
17512                                    } else {
17513                                        workspace.active_pane().clone()
17514                                    };
17515
17516                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
17517                                    let keep_old_preview = preview_tabs_settings
17518                                        .enable_keep_preview_on_code_navigation;
17519                                    let allow_new_preview = preview_tabs_settings
17520                                        .enable_preview_file_from_code_navigation;
17521
17522                                    workspace.open_project_item(
17523                                        pane,
17524                                        target_buffer.clone(),
17525                                        true,
17526                                        true,
17527                                        keep_old_preview,
17528                                        allow_new_preview,
17529                                        window,
17530                                        cx,
17531                                    )
17532                                });
17533                            target_editor.update(cx, |target_editor, cx| {
17534                                // When selecting a definition in a different buffer, disable the nav history
17535                                // to avoid creating a history entry at the previous cursor location.
17536                                pane.update(cx, |pane, _| pane.disable_history());
17537                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17538                                pane.update(cx, |pane, _| pane.enable_history());
17539                            });
17540                        });
17541                    }
17542                    Navigated::Yes
17543                })
17544            }
17545        })
17546    }
17547
17548    fn compute_target_location(
17549        &self,
17550        lsp_location: lsp::Location,
17551        server_id: LanguageServerId,
17552        window: &mut Window,
17553        cx: &mut Context<Self>,
17554    ) -> Task<anyhow::Result<Option<Location>>> {
17555        let Some(project) = self.project.clone() else {
17556            return Task::ready(Ok(None));
17557        };
17558
17559        cx.spawn_in(window, async move |editor, cx| {
17560            let location_task = editor.update(cx, |_, cx| {
17561                project.update(cx, |project, cx| {
17562                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
17563                })
17564            })?;
17565            let location = Some({
17566                let target_buffer_handle = location_task.await.context("open local buffer")?;
17567                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
17568                    let target_start = target_buffer
17569                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
17570                    let target_end = target_buffer
17571                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
17572                    target_buffer.anchor_after(target_start)
17573                        ..target_buffer.anchor_before(target_end)
17574                })?;
17575                Location {
17576                    buffer: target_buffer_handle,
17577                    range,
17578                }
17579            });
17580            Ok(location)
17581        })
17582    }
17583
17584    fn go_to_next_reference(
17585        &mut self,
17586        _: &GoToNextReference,
17587        window: &mut Window,
17588        cx: &mut Context<Self>,
17589    ) {
17590        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
17591        if let Some(task) = task {
17592            task.detach();
17593        };
17594    }
17595
17596    fn go_to_prev_reference(
17597        &mut self,
17598        _: &GoToPreviousReference,
17599        window: &mut Window,
17600        cx: &mut Context<Self>,
17601    ) {
17602        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
17603        if let Some(task) = task {
17604            task.detach();
17605        };
17606    }
17607
17608    pub fn go_to_reference_before_or_after_position(
17609        &mut self,
17610        direction: Direction,
17611        count: usize,
17612        window: &mut Window,
17613        cx: &mut Context<Self>,
17614    ) -> Option<Task<Result<()>>> {
17615        let selection = self.selections.newest_anchor();
17616        let head = selection.head();
17617
17618        let multi_buffer = self.buffer.read(cx);
17619
17620        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
17621        let workspace = self.workspace()?;
17622        let project = workspace.read(cx).project().clone();
17623        let references =
17624            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
17625        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
17626            let Some(locations) = references.await? else {
17627                return Ok(());
17628            };
17629
17630            if locations.is_empty() {
17631                // totally normal - the cursor may be on something which is not
17632                // a symbol (e.g. a keyword)
17633                log::info!("no references found under cursor");
17634                return Ok(());
17635            }
17636
17637            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
17638
17639            let (locations, current_location_index) =
17640                multi_buffer.update(cx, |multi_buffer, cx| {
17641                    let mut locations = locations
17642                        .into_iter()
17643                        .filter_map(|loc| {
17644                            let start = multi_buffer.buffer_anchor_to_anchor(
17645                                &loc.buffer,
17646                                loc.range.start,
17647                                cx,
17648                            )?;
17649                            let end = multi_buffer.buffer_anchor_to_anchor(
17650                                &loc.buffer,
17651                                loc.range.end,
17652                                cx,
17653                            )?;
17654                            Some(start..end)
17655                        })
17656                        .collect::<Vec<_>>();
17657
17658                    let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17659                    // There is an O(n) implementation, but given this list will be
17660                    // small (usually <100 items), the extra O(log(n)) factor isn't
17661                    // worth the (surprisingly large amount of) extra complexity.
17662                    locations
17663                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
17664
17665                    let head_offset = head.to_offset(&multi_buffer_snapshot);
17666
17667                    let current_location_index = locations.iter().position(|loc| {
17668                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
17669                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
17670                    });
17671
17672                    (locations, current_location_index)
17673                })?;
17674
17675            let Some(current_location_index) = current_location_index else {
17676                // This indicates something has gone wrong, because we already
17677                // handle the "no references" case above
17678                log::error!(
17679                    "failed to find current reference under cursor. Total references: {}",
17680                    locations.len()
17681                );
17682                return Ok(());
17683            };
17684
17685            let destination_location_index = match direction {
17686                Direction::Next => (current_location_index + count) % locations.len(),
17687                Direction::Prev => {
17688                    (current_location_index + locations.len() - count % locations.len())
17689                        % locations.len()
17690                }
17691            };
17692
17693            // TODO(cameron): is this needed?
17694            // the thinking is to avoid "jumping to the current location" (avoid
17695            // polluting "jumplist" in vim terms)
17696            if current_location_index == destination_location_index {
17697                return Ok(());
17698            }
17699
17700            let Range { start, end } = locations[destination_location_index];
17701
17702            editor.update_in(cx, |editor, window, cx| {
17703                let effects = SelectionEffects::default();
17704
17705                editor.unfold_ranges(&[start..end], false, false, cx);
17706                editor.change_selections(effects, window, cx, |s| {
17707                    s.select_ranges([start..start]);
17708                });
17709            })?;
17710
17711            Ok(())
17712        }))
17713    }
17714
17715    pub fn find_all_references(
17716        &mut self,
17717        action: &FindAllReferences,
17718        window: &mut Window,
17719        cx: &mut Context<Self>,
17720    ) -> Option<Task<Result<Navigated>>> {
17721        let always_open_multibuffer = action.always_open_multibuffer;
17722        let selection = self.selections.newest_anchor();
17723        let multi_buffer = self.buffer.read(cx);
17724        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
17725        let selection_offset = selection.map(|anchor| anchor.to_offset(&multi_buffer_snapshot));
17726        let selection_point = selection.map(|anchor| anchor.to_point(&multi_buffer_snapshot));
17727        let head = selection_offset.head();
17728
17729        let head_anchor = multi_buffer_snapshot.anchor_at(
17730            head,
17731            if head < selection_offset.tail() {
17732                Bias::Right
17733            } else {
17734                Bias::Left
17735            },
17736        );
17737
17738        match self
17739            .find_all_references_task_sources
17740            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17741        {
17742            Ok(_) => {
17743                log::info!(
17744                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
17745                );
17746                return None;
17747            }
17748            Err(i) => {
17749                self.find_all_references_task_sources.insert(i, head_anchor);
17750            }
17751        }
17752
17753        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
17754        let workspace = self.workspace()?;
17755        let project = workspace.read(cx).project().clone();
17756        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
17757        Some(cx.spawn_in(window, async move |editor, cx| {
17758            let _cleanup = cx.on_drop(&editor, move |editor, _| {
17759                if let Ok(i) = editor
17760                    .find_all_references_task_sources
17761                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
17762                {
17763                    editor.find_all_references_task_sources.remove(i);
17764                }
17765            });
17766
17767            let Some(locations) = references.await? else {
17768                return anyhow::Ok(Navigated::No);
17769            };
17770            let mut locations = cx.update(|_, cx| {
17771                locations
17772                    .into_iter()
17773                    .map(|location| {
17774                        let buffer = location.buffer.read(cx);
17775                        (location.buffer, location.range.to_point(buffer))
17776                    })
17777                    // if special-casing the single-match case, remove ranges
17778                    // that intersect current selection
17779                    .filter(|(location_buffer, location)| {
17780                        if always_open_multibuffer || &buffer != location_buffer {
17781                            return true;
17782                        }
17783
17784                        !location.contains_inclusive(&selection_point.range())
17785                    })
17786                    .into_group_map()
17787            })?;
17788            if locations.is_empty() {
17789                return anyhow::Ok(Navigated::No);
17790            }
17791            for ranges in locations.values_mut() {
17792                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17793                ranges.dedup();
17794            }
17795            let mut num_locations = 0;
17796            for ranges in locations.values_mut() {
17797                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17798                ranges.dedup();
17799                num_locations += ranges.len();
17800            }
17801
17802            if num_locations == 1 && !always_open_multibuffer {
17803                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17804                let target_range = target_ranges.first().unwrap().clone();
17805
17806                return editor.update_in(cx, |editor, window, cx| {
17807                    let range = target_range.to_point(target_buffer.read(cx));
17808                    let range = editor.range_for_match(&range);
17809                    let range = range.start..range.start;
17810
17811                    if Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref() {
17812                        editor.go_to_singleton_buffer_range(range, window, cx);
17813                    } else {
17814                        let pane = workspace.read(cx).active_pane().clone();
17815                        window.defer(cx, move |window, cx| {
17816                            let target_editor: Entity<Self> =
17817                                workspace.update(cx, |workspace, cx| {
17818                                    let pane = workspace.active_pane().clone();
17819
17820                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
17821                                    let keep_old_preview = preview_tabs_settings
17822                                        .enable_keep_preview_on_code_navigation;
17823                                    let allow_new_preview = preview_tabs_settings
17824                                        .enable_preview_file_from_code_navigation;
17825
17826                                    workspace.open_project_item(
17827                                        pane,
17828                                        target_buffer.clone(),
17829                                        true,
17830                                        true,
17831                                        keep_old_preview,
17832                                        allow_new_preview,
17833                                        window,
17834                                        cx,
17835                                    )
17836                                });
17837                            target_editor.update(cx, |target_editor, cx| {
17838                                // When selecting a definition in a different buffer, disable the nav history
17839                                // to avoid creating a history entry at the previous cursor location.
17840                                pane.update(cx, |pane, _| pane.disable_history());
17841                                target_editor.go_to_singleton_buffer_range(range, window, cx);
17842                                pane.update(cx, |pane, _| pane.enable_history());
17843                            });
17844                        });
17845                    }
17846                    Navigated::No
17847                });
17848            }
17849
17850            workspace.update_in(cx, |workspace, window, cx| {
17851                let target = locations
17852                    .iter()
17853                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17854                    .map(|(buffer, location)| {
17855                        buffer
17856                            .read(cx)
17857                            .text_for_range(location.clone())
17858                            .collect::<String>()
17859                    })
17860                    .filter(|text| !text.contains('\n'))
17861                    .unique()
17862                    .take(3)
17863                    .join(", ");
17864                let title = if target.is_empty() {
17865                    "References".to_owned()
17866                } else {
17867                    format!("References to {target}")
17868                };
17869                let allow_preview = PreviewTabsSettings::get_global(cx)
17870                    .enable_preview_multibuffer_from_code_navigation;
17871                Self::open_locations_in_multibuffer(
17872                    workspace,
17873                    locations,
17874                    title,
17875                    false,
17876                    allow_preview,
17877                    MultibufferSelectionMode::First,
17878                    window,
17879                    cx,
17880                );
17881                Navigated::Yes
17882            })
17883        }))
17884    }
17885
17886    /// Opens a multibuffer with the given project locations in it.
17887    pub fn open_locations_in_multibuffer(
17888        workspace: &mut Workspace,
17889        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
17890        title: String,
17891        split: bool,
17892        allow_preview: bool,
17893        multibuffer_selection_mode: MultibufferSelectionMode,
17894        window: &mut Window,
17895        cx: &mut Context<Workspace>,
17896    ) {
17897        if locations.is_empty() {
17898            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
17899            return;
17900        }
17901
17902        let capability = workspace.project().read(cx).capability();
17903        let mut ranges = <Vec<Range<Anchor>>>::new();
17904
17905        // a key to find existing multibuffer editors with the same set of locations
17906        // to prevent us from opening more and more multibuffer tabs for searches and the like
17907        let mut key = (title.clone(), vec![]);
17908        let excerpt_buffer = cx.new(|cx| {
17909            let key = &mut key.1;
17910            let mut multibuffer = MultiBuffer::new(capability);
17911            for (buffer, mut ranges_for_buffer) in locations {
17912                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
17913                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
17914                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
17915                    PathKey::for_buffer(&buffer, cx),
17916                    buffer.clone(),
17917                    ranges_for_buffer,
17918                    multibuffer_context_lines(cx),
17919                    cx,
17920                );
17921                ranges.extend(new_ranges)
17922            }
17923
17924            multibuffer.with_title(title)
17925        });
17926        let existing = workspace.active_pane().update(cx, |pane, cx| {
17927            pane.items()
17928                .filter_map(|item| item.downcast::<Editor>())
17929                .find(|editor| {
17930                    editor
17931                        .read(cx)
17932                        .lookup_key
17933                        .as_ref()
17934                        .and_then(|it| {
17935                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
17936                        })
17937                        .is_some_and(|it| *it == key)
17938                })
17939        });
17940        let was_existing = existing.is_some();
17941        let editor = existing.unwrap_or_else(|| {
17942            cx.new(|cx| {
17943                let mut editor = Editor::for_multibuffer(
17944                    excerpt_buffer,
17945                    Some(workspace.project().clone()),
17946                    window,
17947                    cx,
17948                );
17949                editor.lookup_key = Some(Box::new(key));
17950                editor
17951            })
17952        });
17953        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
17954            MultibufferSelectionMode::First => {
17955                if let Some(first_range) = ranges.first() {
17956                    editor.change_selections(
17957                        SelectionEffects::no_scroll(),
17958                        window,
17959                        cx,
17960                        |selections| {
17961                            selections.clear_disjoint();
17962                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
17963                        },
17964                    );
17965                }
17966                editor.highlight_background::<Self>(
17967                    &ranges,
17968                    |_, theme| theme.colors().editor_highlighted_line_background,
17969                    cx,
17970                );
17971            }
17972            MultibufferSelectionMode::All => {
17973                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
17974                    selections.clear_disjoint();
17975                    selections.select_anchor_ranges(ranges);
17976                });
17977            }
17978        });
17979
17980        let item = Box::new(editor);
17981
17982        let pane = if split {
17983            workspace.adjacent_pane(window, cx)
17984        } else {
17985            workspace.active_pane().clone()
17986        };
17987        let activate_pane = split;
17988
17989        let mut destination_index = None;
17990        pane.update(cx, |pane, cx| {
17991            if allow_preview && !was_existing {
17992                destination_index = pane.replace_preview_item_id(item.item_id(), window, cx);
17993            }
17994            if was_existing && !allow_preview {
17995                pane.unpreview_item_if_preview(item.item_id());
17996            }
17997            pane.add_item(item, activate_pane, true, destination_index, window, cx);
17998        });
17999    }
18000
18001    pub fn rename(
18002        &mut self,
18003        _: &Rename,
18004        window: &mut Window,
18005        cx: &mut Context<Self>,
18006    ) -> Option<Task<Result<()>>> {
18007        use language::ToOffset as _;
18008
18009        let provider = self.semantics_provider.clone()?;
18010        let selection = self.selections.newest_anchor().clone();
18011        let (cursor_buffer, cursor_buffer_position) = self
18012            .buffer
18013            .read(cx)
18014            .text_anchor_for_position(selection.head(), cx)?;
18015        let (tail_buffer, cursor_buffer_position_end) = self
18016            .buffer
18017            .read(cx)
18018            .text_anchor_for_position(selection.tail(), cx)?;
18019        if tail_buffer != cursor_buffer {
18020            return None;
18021        }
18022
18023        let snapshot = cursor_buffer.read(cx).snapshot();
18024        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
18025        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
18026        let prepare_rename = provider
18027            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
18028            .unwrap_or_else(|| Task::ready(Ok(None)));
18029        drop(snapshot);
18030
18031        Some(cx.spawn_in(window, async move |this, cx| {
18032            let rename_range = if let Some(range) = prepare_rename.await? {
18033                Some(range)
18034            } else {
18035                this.update(cx, |this, cx| {
18036                    let buffer = this.buffer.read(cx).snapshot(cx);
18037                    let mut buffer_highlights = this
18038                        .document_highlights_for_position(selection.head(), &buffer)
18039                        .filter(|highlight| {
18040                            highlight.start.excerpt_id == selection.head().excerpt_id
18041                                && highlight.end.excerpt_id == selection.head().excerpt_id
18042                        });
18043                    buffer_highlights
18044                        .next()
18045                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
18046                })?
18047            };
18048            if let Some(rename_range) = rename_range {
18049                this.update_in(cx, |this, window, cx| {
18050                    let snapshot = cursor_buffer.read(cx).snapshot();
18051                    let rename_buffer_range = rename_range.to_offset(&snapshot);
18052                    let cursor_offset_in_rename_range =
18053                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
18054                    let cursor_offset_in_rename_range_end =
18055                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
18056
18057                    this.take_rename(false, window, cx);
18058                    let buffer = this.buffer.read(cx).read(cx);
18059                    let cursor_offset = selection.head().to_offset(&buffer);
18060                    let rename_start =
18061                        cursor_offset.saturating_sub_usize(cursor_offset_in_rename_range);
18062                    let rename_end = rename_start + rename_buffer_range.len();
18063                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
18064                    let mut old_highlight_id = None;
18065                    let old_name: Arc<str> = buffer
18066                        .chunks(rename_start..rename_end, true)
18067                        .map(|chunk| {
18068                            if old_highlight_id.is_none() {
18069                                old_highlight_id = chunk.syntax_highlight_id;
18070                            }
18071                            chunk.text
18072                        })
18073                        .collect::<String>()
18074                        .into();
18075
18076                    drop(buffer);
18077
18078                    // Position the selection in the rename editor so that it matches the current selection.
18079                    this.show_local_selections = false;
18080                    let rename_editor = cx.new(|cx| {
18081                        let mut editor = Editor::single_line(window, cx);
18082                        editor.buffer.update(cx, |buffer, cx| {
18083                            buffer.edit(
18084                                [(MultiBufferOffset(0)..MultiBufferOffset(0), old_name.clone())],
18085                                None,
18086                                cx,
18087                            )
18088                        });
18089                        let cursor_offset_in_rename_range =
18090                            MultiBufferOffset(cursor_offset_in_rename_range);
18091                        let cursor_offset_in_rename_range_end =
18092                            MultiBufferOffset(cursor_offset_in_rename_range_end);
18093                        let rename_selection_range = match cursor_offset_in_rename_range
18094                            .cmp(&cursor_offset_in_rename_range_end)
18095                        {
18096                            Ordering::Equal => {
18097                                editor.select_all(&SelectAll, window, cx);
18098                                return editor;
18099                            }
18100                            Ordering::Less => {
18101                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
18102                            }
18103                            Ordering::Greater => {
18104                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
18105                            }
18106                        };
18107                        if rename_selection_range.end.0 > old_name.len() {
18108                            editor.select_all(&SelectAll, window, cx);
18109                        } else {
18110                            editor.change_selections(Default::default(), window, cx, |s| {
18111                                s.select_ranges([rename_selection_range]);
18112                            });
18113                        }
18114                        editor
18115                    });
18116                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
18117                        if e == &EditorEvent::Focused {
18118                            cx.emit(EditorEvent::FocusedIn)
18119                        }
18120                    })
18121                    .detach();
18122
18123                    let write_highlights =
18124                        this.clear_background_highlights::<DocumentHighlightWrite>(cx);
18125                    let read_highlights =
18126                        this.clear_background_highlights::<DocumentHighlightRead>(cx);
18127                    let ranges = write_highlights
18128                        .iter()
18129                        .flat_map(|(_, ranges)| ranges.iter())
18130                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
18131                        .cloned()
18132                        .collect();
18133
18134                    this.highlight_text::<Rename>(
18135                        ranges,
18136                        HighlightStyle {
18137                            fade_out: Some(0.6),
18138                            ..Default::default()
18139                        },
18140                        cx,
18141                    );
18142                    let rename_focus_handle = rename_editor.focus_handle(cx);
18143                    window.focus(&rename_focus_handle);
18144                    let block_id = this.insert_blocks(
18145                        [BlockProperties {
18146                            style: BlockStyle::Flex,
18147                            placement: BlockPlacement::Below(range.start),
18148                            height: Some(1),
18149                            render: Arc::new({
18150                                let rename_editor = rename_editor.clone();
18151                                move |cx: &mut BlockContext| {
18152                                    let mut text_style = cx.editor_style.text.clone();
18153                                    if let Some(highlight_style) = old_highlight_id
18154                                        .and_then(|h| h.style(&cx.editor_style.syntax))
18155                                    {
18156                                        text_style = text_style.highlight(highlight_style);
18157                                    }
18158                                    div()
18159                                        .block_mouse_except_scroll()
18160                                        .pl(cx.anchor_x)
18161                                        .child(EditorElement::new(
18162                                            &rename_editor,
18163                                            EditorStyle {
18164                                                background: cx.theme().system().transparent,
18165                                                local_player: cx.editor_style.local_player,
18166                                                text: text_style,
18167                                                scrollbar_width: cx.editor_style.scrollbar_width,
18168                                                syntax: cx.editor_style.syntax.clone(),
18169                                                status: cx.editor_style.status.clone(),
18170                                                inlay_hints_style: HighlightStyle {
18171                                                    font_weight: Some(FontWeight::BOLD),
18172                                                    ..make_inlay_hints_style(cx.app)
18173                                                },
18174                                                edit_prediction_styles: make_suggestion_styles(
18175                                                    cx.app,
18176                                                ),
18177                                                ..EditorStyle::default()
18178                                            },
18179                                        ))
18180                                        .into_any_element()
18181                                }
18182                            }),
18183                            priority: 0,
18184                        }],
18185                        Some(Autoscroll::fit()),
18186                        cx,
18187                    )[0];
18188                    this.pending_rename = Some(RenameState {
18189                        range,
18190                        old_name,
18191                        editor: rename_editor,
18192                        block_id,
18193                    });
18194                })?;
18195            }
18196
18197            Ok(())
18198        }))
18199    }
18200
18201    pub fn confirm_rename(
18202        &mut self,
18203        _: &ConfirmRename,
18204        window: &mut Window,
18205        cx: &mut Context<Self>,
18206    ) -> Option<Task<Result<()>>> {
18207        let rename = self.take_rename(false, window, cx)?;
18208        let workspace = self.workspace()?.downgrade();
18209        let (buffer, start) = self
18210            .buffer
18211            .read(cx)
18212            .text_anchor_for_position(rename.range.start, cx)?;
18213        let (end_buffer, _) = self
18214            .buffer
18215            .read(cx)
18216            .text_anchor_for_position(rename.range.end, cx)?;
18217        if buffer != end_buffer {
18218            return None;
18219        }
18220
18221        let old_name = rename.old_name;
18222        let new_name = rename.editor.read(cx).text(cx);
18223
18224        let rename = self.semantics_provider.as_ref()?.perform_rename(
18225            &buffer,
18226            start,
18227            new_name.clone(),
18228            cx,
18229        )?;
18230
18231        Some(cx.spawn_in(window, async move |editor, cx| {
18232            let project_transaction = rename.await?;
18233            Self::open_project_transaction(
18234                &editor,
18235                workspace,
18236                project_transaction,
18237                format!("Rename: {}{}", old_name, new_name),
18238                cx,
18239            )
18240            .await?;
18241
18242            editor.update(cx, |editor, cx| {
18243                editor.refresh_document_highlights(cx);
18244            })?;
18245            Ok(())
18246        }))
18247    }
18248
18249    fn take_rename(
18250        &mut self,
18251        moving_cursor: bool,
18252        window: &mut Window,
18253        cx: &mut Context<Self>,
18254    ) -> Option<RenameState> {
18255        let rename = self.pending_rename.take()?;
18256        if rename.editor.focus_handle(cx).is_focused(window) {
18257            window.focus(&self.focus_handle);
18258        }
18259
18260        self.remove_blocks(
18261            [rename.block_id].into_iter().collect(),
18262            Some(Autoscroll::fit()),
18263            cx,
18264        );
18265        self.clear_highlights::<Rename>(cx);
18266        self.show_local_selections = true;
18267
18268        if moving_cursor {
18269            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
18270                editor
18271                    .selections
18272                    .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
18273                    .head()
18274            });
18275
18276            // Update the selection to match the position of the selection inside
18277            // the rename editor.
18278            let snapshot = self.buffer.read(cx).read(cx);
18279            let rename_range = rename.range.to_offset(&snapshot);
18280            let cursor_in_editor = snapshot
18281                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
18282                .min(rename_range.end);
18283            drop(snapshot);
18284
18285            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18286                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
18287            });
18288        } else {
18289            self.refresh_document_highlights(cx);
18290        }
18291
18292        Some(rename)
18293    }
18294
18295    pub fn pending_rename(&self) -> Option<&RenameState> {
18296        self.pending_rename.as_ref()
18297    }
18298
18299    fn format(
18300        &mut self,
18301        _: &Format,
18302        window: &mut Window,
18303        cx: &mut Context<Self>,
18304    ) -> Option<Task<Result<()>>> {
18305        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18306
18307        let project = match &self.project {
18308            Some(project) => project.clone(),
18309            None => return None,
18310        };
18311
18312        Some(self.perform_format(
18313            project,
18314            FormatTrigger::Manual,
18315            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
18316            window,
18317            cx,
18318        ))
18319    }
18320
18321    fn format_selections(
18322        &mut self,
18323        _: &FormatSelections,
18324        window: &mut Window,
18325        cx: &mut Context<Self>,
18326    ) -> Option<Task<Result<()>>> {
18327        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18328
18329        let project = match &self.project {
18330            Some(project) => project.clone(),
18331            None => return None,
18332        };
18333
18334        let ranges = self
18335            .selections
18336            .all_adjusted(&self.display_snapshot(cx))
18337            .into_iter()
18338            .map(|selection| selection.range())
18339            .collect_vec();
18340
18341        Some(self.perform_format(
18342            project,
18343            FormatTrigger::Manual,
18344            FormatTarget::Ranges(ranges),
18345            window,
18346            cx,
18347        ))
18348    }
18349
18350    fn perform_format(
18351        &mut self,
18352        project: Entity<Project>,
18353        trigger: FormatTrigger,
18354        target: FormatTarget,
18355        window: &mut Window,
18356        cx: &mut Context<Self>,
18357    ) -> Task<Result<()>> {
18358        let buffer = self.buffer.clone();
18359        let (buffers, target) = match target {
18360            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
18361            FormatTarget::Ranges(selection_ranges) => {
18362                let multi_buffer = buffer.read(cx);
18363                let snapshot = multi_buffer.read(cx);
18364                let mut buffers = HashSet::default();
18365                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
18366                    BTreeMap::new();
18367                for selection_range in selection_ranges {
18368                    for (buffer, buffer_range, _) in
18369                        snapshot.range_to_buffer_ranges(selection_range)
18370                    {
18371                        let buffer_id = buffer.remote_id();
18372                        let start = buffer.anchor_before(buffer_range.start);
18373                        let end = buffer.anchor_after(buffer_range.end);
18374                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
18375                        buffer_id_to_ranges
18376                            .entry(buffer_id)
18377                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
18378                            .or_insert_with(|| vec![start..end]);
18379                    }
18380                }
18381                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
18382            }
18383        };
18384
18385        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
18386        let selections_prev = transaction_id_prev
18387            .and_then(|transaction_id_prev| {
18388                // default to selections as they were after the last edit, if we have them,
18389                // instead of how they are now.
18390                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
18391                // will take you back to where you made the last edit, instead of staying where you scrolled
18392                self.selection_history
18393                    .transaction(transaction_id_prev)
18394                    .map(|t| t.0.clone())
18395            })
18396            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
18397
18398        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
18399        let format = project.update(cx, |project, cx| {
18400            project.format(buffers, target, true, trigger, cx)
18401        });
18402
18403        cx.spawn_in(window, async move |editor, cx| {
18404            let transaction = futures::select_biased! {
18405                transaction = format.log_err().fuse() => transaction,
18406                () = timeout => {
18407                    log::warn!("timed out waiting for formatting");
18408                    None
18409                }
18410            };
18411
18412            buffer
18413                .update(cx, |buffer, cx| {
18414                    if let Some(transaction) = transaction
18415                        && !buffer.is_singleton()
18416                    {
18417                        buffer.push_transaction(&transaction.0, cx);
18418                    }
18419                    cx.notify();
18420                })
18421                .ok();
18422
18423            if let Some(transaction_id_now) =
18424                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
18425            {
18426                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
18427                if has_new_transaction {
18428                    _ = editor.update(cx, |editor, _| {
18429                        editor
18430                            .selection_history
18431                            .insert_transaction(transaction_id_now, selections_prev);
18432                    });
18433                }
18434            }
18435
18436            Ok(())
18437        })
18438    }
18439
18440    fn organize_imports(
18441        &mut self,
18442        _: &OrganizeImports,
18443        window: &mut Window,
18444        cx: &mut Context<Self>,
18445    ) -> Option<Task<Result<()>>> {
18446        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18447        let project = match &self.project {
18448            Some(project) => project.clone(),
18449            None => return None,
18450        };
18451        Some(self.perform_code_action_kind(
18452            project,
18453            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
18454            window,
18455            cx,
18456        ))
18457    }
18458
18459    fn perform_code_action_kind(
18460        &mut self,
18461        project: Entity<Project>,
18462        kind: CodeActionKind,
18463        window: &mut Window,
18464        cx: &mut Context<Self>,
18465    ) -> Task<Result<()>> {
18466        let buffer = self.buffer.clone();
18467        let buffers = buffer.read(cx).all_buffers();
18468        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
18469        let apply_action = project.update(cx, |project, cx| {
18470            project.apply_code_action_kind(buffers, kind, true, cx)
18471        });
18472        cx.spawn_in(window, async move |_, cx| {
18473            let transaction = futures::select_biased! {
18474                () = timeout => {
18475                    log::warn!("timed out waiting for executing code action");
18476                    None
18477                }
18478                transaction = apply_action.log_err().fuse() => transaction,
18479            };
18480            buffer
18481                .update(cx, |buffer, cx| {
18482                    // check if we need this
18483                    if let Some(transaction) = transaction
18484                        && !buffer.is_singleton()
18485                    {
18486                        buffer.push_transaction(&transaction.0, cx);
18487                    }
18488                    cx.notify();
18489                })
18490                .ok();
18491            Ok(())
18492        })
18493    }
18494
18495    pub fn restart_language_server(
18496        &mut self,
18497        _: &RestartLanguageServer,
18498        _: &mut Window,
18499        cx: &mut Context<Self>,
18500    ) {
18501        if let Some(project) = self.project.clone() {
18502            self.buffer.update(cx, |multi_buffer, cx| {
18503                project.update(cx, |project, cx| {
18504                    project.restart_language_servers_for_buffers(
18505                        multi_buffer.all_buffers().into_iter().collect(),
18506                        HashSet::default(),
18507                        cx,
18508                    );
18509                });
18510            })
18511        }
18512    }
18513
18514    pub fn stop_language_server(
18515        &mut self,
18516        _: &StopLanguageServer,
18517        _: &mut Window,
18518        cx: &mut Context<Self>,
18519    ) {
18520        if let Some(project) = self.project.clone() {
18521            self.buffer.update(cx, |multi_buffer, cx| {
18522                project.update(cx, |project, cx| {
18523                    project.stop_language_servers_for_buffers(
18524                        multi_buffer.all_buffers().into_iter().collect(),
18525                        HashSet::default(),
18526                        cx,
18527                    );
18528                });
18529            });
18530            self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
18531        }
18532    }
18533
18534    fn cancel_language_server_work(
18535        workspace: &mut Workspace,
18536        _: &actions::CancelLanguageServerWork,
18537        _: &mut Window,
18538        cx: &mut Context<Workspace>,
18539    ) {
18540        let project = workspace.project();
18541        let buffers = workspace
18542            .active_item(cx)
18543            .and_then(|item| item.act_as::<Editor>(cx))
18544            .map_or(HashSet::default(), |editor| {
18545                editor.read(cx).buffer.read(cx).all_buffers()
18546            });
18547        project.update(cx, |project, cx| {
18548            project.cancel_language_server_work_for_buffers(buffers, cx);
18549        });
18550    }
18551
18552    fn show_character_palette(
18553        &mut self,
18554        _: &ShowCharacterPalette,
18555        window: &mut Window,
18556        _: &mut Context<Self>,
18557    ) {
18558        window.show_character_palette();
18559    }
18560
18561    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
18562        if !self.diagnostics_enabled() {
18563            return;
18564        }
18565
18566        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
18567            let buffer = self.buffer.read(cx).snapshot(cx);
18568            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
18569            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
18570            let is_valid = buffer
18571                .diagnostics_in_range::<MultiBufferOffset>(primary_range_start..primary_range_end)
18572                .any(|entry| {
18573                    entry.diagnostic.is_primary
18574                        && !entry.range.is_empty()
18575                        && entry.range.start == primary_range_start
18576                        && entry.diagnostic.message == active_diagnostics.active_message
18577                });
18578
18579            if !is_valid {
18580                self.dismiss_diagnostics(cx);
18581            }
18582        }
18583    }
18584
18585    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
18586        match &self.active_diagnostics {
18587            ActiveDiagnostic::Group(group) => Some(group),
18588            _ => None,
18589        }
18590    }
18591
18592    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
18593        if !self.diagnostics_enabled() {
18594            return;
18595        }
18596        self.dismiss_diagnostics(cx);
18597        self.active_diagnostics = ActiveDiagnostic::All;
18598    }
18599
18600    fn activate_diagnostics(
18601        &mut self,
18602        buffer_id: BufferId,
18603        diagnostic: DiagnosticEntryRef<'_, MultiBufferOffset>,
18604        window: &mut Window,
18605        cx: &mut Context<Self>,
18606    ) {
18607        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18608            return;
18609        }
18610        self.dismiss_diagnostics(cx);
18611        let snapshot = self.snapshot(window, cx);
18612        let buffer = self.buffer.read(cx).snapshot(cx);
18613        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
18614            return;
18615        };
18616
18617        let diagnostic_group = buffer
18618            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
18619            .collect::<Vec<_>>();
18620
18621        let language_registry = self
18622            .project()
18623            .map(|project| project.read(cx).languages().clone());
18624
18625        let blocks = renderer.render_group(
18626            diagnostic_group,
18627            buffer_id,
18628            snapshot,
18629            cx.weak_entity(),
18630            language_registry,
18631            cx,
18632        );
18633
18634        let blocks = self.display_map.update(cx, |display_map, cx| {
18635            display_map.insert_blocks(blocks, cx).into_iter().collect()
18636        });
18637        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
18638            active_range: buffer.anchor_before(diagnostic.range.start)
18639                ..buffer.anchor_after(diagnostic.range.end),
18640            active_message: diagnostic.diagnostic.message.clone(),
18641            group_id: diagnostic.diagnostic.group_id,
18642            blocks,
18643        });
18644        cx.notify();
18645    }
18646
18647    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
18648        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
18649            return;
18650        };
18651
18652        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
18653        if let ActiveDiagnostic::Group(group) = prev {
18654            self.display_map.update(cx, |display_map, cx| {
18655                display_map.remove_blocks(group.blocks, cx);
18656            });
18657            cx.notify();
18658        }
18659    }
18660
18661    /// Disable inline diagnostics rendering for this editor.
18662    pub fn disable_inline_diagnostics(&mut self) {
18663        self.inline_diagnostics_enabled = false;
18664        self.inline_diagnostics_update = Task::ready(());
18665        self.inline_diagnostics.clear();
18666    }
18667
18668    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
18669        self.diagnostics_enabled = false;
18670        self.dismiss_diagnostics(cx);
18671        self.inline_diagnostics_update = Task::ready(());
18672        self.inline_diagnostics.clear();
18673    }
18674
18675    pub fn disable_word_completions(&mut self) {
18676        self.word_completions_enabled = false;
18677    }
18678
18679    pub fn diagnostics_enabled(&self) -> bool {
18680        self.diagnostics_enabled && self.mode.is_full()
18681    }
18682
18683    pub fn inline_diagnostics_enabled(&self) -> bool {
18684        self.inline_diagnostics_enabled && self.diagnostics_enabled()
18685    }
18686
18687    pub fn show_inline_diagnostics(&self) -> bool {
18688        self.show_inline_diagnostics
18689    }
18690
18691    pub fn toggle_inline_diagnostics(
18692        &mut self,
18693        _: &ToggleInlineDiagnostics,
18694        window: &mut Window,
18695        cx: &mut Context<Editor>,
18696    ) {
18697        self.show_inline_diagnostics = !self.show_inline_diagnostics;
18698        self.refresh_inline_diagnostics(false, window, cx);
18699    }
18700
18701    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
18702        self.diagnostics_max_severity = severity;
18703        self.display_map.update(cx, |display_map, _| {
18704            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
18705        });
18706    }
18707
18708    pub fn toggle_diagnostics(
18709        &mut self,
18710        _: &ToggleDiagnostics,
18711        window: &mut Window,
18712        cx: &mut Context<Editor>,
18713    ) {
18714        if !self.diagnostics_enabled() {
18715            return;
18716        }
18717
18718        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18719            EditorSettings::get_global(cx)
18720                .diagnostics_max_severity
18721                .filter(|severity| severity != &DiagnosticSeverity::Off)
18722                .unwrap_or(DiagnosticSeverity::Hint)
18723        } else {
18724            DiagnosticSeverity::Off
18725        };
18726        self.set_max_diagnostics_severity(new_severity, cx);
18727        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
18728            self.active_diagnostics = ActiveDiagnostic::None;
18729            self.inline_diagnostics_update = Task::ready(());
18730            self.inline_diagnostics.clear();
18731        } else {
18732            self.refresh_inline_diagnostics(false, window, cx);
18733        }
18734
18735        cx.notify();
18736    }
18737
18738    pub fn toggle_minimap(
18739        &mut self,
18740        _: &ToggleMinimap,
18741        window: &mut Window,
18742        cx: &mut Context<Editor>,
18743    ) {
18744        if self.supports_minimap(cx) {
18745            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
18746        }
18747    }
18748
18749    fn refresh_inline_diagnostics(
18750        &mut self,
18751        debounce: bool,
18752        window: &mut Window,
18753        cx: &mut Context<Self>,
18754    ) {
18755        let max_severity = ProjectSettings::get_global(cx)
18756            .diagnostics
18757            .inline
18758            .max_severity
18759            .unwrap_or(self.diagnostics_max_severity);
18760
18761        if !self.inline_diagnostics_enabled()
18762            || !self.diagnostics_enabled()
18763            || !self.show_inline_diagnostics
18764            || max_severity == DiagnosticSeverity::Off
18765        {
18766            self.inline_diagnostics_update = Task::ready(());
18767            self.inline_diagnostics.clear();
18768            return;
18769        }
18770
18771        let debounce_ms = ProjectSettings::get_global(cx)
18772            .diagnostics
18773            .inline
18774            .update_debounce_ms;
18775        let debounce = if debounce && debounce_ms > 0 {
18776            Some(Duration::from_millis(debounce_ms))
18777        } else {
18778            None
18779        };
18780        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
18781            if let Some(debounce) = debounce {
18782                cx.background_executor().timer(debounce).await;
18783            }
18784            let Some(snapshot) = editor.upgrade().and_then(|editor| {
18785                editor
18786                    .update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
18787                    .ok()
18788            }) else {
18789                return;
18790            };
18791
18792            let new_inline_diagnostics = cx
18793                .background_spawn(async move {
18794                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
18795                    for diagnostic_entry in
18796                        snapshot.diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
18797                    {
18798                        let message = diagnostic_entry
18799                            .diagnostic
18800                            .message
18801                            .split_once('\n')
18802                            .map(|(line, _)| line)
18803                            .map(SharedString::new)
18804                            .unwrap_or_else(|| {
18805                                SharedString::new(&*diagnostic_entry.diagnostic.message)
18806                            });
18807                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
18808                        let (Ok(i) | Err(i)) = inline_diagnostics
18809                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
18810                        inline_diagnostics.insert(
18811                            i,
18812                            (
18813                                start_anchor,
18814                                InlineDiagnostic {
18815                                    message,
18816                                    group_id: diagnostic_entry.diagnostic.group_id,
18817                                    start: diagnostic_entry.range.start.to_point(&snapshot),
18818                                    is_primary: diagnostic_entry.diagnostic.is_primary,
18819                                    severity: diagnostic_entry.diagnostic.severity,
18820                                },
18821                            ),
18822                        );
18823                    }
18824                    inline_diagnostics
18825                })
18826                .await;
18827
18828            editor
18829                .update(cx, |editor, cx| {
18830                    editor.inline_diagnostics = new_inline_diagnostics;
18831                    cx.notify();
18832                })
18833                .ok();
18834        });
18835    }
18836
18837    fn pull_diagnostics(
18838        &mut self,
18839        buffer_id: Option<BufferId>,
18840        window: &Window,
18841        cx: &mut Context<Self>,
18842    ) -> Option<()> {
18843        if self.ignore_lsp_data() || !self.diagnostics_enabled() {
18844            return None;
18845        }
18846        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
18847            .diagnostics
18848            .lsp_pull_diagnostics;
18849        if !pull_diagnostics_settings.enabled {
18850            return None;
18851        }
18852        let project = self.project()?.downgrade();
18853
18854        let mut edited_buffer_ids = HashSet::default();
18855        let mut edited_worktree_ids = HashSet::default();
18856        let edited_buffers = match buffer_id {
18857            Some(buffer_id) => {
18858                let buffer = self.buffer().read(cx).buffer(buffer_id)?;
18859                let worktree_id = buffer.read(cx).file().map(|f| f.worktree_id(cx))?;
18860                edited_buffer_ids.insert(buffer.read(cx).remote_id());
18861                edited_worktree_ids.insert(worktree_id);
18862                vec![buffer]
18863            }
18864            None => self
18865                .buffer()
18866                .read(cx)
18867                .all_buffers()
18868                .into_iter()
18869                .filter(|buffer| {
18870                    let buffer = buffer.read(cx);
18871                    match buffer.file().map(|f| f.worktree_id(cx)) {
18872                        Some(worktree_id) => {
18873                            edited_buffer_ids.insert(buffer.remote_id());
18874                            edited_worktree_ids.insert(worktree_id);
18875                            true
18876                        }
18877                        None => false,
18878                    }
18879                })
18880                .collect::<Vec<_>>(),
18881        };
18882
18883        if edited_buffers.is_empty() {
18884            self.pull_diagnostics_task = Task::ready(());
18885            self.pull_diagnostics_background_task = Task::ready(());
18886            return None;
18887        }
18888
18889        let mut already_used_buffers = HashSet::default();
18890        let related_open_buffers = self
18891            .workspace
18892            .as_ref()
18893            .and_then(|(workspace, _)| workspace.upgrade())
18894            .into_iter()
18895            .flat_map(|workspace| workspace.read(cx).panes())
18896            .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
18897            .filter(|editor| editor != &cx.entity())
18898            .flat_map(|editor| editor.read(cx).buffer().read(cx).all_buffers())
18899            .filter(|buffer| {
18900                let buffer = buffer.read(cx);
18901                let buffer_id = buffer.remote_id();
18902                if already_used_buffers.insert(buffer_id) {
18903                    if let Some(worktree_id) = buffer.file().map(|f| f.worktree_id(cx)) {
18904                        return !edited_buffer_ids.contains(&buffer_id)
18905                            && !edited_worktree_ids.contains(&worktree_id);
18906                    }
18907                }
18908                false
18909            })
18910            .collect::<Vec<_>>();
18911
18912        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
18913        let make_spawn = |buffers: Vec<Entity<Buffer>>, delay: Duration| {
18914            if buffers.is_empty() {
18915                return Task::ready(());
18916            }
18917            let project_weak = project.clone();
18918            cx.spawn_in(window, async move |_, cx| {
18919                cx.background_executor().timer(delay).await;
18920
18921                let Ok(mut pull_diagnostics_tasks) = cx.update(|_, cx| {
18922                    buffers
18923                        .into_iter()
18924                        .filter_map(|buffer| {
18925                            project_weak
18926                                .update(cx, |project, cx| {
18927                                    project.lsp_store().update(cx, |lsp_store, cx| {
18928                                        lsp_store.pull_diagnostics_for_buffer(buffer, cx)
18929                                    })
18930                                })
18931                                .ok()
18932                        })
18933                        .collect::<FuturesUnordered<_>>()
18934                }) else {
18935                    return;
18936                };
18937
18938                while let Some(pull_task) = pull_diagnostics_tasks.next().await {
18939                    if let Err(e) = pull_task {
18940                        log::error!("Failed to update project diagnostics: {e:#}");
18941                    }
18942                }
18943            })
18944        };
18945
18946        self.pull_diagnostics_task = make_spawn(edited_buffers, debounce);
18947        self.pull_diagnostics_background_task = make_spawn(related_open_buffers, debounce * 2);
18948
18949        Some(())
18950    }
18951
18952    pub fn set_selections_from_remote(
18953        &mut self,
18954        selections: Vec<Selection<Anchor>>,
18955        pending_selection: Option<Selection<Anchor>>,
18956        window: &mut Window,
18957        cx: &mut Context<Self>,
18958    ) {
18959        let old_cursor_position = self.selections.newest_anchor().head();
18960        self.selections
18961            .change_with(&self.display_snapshot(cx), |s| {
18962                s.select_anchors(selections);
18963                if let Some(pending_selection) = pending_selection {
18964                    s.set_pending(pending_selection, SelectMode::Character);
18965                } else {
18966                    s.clear_pending();
18967                }
18968            });
18969        self.selections_did_change(
18970            false,
18971            &old_cursor_position,
18972            SelectionEffects::default(),
18973            window,
18974            cx,
18975        );
18976    }
18977
18978    pub fn transact(
18979        &mut self,
18980        window: &mut Window,
18981        cx: &mut Context<Self>,
18982        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
18983    ) -> Option<TransactionId> {
18984        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
18985            this.start_transaction_at(Instant::now(), window, cx);
18986            update(this, window, cx);
18987            this.end_transaction_at(Instant::now(), cx)
18988        })
18989    }
18990
18991    pub fn start_transaction_at(
18992        &mut self,
18993        now: Instant,
18994        window: &mut Window,
18995        cx: &mut Context<Self>,
18996    ) -> Option<TransactionId> {
18997        self.end_selection(window, cx);
18998        if let Some(tx_id) = self
18999            .buffer
19000            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
19001        {
19002            self.selection_history
19003                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
19004            cx.emit(EditorEvent::TransactionBegun {
19005                transaction_id: tx_id,
19006            });
19007            Some(tx_id)
19008        } else {
19009            None
19010        }
19011    }
19012
19013    pub fn end_transaction_at(
19014        &mut self,
19015        now: Instant,
19016        cx: &mut Context<Self>,
19017    ) -> Option<TransactionId> {
19018        if let Some(transaction_id) = self
19019            .buffer
19020            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
19021        {
19022            if let Some((_, end_selections)) =
19023                self.selection_history.transaction_mut(transaction_id)
19024            {
19025                *end_selections = Some(self.selections.disjoint_anchors_arc());
19026            } else {
19027                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
19028            }
19029
19030            cx.emit(EditorEvent::Edited { transaction_id });
19031            Some(transaction_id)
19032        } else {
19033            None
19034        }
19035    }
19036
19037    pub fn modify_transaction_selection_history(
19038        &mut self,
19039        transaction_id: TransactionId,
19040        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
19041    ) -> bool {
19042        self.selection_history
19043            .transaction_mut(transaction_id)
19044            .map(modify)
19045            .is_some()
19046    }
19047
19048    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
19049        if self.selection_mark_mode {
19050            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
19051                s.move_with(|_, sel| {
19052                    sel.collapse_to(sel.head(), SelectionGoal::None);
19053                });
19054            })
19055        }
19056        self.selection_mark_mode = true;
19057        cx.notify();
19058    }
19059
19060    pub fn swap_selection_ends(
19061        &mut self,
19062        _: &actions::SwapSelectionEnds,
19063        window: &mut Window,
19064        cx: &mut Context<Self>,
19065    ) {
19066        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
19067            s.move_with(|_, sel| {
19068                if sel.start != sel.end {
19069                    sel.reversed = !sel.reversed
19070                }
19071            });
19072        });
19073        self.request_autoscroll(Autoscroll::newest(), cx);
19074        cx.notify();
19075    }
19076
19077    pub fn toggle_focus(
19078        workspace: &mut Workspace,
19079        _: &actions::ToggleFocus,
19080        window: &mut Window,
19081        cx: &mut Context<Workspace>,
19082    ) {
19083        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
19084            return;
19085        };
19086        workspace.activate_item(&item, true, true, window, cx);
19087    }
19088
19089    pub fn toggle_fold(
19090        &mut self,
19091        _: &actions::ToggleFold,
19092        window: &mut Window,
19093        cx: &mut Context<Self>,
19094    ) {
19095        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19096            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19097            let selection = self.selections.newest::<Point>(&display_map);
19098
19099            let range = if selection.is_empty() {
19100                let point = selection.head().to_display_point(&display_map);
19101                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
19102                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
19103                    .to_point(&display_map);
19104                start..end
19105            } else {
19106                selection.range()
19107            };
19108            if display_map.folds_in_range(range).next().is_some() {
19109                self.unfold_lines(&Default::default(), window, cx)
19110            } else {
19111                self.fold(&Default::default(), window, cx)
19112            }
19113        } else {
19114            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19115            let buffer_ids: HashSet<_> = self
19116                .selections
19117                .disjoint_anchor_ranges()
19118                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19119                .collect();
19120
19121            let should_unfold = buffer_ids
19122                .iter()
19123                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
19124
19125            for buffer_id in buffer_ids {
19126                if should_unfold {
19127                    self.unfold_buffer(buffer_id, cx);
19128                } else {
19129                    self.fold_buffer(buffer_id, cx);
19130                }
19131            }
19132        }
19133    }
19134
19135    pub fn toggle_fold_recursive(
19136        &mut self,
19137        _: &actions::ToggleFoldRecursive,
19138        window: &mut Window,
19139        cx: &mut Context<Self>,
19140    ) {
19141        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
19142
19143        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19144        let range = if selection.is_empty() {
19145            let point = selection.head().to_display_point(&display_map);
19146            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
19147            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
19148                .to_point(&display_map);
19149            start..end
19150        } else {
19151            selection.range()
19152        };
19153        if display_map.folds_in_range(range).next().is_some() {
19154            self.unfold_recursive(&Default::default(), window, cx)
19155        } else {
19156            self.fold_recursive(&Default::default(), window, cx)
19157        }
19158    }
19159
19160    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
19161        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19162            let mut to_fold = Vec::new();
19163            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19164            let selections = self.selections.all_adjusted(&display_map);
19165
19166            for selection in selections {
19167                let range = selection.range().sorted();
19168                let buffer_start_row = range.start.row;
19169
19170                if range.start.row != range.end.row {
19171                    let mut found = false;
19172                    let mut row = range.start.row;
19173                    while row <= range.end.row {
19174                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19175                        {
19176                            found = true;
19177                            row = crease.range().end.row + 1;
19178                            to_fold.push(crease);
19179                        } else {
19180                            row += 1
19181                        }
19182                    }
19183                    if found {
19184                        continue;
19185                    }
19186                }
19187
19188                for row in (0..=range.start.row).rev() {
19189                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19190                        && crease.range().end.row >= buffer_start_row
19191                    {
19192                        to_fold.push(crease);
19193                        if row <= range.start.row {
19194                            break;
19195                        }
19196                    }
19197                }
19198            }
19199
19200            self.fold_creases(to_fold, true, window, cx);
19201        } else {
19202            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19203            let buffer_ids = self
19204                .selections
19205                .disjoint_anchor_ranges()
19206                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19207                .collect::<HashSet<_>>();
19208            for buffer_id in buffer_ids {
19209                self.fold_buffer(buffer_id, cx);
19210            }
19211        }
19212    }
19213
19214    pub fn toggle_fold_all(
19215        &mut self,
19216        _: &actions::ToggleFoldAll,
19217        window: &mut Window,
19218        cx: &mut Context<Self>,
19219    ) {
19220        if self.buffer.read(cx).is_singleton() {
19221            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19222            let has_folds = display_map
19223                .folds_in_range(MultiBufferOffset(0)..display_map.buffer_snapshot().len())
19224                .next()
19225                .is_some();
19226
19227            if has_folds {
19228                self.unfold_all(&actions::UnfoldAll, window, cx);
19229            } else {
19230                self.fold_all(&actions::FoldAll, window, cx);
19231            }
19232        } else {
19233            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
19234            let should_unfold = buffer_ids
19235                .iter()
19236                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
19237
19238            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
19239                editor
19240                    .update_in(cx, |editor, _, cx| {
19241                        for buffer_id in buffer_ids {
19242                            if should_unfold {
19243                                editor.unfold_buffer(buffer_id, cx);
19244                            } else {
19245                                editor.fold_buffer(buffer_id, cx);
19246                            }
19247                        }
19248                    })
19249                    .ok();
19250            });
19251        }
19252    }
19253
19254    fn fold_at_level(
19255        &mut self,
19256        fold_at: &FoldAtLevel,
19257        window: &mut Window,
19258        cx: &mut Context<Self>,
19259    ) {
19260        if !self.buffer.read(cx).is_singleton() {
19261            return;
19262        }
19263
19264        let fold_at_level = fold_at.0;
19265        let snapshot = self.buffer.read(cx).snapshot(cx);
19266        let mut to_fold = Vec::new();
19267        let mut stack = vec![(0, snapshot.max_row().0, 1)];
19268
19269        let row_ranges_to_keep: Vec<Range<u32>> = self
19270            .selections
19271            .all::<Point>(&self.display_snapshot(cx))
19272            .into_iter()
19273            .map(|sel| sel.start.row..sel.end.row)
19274            .collect();
19275
19276        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
19277            while start_row < end_row {
19278                match self
19279                    .snapshot(window, cx)
19280                    .crease_for_buffer_row(MultiBufferRow(start_row))
19281                {
19282                    Some(crease) => {
19283                        let nested_start_row = crease.range().start.row + 1;
19284                        let nested_end_row = crease.range().end.row;
19285
19286                        if current_level < fold_at_level {
19287                            stack.push((nested_start_row, nested_end_row, current_level + 1));
19288                        } else if current_level == fold_at_level {
19289                            // Fold iff there is no selection completely contained within the fold region
19290                            if !row_ranges_to_keep.iter().any(|selection| {
19291                                selection.end >= nested_start_row
19292                                    && selection.start <= nested_end_row
19293                            }) {
19294                                to_fold.push(crease);
19295                            }
19296                        }
19297
19298                        start_row = nested_end_row + 1;
19299                    }
19300                    None => start_row += 1,
19301                }
19302            }
19303        }
19304
19305        self.fold_creases(to_fold, true, window, cx);
19306    }
19307
19308    pub fn fold_at_level_1(
19309        &mut self,
19310        _: &actions::FoldAtLevel1,
19311        window: &mut Window,
19312        cx: &mut Context<Self>,
19313    ) {
19314        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
19315    }
19316
19317    pub fn fold_at_level_2(
19318        &mut self,
19319        _: &actions::FoldAtLevel2,
19320        window: &mut Window,
19321        cx: &mut Context<Self>,
19322    ) {
19323        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
19324    }
19325
19326    pub fn fold_at_level_3(
19327        &mut self,
19328        _: &actions::FoldAtLevel3,
19329        window: &mut Window,
19330        cx: &mut Context<Self>,
19331    ) {
19332        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
19333    }
19334
19335    pub fn fold_at_level_4(
19336        &mut self,
19337        _: &actions::FoldAtLevel4,
19338        window: &mut Window,
19339        cx: &mut Context<Self>,
19340    ) {
19341        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
19342    }
19343
19344    pub fn fold_at_level_5(
19345        &mut self,
19346        _: &actions::FoldAtLevel5,
19347        window: &mut Window,
19348        cx: &mut Context<Self>,
19349    ) {
19350        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
19351    }
19352
19353    pub fn fold_at_level_6(
19354        &mut self,
19355        _: &actions::FoldAtLevel6,
19356        window: &mut Window,
19357        cx: &mut Context<Self>,
19358    ) {
19359        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
19360    }
19361
19362    pub fn fold_at_level_7(
19363        &mut self,
19364        _: &actions::FoldAtLevel7,
19365        window: &mut Window,
19366        cx: &mut Context<Self>,
19367    ) {
19368        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
19369    }
19370
19371    pub fn fold_at_level_8(
19372        &mut self,
19373        _: &actions::FoldAtLevel8,
19374        window: &mut Window,
19375        cx: &mut Context<Self>,
19376    ) {
19377        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
19378    }
19379
19380    pub fn fold_at_level_9(
19381        &mut self,
19382        _: &actions::FoldAtLevel9,
19383        window: &mut Window,
19384        cx: &mut Context<Self>,
19385    ) {
19386        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
19387    }
19388
19389    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
19390        if self.buffer.read(cx).is_singleton() {
19391            let mut fold_ranges = Vec::new();
19392            let snapshot = self.buffer.read(cx).snapshot(cx);
19393
19394            for row in 0..snapshot.max_row().0 {
19395                if let Some(foldable_range) = self
19396                    .snapshot(window, cx)
19397                    .crease_for_buffer_row(MultiBufferRow(row))
19398                {
19399                    fold_ranges.push(foldable_range);
19400                }
19401            }
19402
19403            self.fold_creases(fold_ranges, true, window, cx);
19404        } else {
19405            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
19406                editor
19407                    .update_in(cx, |editor, _, cx| {
19408                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19409                            editor.fold_buffer(buffer_id, cx);
19410                        }
19411                    })
19412                    .ok();
19413            });
19414        }
19415    }
19416
19417    pub fn fold_function_bodies(
19418        &mut self,
19419        _: &actions::FoldFunctionBodies,
19420        window: &mut Window,
19421        cx: &mut Context<Self>,
19422    ) {
19423        let snapshot = self.buffer.read(cx).snapshot(cx);
19424
19425        let ranges = snapshot
19426            .text_object_ranges(
19427                MultiBufferOffset(0)..snapshot.len(),
19428                TreeSitterOptions::default(),
19429            )
19430            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
19431            .collect::<Vec<_>>();
19432
19433        let creases = ranges
19434            .into_iter()
19435            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
19436            .collect();
19437
19438        self.fold_creases(creases, true, window, cx);
19439    }
19440
19441    pub fn fold_recursive(
19442        &mut self,
19443        _: &actions::FoldRecursive,
19444        window: &mut Window,
19445        cx: &mut Context<Self>,
19446    ) {
19447        let mut to_fold = Vec::new();
19448        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19449        let selections = self.selections.all_adjusted(&display_map);
19450
19451        for selection in selections {
19452            let range = selection.range().sorted();
19453            let buffer_start_row = range.start.row;
19454
19455            if range.start.row != range.end.row {
19456                let mut found = false;
19457                for row in range.start.row..=range.end.row {
19458                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19459                        found = true;
19460                        to_fold.push(crease);
19461                    }
19462                }
19463                if found {
19464                    continue;
19465                }
19466            }
19467
19468            for row in (0..=range.start.row).rev() {
19469                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19470                    if crease.range().end.row >= buffer_start_row {
19471                        to_fold.push(crease);
19472                    } else {
19473                        break;
19474                    }
19475                }
19476            }
19477        }
19478
19479        self.fold_creases(to_fold, true, window, cx);
19480    }
19481
19482    pub fn fold_at(
19483        &mut self,
19484        buffer_row: MultiBufferRow,
19485        window: &mut Window,
19486        cx: &mut Context<Self>,
19487    ) {
19488        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19489
19490        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
19491            let autoscroll = self
19492                .selections
19493                .all::<Point>(&display_map)
19494                .iter()
19495                .any(|selection| crease.range().overlaps(&selection.range()));
19496
19497            self.fold_creases(vec![crease], autoscroll, window, cx);
19498        }
19499    }
19500
19501    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
19502        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19503            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19504            let buffer = display_map.buffer_snapshot();
19505            let selections = self.selections.all::<Point>(&display_map);
19506            let ranges = selections
19507                .iter()
19508                .map(|s| {
19509                    let range = s.display_range(&display_map).sorted();
19510                    let mut start = range.start.to_point(&display_map);
19511                    let mut end = range.end.to_point(&display_map);
19512                    start.column = 0;
19513                    end.column = buffer.line_len(MultiBufferRow(end.row));
19514                    start..end
19515                })
19516                .collect::<Vec<_>>();
19517
19518            self.unfold_ranges(&ranges, true, true, cx);
19519        } else {
19520            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19521            let buffer_ids = self
19522                .selections
19523                .disjoint_anchor_ranges()
19524                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19525                .collect::<HashSet<_>>();
19526            for buffer_id in buffer_ids {
19527                self.unfold_buffer(buffer_id, cx);
19528            }
19529        }
19530    }
19531
19532    pub fn unfold_recursive(
19533        &mut self,
19534        _: &UnfoldRecursive,
19535        _window: &mut Window,
19536        cx: &mut Context<Self>,
19537    ) {
19538        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19539        let selections = self.selections.all::<Point>(&display_map);
19540        let ranges = selections
19541            .iter()
19542            .map(|s| {
19543                let mut range = s.display_range(&display_map).sorted();
19544                *range.start.column_mut() = 0;
19545                *range.end.column_mut() = display_map.line_len(range.end.row());
19546                let start = range.start.to_point(&display_map);
19547                let end = range.end.to_point(&display_map);
19548                start..end
19549            })
19550            .collect::<Vec<_>>();
19551
19552        self.unfold_ranges(&ranges, true, true, cx);
19553    }
19554
19555    pub fn unfold_at(
19556        &mut self,
19557        buffer_row: MultiBufferRow,
19558        _window: &mut Window,
19559        cx: &mut Context<Self>,
19560    ) {
19561        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19562
19563        let intersection_range = Point::new(buffer_row.0, 0)
19564            ..Point::new(
19565                buffer_row.0,
19566                display_map.buffer_snapshot().line_len(buffer_row),
19567            );
19568
19569        let autoscroll = self
19570            .selections
19571            .all::<Point>(&display_map)
19572            .iter()
19573            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
19574
19575        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
19576    }
19577
19578    pub fn unfold_all(
19579        &mut self,
19580        _: &actions::UnfoldAll,
19581        _window: &mut Window,
19582        cx: &mut Context<Self>,
19583    ) {
19584        if self.buffer.read(cx).is_singleton() {
19585            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19586            self.unfold_ranges(
19587                &[MultiBufferOffset(0)..display_map.buffer_snapshot().len()],
19588                true,
19589                true,
19590                cx,
19591            );
19592        } else {
19593            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
19594                editor
19595                    .update(cx, |editor, cx| {
19596                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19597                            editor.unfold_buffer(buffer_id, cx);
19598                        }
19599                    })
19600                    .ok();
19601            });
19602        }
19603    }
19604
19605    pub fn fold_selected_ranges(
19606        &mut self,
19607        _: &FoldSelectedRanges,
19608        window: &mut Window,
19609        cx: &mut Context<Self>,
19610    ) {
19611        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19612        let selections = self.selections.all_adjusted(&display_map);
19613        let ranges = selections
19614            .into_iter()
19615            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
19616            .collect::<Vec<_>>();
19617        self.fold_creases(ranges, true, window, cx);
19618    }
19619
19620    pub fn fold_ranges<T: ToOffset + Clone>(
19621        &mut self,
19622        ranges: Vec<Range<T>>,
19623        auto_scroll: bool,
19624        window: &mut Window,
19625        cx: &mut Context<Self>,
19626    ) {
19627        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19628        let ranges = ranges
19629            .into_iter()
19630            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
19631            .collect::<Vec<_>>();
19632        self.fold_creases(ranges, auto_scroll, window, cx);
19633    }
19634
19635    pub fn fold_creases<T: ToOffset + Clone>(
19636        &mut self,
19637        creases: Vec<Crease<T>>,
19638        auto_scroll: bool,
19639        _window: &mut Window,
19640        cx: &mut Context<Self>,
19641    ) {
19642        if creases.is_empty() {
19643            return;
19644        }
19645
19646        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
19647
19648        if auto_scroll {
19649            self.request_autoscroll(Autoscroll::fit(), cx);
19650        }
19651
19652        cx.notify();
19653
19654        self.scrollbar_marker_state.dirty = true;
19655        self.folds_did_change(cx);
19656    }
19657
19658    /// Removes any folds whose ranges intersect any of the given ranges.
19659    pub fn unfold_ranges<T: ToOffset + Clone>(
19660        &mut self,
19661        ranges: &[Range<T>],
19662        inclusive: bool,
19663        auto_scroll: bool,
19664        cx: &mut Context<Self>,
19665    ) {
19666        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19667            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx)
19668        });
19669        self.folds_did_change(cx);
19670    }
19671
19672    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19673        if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
19674            return;
19675        }
19676
19677        let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19678        self.display_map.update(cx, |display_map, cx| {
19679            display_map.fold_buffers([buffer_id], cx)
19680        });
19681
19682        let snapshot = self.display_snapshot(cx);
19683        self.selections.change_with(&snapshot, |selections| {
19684            selections.remove_selections_from_buffer(buffer_id);
19685        });
19686
19687        cx.emit(EditorEvent::BufferFoldToggled {
19688            ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
19689            folded: true,
19690        });
19691        cx.notify();
19692    }
19693
19694    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19695        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
19696            return;
19697        }
19698        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
19699        self.display_map.update(cx, |display_map, cx| {
19700            display_map.unfold_buffers([buffer_id], cx);
19701        });
19702        cx.emit(EditorEvent::BufferFoldToggled {
19703            ids: unfolded_excerpts.iter().map(|&(id, _)| id).collect(),
19704            folded: false,
19705        });
19706        cx.notify();
19707    }
19708
19709    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
19710        self.display_map.read(cx).is_buffer_folded(buffer)
19711    }
19712
19713    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
19714        self.display_map.read(cx).folded_buffers()
19715    }
19716
19717    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
19718        self.display_map.update(cx, |display_map, cx| {
19719            display_map.disable_header_for_buffer(buffer_id, cx);
19720        });
19721        cx.notify();
19722    }
19723
19724    /// Removes any folds with the given ranges.
19725    pub fn remove_folds_with_type<T: ToOffset + Clone>(
19726        &mut self,
19727        ranges: &[Range<T>],
19728        type_id: TypeId,
19729        auto_scroll: bool,
19730        cx: &mut Context<Self>,
19731    ) {
19732        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
19733            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
19734        });
19735        self.folds_did_change(cx);
19736    }
19737
19738    fn remove_folds_with<T: ToOffset + Clone>(
19739        &mut self,
19740        ranges: &[Range<T>],
19741        auto_scroll: bool,
19742        cx: &mut Context<Self>,
19743        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
19744    ) {
19745        if ranges.is_empty() {
19746            return;
19747        }
19748
19749        let mut buffers_affected = HashSet::default();
19750        let multi_buffer = self.buffer().read(cx);
19751        for range in ranges {
19752            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
19753                buffers_affected.insert(buffer.read(cx).remote_id());
19754            };
19755        }
19756
19757        self.display_map.update(cx, update);
19758
19759        if auto_scroll {
19760            self.request_autoscroll(Autoscroll::fit(), cx);
19761        }
19762
19763        cx.notify();
19764        self.scrollbar_marker_state.dirty = true;
19765        self.active_indent_guides_state.dirty = true;
19766    }
19767
19768    pub fn update_renderer_widths(
19769        &mut self,
19770        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
19771        cx: &mut Context<Self>,
19772    ) -> bool {
19773        self.display_map
19774            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
19775    }
19776
19777    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
19778        self.display_map.read(cx).fold_placeholder.clone()
19779    }
19780
19781    pub fn set_use_base_text_line_numbers(&mut self, show: bool, _cx: &mut Context<Self>) {
19782        self.use_base_text_line_numbers = show;
19783    }
19784
19785    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
19786        self.buffer.update(cx, |buffer, cx| {
19787            buffer.set_all_diff_hunks_expanded(cx);
19788        });
19789    }
19790
19791    pub fn expand_all_diff_hunks(
19792        &mut self,
19793        _: &ExpandAllDiffHunks,
19794        _window: &mut Window,
19795        cx: &mut Context<Self>,
19796    ) {
19797        self.buffer.update(cx, |buffer, cx| {
19798            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19799        });
19800    }
19801
19802    pub fn collapse_all_diff_hunks(
19803        &mut self,
19804        _: &CollapseAllDiffHunks,
19805        _window: &mut Window,
19806        cx: &mut Context<Self>,
19807    ) {
19808        self.buffer.update(cx, |buffer, cx| {
19809            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
19810        });
19811    }
19812
19813    pub fn toggle_selected_diff_hunks(
19814        &mut self,
19815        _: &ToggleSelectedDiffHunks,
19816        _window: &mut Window,
19817        cx: &mut Context<Self>,
19818    ) {
19819        let ranges: Vec<_> = self
19820            .selections
19821            .disjoint_anchors()
19822            .iter()
19823            .map(|s| s.range())
19824            .collect();
19825        self.toggle_diff_hunks_in_ranges(ranges, cx);
19826    }
19827
19828    pub fn diff_hunks_in_ranges<'a>(
19829        &'a self,
19830        ranges: &'a [Range<Anchor>],
19831        buffer: &'a MultiBufferSnapshot,
19832    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
19833        ranges.iter().flat_map(move |range| {
19834            let end_excerpt_id = range.end.excerpt_id;
19835            let range = range.to_point(buffer);
19836            let mut peek_end = range.end;
19837            if range.end.row < buffer.max_row().0 {
19838                peek_end = Point::new(range.end.row + 1, 0);
19839            }
19840            buffer
19841                .diff_hunks_in_range(range.start..peek_end)
19842                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
19843        })
19844    }
19845
19846    pub fn has_stageable_diff_hunks_in_ranges(
19847        &self,
19848        ranges: &[Range<Anchor>],
19849        snapshot: &MultiBufferSnapshot,
19850    ) -> bool {
19851        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
19852        hunks.any(|hunk| hunk.status().has_secondary_hunk())
19853    }
19854
19855    pub fn toggle_staged_selected_diff_hunks(
19856        &mut self,
19857        _: &::git::ToggleStaged,
19858        _: &mut Window,
19859        cx: &mut Context<Self>,
19860    ) {
19861        let snapshot = self.buffer.read(cx).snapshot(cx);
19862        let ranges: Vec<_> = self
19863            .selections
19864            .disjoint_anchors()
19865            .iter()
19866            .map(|s| s.range())
19867            .collect();
19868        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
19869        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19870    }
19871
19872    pub fn set_render_diff_hunk_controls(
19873        &mut self,
19874        render_diff_hunk_controls: RenderDiffHunkControlsFn,
19875        cx: &mut Context<Self>,
19876    ) {
19877        self.render_diff_hunk_controls = render_diff_hunk_controls;
19878        cx.notify();
19879    }
19880
19881    pub fn stage_and_next(
19882        &mut self,
19883        _: &::git::StageAndNext,
19884        window: &mut Window,
19885        cx: &mut Context<Self>,
19886    ) {
19887        self.do_stage_or_unstage_and_next(true, window, cx);
19888    }
19889
19890    pub fn unstage_and_next(
19891        &mut self,
19892        _: &::git::UnstageAndNext,
19893        window: &mut Window,
19894        cx: &mut Context<Self>,
19895    ) {
19896        self.do_stage_or_unstage_and_next(false, window, cx);
19897    }
19898
19899    pub fn stage_or_unstage_diff_hunks(
19900        &mut self,
19901        stage: bool,
19902        ranges: Vec<Range<Anchor>>,
19903        cx: &mut Context<Self>,
19904    ) {
19905        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
19906        cx.spawn(async move |this, cx| {
19907            task.await?;
19908            this.update(cx, |this, cx| {
19909                let snapshot = this.buffer.read(cx).snapshot(cx);
19910                let chunk_by = this
19911                    .diff_hunks_in_ranges(&ranges, &snapshot)
19912                    .chunk_by(|hunk| hunk.buffer_id);
19913                for (buffer_id, hunks) in &chunk_by {
19914                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
19915                }
19916            })
19917        })
19918        .detach_and_log_err(cx);
19919    }
19920
19921    fn save_buffers_for_ranges_if_needed(
19922        &mut self,
19923        ranges: &[Range<Anchor>],
19924        cx: &mut Context<Editor>,
19925    ) -> Task<Result<()>> {
19926        let multibuffer = self.buffer.read(cx);
19927        let snapshot = multibuffer.read(cx);
19928        let buffer_ids: HashSet<_> = ranges
19929            .iter()
19930            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
19931            .collect();
19932        drop(snapshot);
19933
19934        let mut buffers = HashSet::default();
19935        for buffer_id in buffer_ids {
19936            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
19937                let buffer = buffer_entity.read(cx);
19938                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
19939                {
19940                    buffers.insert(buffer_entity);
19941                }
19942            }
19943        }
19944
19945        if let Some(project) = &self.project {
19946            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
19947        } else {
19948            Task::ready(Ok(()))
19949        }
19950    }
19951
19952    fn do_stage_or_unstage_and_next(
19953        &mut self,
19954        stage: bool,
19955        window: &mut Window,
19956        cx: &mut Context<Self>,
19957    ) {
19958        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
19959
19960        if ranges.iter().any(|range| range.start != range.end) {
19961            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19962            return;
19963        }
19964
19965        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
19966        let snapshot = self.snapshot(window, cx);
19967        let position = self
19968            .selections
19969            .newest::<Point>(&snapshot.display_snapshot)
19970            .head();
19971        let mut row = snapshot
19972            .buffer_snapshot()
19973            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
19974            .find(|hunk| hunk.row_range.start.0 > position.row)
19975            .map(|hunk| hunk.row_range.start);
19976
19977        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
19978        // Outside of the project diff editor, wrap around to the beginning.
19979        if !all_diff_hunks_expanded {
19980            row = row.or_else(|| {
19981                snapshot
19982                    .buffer_snapshot()
19983                    .diff_hunks_in_range(Point::zero()..position)
19984                    .find(|hunk| hunk.row_range.end.0 < position.row)
19985                    .map(|hunk| hunk.row_range.start)
19986            });
19987        }
19988
19989        if let Some(row) = row {
19990            let destination = Point::new(row.0, 0);
19991            let autoscroll = Autoscroll::center();
19992
19993            self.unfold_ranges(&[destination..destination], false, false, cx);
19994            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
19995                s.select_ranges([destination..destination]);
19996            });
19997        }
19998    }
19999
20000    fn do_stage_or_unstage(
20001        &self,
20002        stage: bool,
20003        buffer_id: BufferId,
20004        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
20005        cx: &mut App,
20006    ) -> Option<()> {
20007        let project = self.project()?;
20008        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
20009        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
20010        let buffer_snapshot = buffer.read(cx).snapshot();
20011        let file_exists = buffer_snapshot
20012            .file()
20013            .is_some_and(|file| file.disk_state().exists());
20014        diff.update(cx, |diff, cx| {
20015            diff.stage_or_unstage_hunks(
20016                stage,
20017                &hunks
20018                    .map(|hunk| buffer_diff::DiffHunk {
20019                        buffer_range: hunk.buffer_range,
20020                        // We don't need to pass in word diffs here because they're only used for rendering and
20021                        // this function changes internal state
20022                        base_word_diffs: Vec::default(),
20023                        buffer_word_diffs: Vec::default(),
20024                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
20025                            ..hunk.diff_base_byte_range.end.0,
20026                        secondary_status: hunk.secondary_status,
20027                        range: Point::zero()..Point::zero(), // unused
20028                    })
20029                    .collect::<Vec<_>>(),
20030                &buffer_snapshot,
20031                file_exists,
20032                cx,
20033            )
20034        });
20035        None
20036    }
20037
20038    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
20039        let ranges: Vec<_> = self
20040            .selections
20041            .disjoint_anchors()
20042            .iter()
20043            .map(|s| s.range())
20044            .collect();
20045        self.buffer
20046            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
20047    }
20048
20049    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
20050        self.buffer.update(cx, |buffer, cx| {
20051            let ranges = vec![Anchor::min()..Anchor::max()];
20052            if !buffer.all_diff_hunks_expanded()
20053                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
20054            {
20055                buffer.collapse_diff_hunks(ranges, cx);
20056                true
20057            } else {
20058                false
20059            }
20060        })
20061    }
20062
20063    fn has_any_expanded_diff_hunks(&self, cx: &App) -> bool {
20064        if self.buffer.read(cx).all_diff_hunks_expanded() {
20065            return true;
20066        }
20067        let ranges = vec![Anchor::min()..Anchor::max()];
20068        self.buffer
20069            .read(cx)
20070            .has_expanded_diff_hunks_in_ranges(&ranges, cx)
20071    }
20072
20073    fn toggle_diff_hunks_in_ranges(
20074        &mut self,
20075        ranges: Vec<Range<Anchor>>,
20076        cx: &mut Context<Editor>,
20077    ) {
20078        self.buffer.update(cx, |buffer, cx| {
20079            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
20080            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
20081        })
20082    }
20083
20084    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
20085        self.buffer.update(cx, |buffer, cx| {
20086            let snapshot = buffer.snapshot(cx);
20087            let excerpt_id = range.end.excerpt_id;
20088            let point_range = range.to_point(&snapshot);
20089            let expand = !buffer.single_hunk_is_expanded(range, cx);
20090            buffer.expand_or_collapse_diff_hunks_inner([(point_range, excerpt_id)], expand, cx);
20091        })
20092    }
20093
20094    pub(crate) fn apply_all_diff_hunks(
20095        &mut self,
20096        _: &ApplyAllDiffHunks,
20097        window: &mut Window,
20098        cx: &mut Context<Self>,
20099    ) {
20100        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20101
20102        let buffers = self.buffer.read(cx).all_buffers();
20103        for branch_buffer in buffers {
20104            branch_buffer.update(cx, |branch_buffer, cx| {
20105                branch_buffer.merge_into_base(Vec::new(), cx);
20106            });
20107        }
20108
20109        if let Some(project) = self.project.clone() {
20110            self.save(
20111                SaveOptions {
20112                    format: true,
20113                    autosave: false,
20114                },
20115                project,
20116                window,
20117                cx,
20118            )
20119            .detach_and_log_err(cx);
20120        }
20121    }
20122
20123    pub(crate) fn apply_selected_diff_hunks(
20124        &mut self,
20125        _: &ApplyDiffHunk,
20126        window: &mut Window,
20127        cx: &mut Context<Self>,
20128    ) {
20129        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20130        let snapshot = self.snapshot(window, cx);
20131        let hunks = snapshot.hunks_for_ranges(
20132            self.selections
20133                .all(&snapshot.display_snapshot)
20134                .into_iter()
20135                .map(|selection| selection.range()),
20136        );
20137        let mut ranges_by_buffer = HashMap::default();
20138        self.transact(window, cx, |editor, _window, cx| {
20139            for hunk in hunks {
20140                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
20141                    ranges_by_buffer
20142                        .entry(buffer.clone())
20143                        .or_insert_with(Vec::new)
20144                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
20145                }
20146            }
20147
20148            for (buffer, ranges) in ranges_by_buffer {
20149                buffer.update(cx, |buffer, cx| {
20150                    buffer.merge_into_base(ranges, cx);
20151                });
20152            }
20153        });
20154
20155        if let Some(project) = self.project.clone() {
20156            self.save(
20157                SaveOptions {
20158                    format: true,
20159                    autosave: false,
20160                },
20161                project,
20162                window,
20163                cx,
20164            )
20165            .detach_and_log_err(cx);
20166        }
20167    }
20168
20169    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
20170        if hovered != self.gutter_hovered {
20171            self.gutter_hovered = hovered;
20172            cx.notify();
20173        }
20174    }
20175
20176    pub fn insert_blocks(
20177        &mut self,
20178        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
20179        autoscroll: Option<Autoscroll>,
20180        cx: &mut Context<Self>,
20181    ) -> Vec<CustomBlockId> {
20182        let blocks = self
20183            .display_map
20184            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
20185        if let Some(autoscroll) = autoscroll {
20186            self.request_autoscroll(autoscroll, cx);
20187        }
20188        cx.notify();
20189        blocks
20190    }
20191
20192    pub fn resize_blocks(
20193        &mut self,
20194        heights: HashMap<CustomBlockId, u32>,
20195        autoscroll: Option<Autoscroll>,
20196        cx: &mut Context<Self>,
20197    ) {
20198        self.display_map
20199            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
20200        if let Some(autoscroll) = autoscroll {
20201            self.request_autoscroll(autoscroll, cx);
20202        }
20203        cx.notify();
20204    }
20205
20206    pub fn replace_blocks(
20207        &mut self,
20208        renderers: HashMap<CustomBlockId, RenderBlock>,
20209        autoscroll: Option<Autoscroll>,
20210        cx: &mut Context<Self>,
20211    ) {
20212        self.display_map
20213            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
20214        if let Some(autoscroll) = autoscroll {
20215            self.request_autoscroll(autoscroll, cx);
20216        }
20217        cx.notify();
20218    }
20219
20220    pub fn remove_blocks(
20221        &mut self,
20222        block_ids: HashSet<CustomBlockId>,
20223        autoscroll: Option<Autoscroll>,
20224        cx: &mut Context<Self>,
20225    ) {
20226        self.display_map.update(cx, |display_map, cx| {
20227            display_map.remove_blocks(block_ids, cx)
20228        });
20229        if let Some(autoscroll) = autoscroll {
20230            self.request_autoscroll(autoscroll, cx);
20231        }
20232        cx.notify();
20233    }
20234
20235    pub fn row_for_block(
20236        &self,
20237        block_id: CustomBlockId,
20238        cx: &mut Context<Self>,
20239    ) -> Option<DisplayRow> {
20240        self.display_map
20241            .update(cx, |map, cx| map.row_for_block(block_id, cx))
20242    }
20243
20244    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
20245        self.focused_block = Some(focused_block);
20246    }
20247
20248    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
20249        self.focused_block.take()
20250    }
20251
20252    pub fn insert_creases(
20253        &mut self,
20254        creases: impl IntoIterator<Item = Crease<Anchor>>,
20255        cx: &mut Context<Self>,
20256    ) -> Vec<CreaseId> {
20257        self.display_map
20258            .update(cx, |map, cx| map.insert_creases(creases, cx))
20259    }
20260
20261    pub fn remove_creases(
20262        &mut self,
20263        ids: impl IntoIterator<Item = CreaseId>,
20264        cx: &mut Context<Self>,
20265    ) -> Vec<(CreaseId, Range<Anchor>)> {
20266        self.display_map
20267            .update(cx, |map, cx| map.remove_creases(ids, cx))
20268    }
20269
20270    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
20271        self.display_map
20272            .update(cx, |map, cx| map.snapshot(cx))
20273            .longest_row()
20274    }
20275
20276    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
20277        self.display_map
20278            .update(cx, |map, cx| map.snapshot(cx))
20279            .max_point()
20280    }
20281
20282    pub fn text(&self, cx: &App) -> String {
20283        self.buffer.read(cx).read(cx).text()
20284    }
20285
20286    pub fn is_empty(&self, cx: &App) -> bool {
20287        self.buffer.read(cx).read(cx).is_empty()
20288    }
20289
20290    pub fn text_option(&self, cx: &App) -> Option<String> {
20291        let text = self.text(cx);
20292        let text = text.trim();
20293
20294        if text.is_empty() {
20295            return None;
20296        }
20297
20298        Some(text.to_string())
20299    }
20300
20301    pub fn set_text(
20302        &mut self,
20303        text: impl Into<Arc<str>>,
20304        window: &mut Window,
20305        cx: &mut Context<Self>,
20306    ) {
20307        self.transact(window, cx, |this, _, cx| {
20308            this.buffer
20309                .read(cx)
20310                .as_singleton()
20311                .expect("you can only call set_text on editors for singleton buffers")
20312                .update(cx, |buffer, cx| buffer.set_text(text, cx));
20313        });
20314    }
20315
20316    pub fn display_text(&self, cx: &mut App) -> String {
20317        self.display_map
20318            .update(cx, |map, cx| map.snapshot(cx))
20319            .text()
20320    }
20321
20322    fn create_minimap(
20323        &self,
20324        minimap_settings: MinimapSettings,
20325        window: &mut Window,
20326        cx: &mut Context<Self>,
20327    ) -> Option<Entity<Self>> {
20328        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
20329            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
20330    }
20331
20332    fn initialize_new_minimap(
20333        &self,
20334        minimap_settings: MinimapSettings,
20335        window: &mut Window,
20336        cx: &mut Context<Self>,
20337    ) -> Entity<Self> {
20338        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
20339
20340        let mut minimap = Editor::new_internal(
20341            EditorMode::Minimap {
20342                parent: cx.weak_entity(),
20343            },
20344            self.buffer.clone(),
20345            None,
20346            Some(self.display_map.clone()),
20347            window,
20348            cx,
20349        );
20350        minimap.scroll_manager.clone_state(&self.scroll_manager);
20351        minimap.set_text_style_refinement(TextStyleRefinement {
20352            font_size: Some(MINIMAP_FONT_SIZE),
20353            font_weight: Some(MINIMAP_FONT_WEIGHT),
20354            ..Default::default()
20355        });
20356        minimap.update_minimap_configuration(minimap_settings, cx);
20357        cx.new(|_| minimap)
20358    }
20359
20360    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
20361        let current_line_highlight = minimap_settings
20362            .current_line_highlight
20363            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
20364        self.set_current_line_highlight(Some(current_line_highlight));
20365    }
20366
20367    pub fn minimap(&self) -> Option<&Entity<Self>> {
20368        self.minimap
20369            .as_ref()
20370            .filter(|_| self.minimap_visibility.visible())
20371    }
20372
20373    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
20374        let mut wrap_guides = smallvec![];
20375
20376        if self.show_wrap_guides == Some(false) {
20377            return wrap_guides;
20378        }
20379
20380        let settings = self.buffer.read(cx).language_settings(cx);
20381        if settings.show_wrap_guides {
20382            match self.soft_wrap_mode(cx) {
20383                SoftWrap::Column(soft_wrap) => {
20384                    wrap_guides.push((soft_wrap as usize, true));
20385                }
20386                SoftWrap::Bounded(soft_wrap) => {
20387                    wrap_guides.push((soft_wrap as usize, true));
20388                }
20389                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
20390            }
20391            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
20392        }
20393
20394        wrap_guides
20395    }
20396
20397    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
20398        let settings = self.buffer.read(cx).language_settings(cx);
20399        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
20400        match mode {
20401            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
20402                SoftWrap::None
20403            }
20404            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
20405            language_settings::SoftWrap::PreferredLineLength => {
20406                SoftWrap::Column(settings.preferred_line_length)
20407            }
20408            language_settings::SoftWrap::Bounded => {
20409                SoftWrap::Bounded(settings.preferred_line_length)
20410            }
20411        }
20412    }
20413
20414    pub fn set_soft_wrap_mode(
20415        &mut self,
20416        mode: language_settings::SoftWrap,
20417
20418        cx: &mut Context<Self>,
20419    ) {
20420        self.soft_wrap_mode_override = Some(mode);
20421        cx.notify();
20422    }
20423
20424    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
20425        self.hard_wrap = hard_wrap;
20426        cx.notify();
20427    }
20428
20429    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
20430        self.text_style_refinement = Some(style);
20431    }
20432
20433    /// called by the Element so we know what style we were most recently rendered with.
20434    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
20435        // We intentionally do not inform the display map about the minimap style
20436        // so that wrapping is not recalculated and stays consistent for the editor
20437        // and its linked minimap.
20438        if !self.mode.is_minimap() {
20439            let font = style.text.font();
20440            let font_size = style.text.font_size.to_pixels(window.rem_size());
20441            let display_map = self
20442                .placeholder_display_map
20443                .as_ref()
20444                .filter(|_| self.is_empty(cx))
20445                .unwrap_or(&self.display_map);
20446
20447            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
20448        }
20449        self.style = Some(style);
20450    }
20451
20452    pub fn style(&mut self, cx: &App) -> &EditorStyle {
20453        if self.style.is_none() {
20454            self.style = Some(self.create_style(cx));
20455        }
20456        self.style.as_ref().unwrap()
20457    }
20458
20459    // Called by the element. This method is not designed to be called outside of the editor
20460    // element's layout code because it does not notify when rewrapping is computed synchronously.
20461    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
20462        if self.is_empty(cx) {
20463            self.placeholder_display_map
20464                .as_ref()
20465                .map_or(false, |display_map| {
20466                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
20467                })
20468        } else {
20469            self.display_map
20470                .update(cx, |map, cx| map.set_wrap_width(width, cx))
20471        }
20472    }
20473
20474    pub fn set_soft_wrap(&mut self) {
20475        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
20476    }
20477
20478    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
20479        if self.soft_wrap_mode_override.is_some() {
20480            self.soft_wrap_mode_override.take();
20481        } else {
20482            let soft_wrap = match self.soft_wrap_mode(cx) {
20483                SoftWrap::GitDiff => return,
20484                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
20485                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
20486                    language_settings::SoftWrap::None
20487                }
20488            };
20489            self.soft_wrap_mode_override = Some(soft_wrap);
20490        }
20491        cx.notify();
20492    }
20493
20494    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
20495        let Some(workspace) = self.workspace() else {
20496            return;
20497        };
20498        let fs = workspace.read(cx).app_state().fs.clone();
20499        let current_show = TabBarSettings::get_global(cx).show;
20500        update_settings_file(fs, cx, move |setting, _| {
20501            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
20502        });
20503    }
20504
20505    pub fn toggle_indent_guides(
20506        &mut self,
20507        _: &ToggleIndentGuides,
20508        _: &mut Window,
20509        cx: &mut Context<Self>,
20510    ) {
20511        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
20512            self.buffer
20513                .read(cx)
20514                .language_settings(cx)
20515                .indent_guides
20516                .enabled
20517        });
20518        self.show_indent_guides = Some(!currently_enabled);
20519        cx.notify();
20520    }
20521
20522    fn should_show_indent_guides(&self) -> Option<bool> {
20523        self.show_indent_guides
20524    }
20525
20526    pub fn disable_indent_guides_for_buffer(
20527        &mut self,
20528        buffer_id: BufferId,
20529        cx: &mut Context<Self>,
20530    ) {
20531        self.buffers_with_disabled_indent_guides.insert(buffer_id);
20532        cx.notify();
20533    }
20534
20535    pub fn has_indent_guides_disabled_for_buffer(&self, buffer_id: BufferId) -> bool {
20536        self.buffers_with_disabled_indent_guides
20537            .contains(&buffer_id)
20538    }
20539
20540    pub fn toggle_line_numbers(
20541        &mut self,
20542        _: &ToggleLineNumbers,
20543        _: &mut Window,
20544        cx: &mut Context<Self>,
20545    ) {
20546        let mut editor_settings = EditorSettings::get_global(cx).clone();
20547        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
20548        EditorSettings::override_global(editor_settings, cx);
20549    }
20550
20551    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
20552        if let Some(show_line_numbers) = self.show_line_numbers {
20553            return show_line_numbers;
20554        }
20555        EditorSettings::get_global(cx).gutter.line_numbers
20556    }
20557
20558    pub fn relative_line_numbers(&self, cx: &mut App) -> RelativeLineNumbers {
20559        match (
20560            self.use_relative_line_numbers,
20561            EditorSettings::get_global(cx).relative_line_numbers,
20562        ) {
20563            (None, setting) => setting,
20564            (Some(false), _) => RelativeLineNumbers::Disabled,
20565            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
20566            (Some(true), _) => RelativeLineNumbers::Enabled,
20567        }
20568    }
20569
20570    pub fn toggle_relative_line_numbers(
20571        &mut self,
20572        _: &ToggleRelativeLineNumbers,
20573        _: &mut Window,
20574        cx: &mut Context<Self>,
20575    ) {
20576        let is_relative = self.relative_line_numbers(cx);
20577        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
20578    }
20579
20580    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
20581        self.use_relative_line_numbers = is_relative;
20582        cx.notify();
20583    }
20584
20585    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
20586        self.show_gutter = show_gutter;
20587        cx.notify();
20588    }
20589
20590    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
20591        self.show_scrollbars = ScrollbarAxes {
20592            horizontal: show,
20593            vertical: show,
20594        };
20595        cx.notify();
20596    }
20597
20598    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20599        self.show_scrollbars.vertical = show;
20600        cx.notify();
20601    }
20602
20603    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
20604        self.show_scrollbars.horizontal = show;
20605        cx.notify();
20606    }
20607
20608    pub fn set_minimap_visibility(
20609        &mut self,
20610        minimap_visibility: MinimapVisibility,
20611        window: &mut Window,
20612        cx: &mut Context<Self>,
20613    ) {
20614        if self.minimap_visibility != minimap_visibility {
20615            if minimap_visibility.visible() && self.minimap.is_none() {
20616                let minimap_settings = EditorSettings::get_global(cx).minimap;
20617                self.minimap =
20618                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
20619            }
20620            self.minimap_visibility = minimap_visibility;
20621            cx.notify();
20622        }
20623    }
20624
20625    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20626        self.set_show_scrollbars(false, cx);
20627        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
20628    }
20629
20630    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
20631        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
20632    }
20633
20634    /// Normally the text in full mode and auto height editors is padded on the
20635    /// left side by roughly half a character width for improved hit testing.
20636    ///
20637    /// Use this method to disable this for cases where this is not wanted (e.g.
20638    /// if you want to align the editor text with some other text above or below)
20639    /// or if you want to add this padding to single-line editors.
20640    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
20641        self.offset_content = offset_content;
20642        cx.notify();
20643    }
20644
20645    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
20646        self.show_line_numbers = Some(show_line_numbers);
20647        cx.notify();
20648    }
20649
20650    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
20651        self.disable_expand_excerpt_buttons = true;
20652        cx.notify();
20653    }
20654
20655    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
20656        self.show_git_diff_gutter = Some(show_git_diff_gutter);
20657        cx.notify();
20658    }
20659
20660    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
20661        self.show_code_actions = Some(show_code_actions);
20662        cx.notify();
20663    }
20664
20665    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
20666        self.show_runnables = Some(show_runnables);
20667        cx.notify();
20668    }
20669
20670    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
20671        self.show_breakpoints = Some(show_breakpoints);
20672        cx.notify();
20673    }
20674
20675    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
20676        if self.display_map.read(cx).masked != masked {
20677            self.display_map.update(cx, |map, _| map.masked = masked);
20678        }
20679        cx.notify()
20680    }
20681
20682    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
20683        self.show_wrap_guides = Some(show_wrap_guides);
20684        cx.notify();
20685    }
20686
20687    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
20688        self.show_indent_guides = Some(show_indent_guides);
20689        cx.notify();
20690    }
20691
20692    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
20693        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
20694            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
20695                && let Some(dir) = file.abs_path(cx).parent()
20696            {
20697                return Some(dir.to_owned());
20698            }
20699        }
20700
20701        None
20702    }
20703
20704    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
20705        self.active_excerpt(cx)?
20706            .1
20707            .read(cx)
20708            .file()
20709            .and_then(|f| f.as_local())
20710    }
20711
20712    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
20713        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20714            let buffer = buffer.read(cx);
20715            if let Some(project_path) = buffer.project_path(cx) {
20716                let project = self.project()?.read(cx);
20717                project.absolute_path(&project_path, cx)
20718            } else {
20719                buffer
20720                    .file()
20721                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
20722            }
20723        })
20724    }
20725
20726    pub fn reveal_in_finder(
20727        &mut self,
20728        _: &RevealInFileManager,
20729        _window: &mut Window,
20730        cx: &mut Context<Self>,
20731    ) {
20732        if let Some(target) = self.target_file(cx) {
20733            cx.reveal_path(&target.abs_path(cx));
20734        }
20735    }
20736
20737    pub fn copy_path(
20738        &mut self,
20739        _: &zed_actions::workspace::CopyPath,
20740        _window: &mut Window,
20741        cx: &mut Context<Self>,
20742    ) {
20743        if let Some(path) = self.target_file_abs_path(cx)
20744            && let Some(path) = path.to_str()
20745        {
20746            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20747        } else {
20748            cx.propagate();
20749        }
20750    }
20751
20752    pub fn copy_relative_path(
20753        &mut self,
20754        _: &zed_actions::workspace::CopyRelativePath,
20755        _window: &mut Window,
20756        cx: &mut Context<Self>,
20757    ) {
20758        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20759            let project = self.project()?.read(cx);
20760            let path = buffer.read(cx).file()?.path();
20761            let path = path.display(project.path_style(cx));
20762            Some(path)
20763        }) {
20764            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
20765        } else {
20766            cx.propagate();
20767        }
20768    }
20769
20770    /// Returns the project path for the editor's buffer, if any buffer is
20771    /// opened in the editor.
20772    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
20773        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
20774            buffer.read(cx).project_path(cx)
20775        } else {
20776            None
20777        }
20778    }
20779
20780    // Returns true if the editor handled a go-to-line request
20781    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
20782        maybe!({
20783            let breakpoint_store = self.breakpoint_store.as_ref()?;
20784
20785            let Some(active_stack_frame) = breakpoint_store.read(cx).active_position().cloned()
20786            else {
20787                self.clear_row_highlights::<ActiveDebugLine>();
20788                return None;
20789            };
20790
20791            let position = active_stack_frame.position;
20792            let buffer_id = position.buffer_id?;
20793            let snapshot = self
20794                .project
20795                .as_ref()?
20796                .read(cx)
20797                .buffer_for_id(buffer_id, cx)?
20798                .read(cx)
20799                .snapshot();
20800
20801            let mut handled = false;
20802            for (id, ExcerptRange { context, .. }) in
20803                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
20804            {
20805                if context.start.cmp(&position, &snapshot).is_ge()
20806                    || context.end.cmp(&position, &snapshot).is_lt()
20807                {
20808                    continue;
20809                }
20810                let snapshot = self.buffer.read(cx).snapshot(cx);
20811                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
20812
20813                handled = true;
20814                self.clear_row_highlights::<ActiveDebugLine>();
20815
20816                self.go_to_line::<ActiveDebugLine>(
20817                    multibuffer_anchor,
20818                    Some(cx.theme().colors().editor_debugger_active_line_background),
20819                    window,
20820                    cx,
20821                );
20822
20823                cx.notify();
20824            }
20825
20826            handled.then_some(())
20827        })
20828        .is_some()
20829    }
20830
20831    pub fn copy_file_name_without_extension(
20832        &mut self,
20833        _: &CopyFileNameWithoutExtension,
20834        _: &mut Window,
20835        cx: &mut Context<Self>,
20836    ) {
20837        if let Some(file_stem) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20838            let file = buffer.read(cx).file()?;
20839            file.path().file_stem()
20840        }) {
20841            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
20842        }
20843    }
20844
20845    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
20846        if let Some(file_name) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
20847            let file = buffer.read(cx).file()?;
20848            Some(file.file_name(cx))
20849        }) {
20850            cx.write_to_clipboard(ClipboardItem::new_string(file_name.to_string()));
20851        }
20852    }
20853
20854    pub fn toggle_git_blame(
20855        &mut self,
20856        _: &::git::Blame,
20857        window: &mut Window,
20858        cx: &mut Context<Self>,
20859    ) {
20860        self.show_git_blame_gutter = !self.show_git_blame_gutter;
20861
20862        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
20863            self.start_git_blame(true, window, cx);
20864        }
20865
20866        cx.notify();
20867    }
20868
20869    pub fn toggle_git_blame_inline(
20870        &mut self,
20871        _: &ToggleGitBlameInline,
20872        window: &mut Window,
20873        cx: &mut Context<Self>,
20874    ) {
20875        self.toggle_git_blame_inline_internal(true, window, cx);
20876        cx.notify();
20877    }
20878
20879    pub fn open_git_blame_commit(
20880        &mut self,
20881        _: &OpenGitBlameCommit,
20882        window: &mut Window,
20883        cx: &mut Context<Self>,
20884    ) {
20885        self.open_git_blame_commit_internal(window, cx);
20886    }
20887
20888    fn open_git_blame_commit_internal(
20889        &mut self,
20890        window: &mut Window,
20891        cx: &mut Context<Self>,
20892    ) -> Option<()> {
20893        let blame = self.blame.as_ref()?;
20894        let snapshot = self.snapshot(window, cx);
20895        let cursor = self
20896            .selections
20897            .newest::<Point>(&snapshot.display_snapshot)
20898            .head();
20899        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
20900        let (_, blame_entry) = blame
20901            .update(cx, |blame, cx| {
20902                blame
20903                    .blame_for_rows(
20904                        &[RowInfo {
20905                            buffer_id: Some(buffer.remote_id()),
20906                            buffer_row: Some(point.row),
20907                            ..Default::default()
20908                        }],
20909                        cx,
20910                    )
20911                    .next()
20912            })
20913            .flatten()?;
20914        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
20915        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
20916        let workspace = self.workspace()?.downgrade();
20917        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
20918        None
20919    }
20920
20921    pub fn git_blame_inline_enabled(&self) -> bool {
20922        self.git_blame_inline_enabled
20923    }
20924
20925    pub fn toggle_selection_menu(
20926        &mut self,
20927        _: &ToggleSelectionMenu,
20928        _: &mut Window,
20929        cx: &mut Context<Self>,
20930    ) {
20931        self.show_selection_menu = self
20932            .show_selection_menu
20933            .map(|show_selections_menu| !show_selections_menu)
20934            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
20935
20936        cx.notify();
20937    }
20938
20939    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
20940        self.show_selection_menu
20941            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
20942    }
20943
20944    fn start_git_blame(
20945        &mut self,
20946        user_triggered: bool,
20947        window: &mut Window,
20948        cx: &mut Context<Self>,
20949    ) {
20950        if let Some(project) = self.project() {
20951            if let Some(buffer) = self.buffer().read(cx).as_singleton()
20952                && buffer.read(cx).file().is_none()
20953            {
20954                return;
20955            }
20956
20957            let focused = self.focus_handle(cx).contains_focused(window, cx);
20958
20959            let project = project.clone();
20960            let blame = cx
20961                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
20962            self.blame_subscription =
20963                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
20964            self.blame = Some(blame);
20965        }
20966    }
20967
20968    fn toggle_git_blame_inline_internal(
20969        &mut self,
20970        user_triggered: bool,
20971        window: &mut Window,
20972        cx: &mut Context<Self>,
20973    ) {
20974        if self.git_blame_inline_enabled {
20975            self.git_blame_inline_enabled = false;
20976            self.show_git_blame_inline = false;
20977            self.show_git_blame_inline_delay_task.take();
20978        } else {
20979            self.git_blame_inline_enabled = true;
20980            self.start_git_blame_inline(user_triggered, window, cx);
20981        }
20982
20983        cx.notify();
20984    }
20985
20986    fn start_git_blame_inline(
20987        &mut self,
20988        user_triggered: bool,
20989        window: &mut Window,
20990        cx: &mut Context<Self>,
20991    ) {
20992        self.start_git_blame(user_triggered, window, cx);
20993
20994        if ProjectSettings::get_global(cx)
20995            .git
20996            .inline_blame_delay()
20997            .is_some()
20998        {
20999            self.start_inline_blame_timer(window, cx);
21000        } else {
21001            self.show_git_blame_inline = true
21002        }
21003    }
21004
21005    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
21006        self.blame.as_ref()
21007    }
21008
21009    pub fn show_git_blame_gutter(&self) -> bool {
21010        self.show_git_blame_gutter
21011    }
21012
21013    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
21014        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
21015    }
21016
21017    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
21018        self.show_git_blame_inline
21019            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
21020            && !self.newest_selection_head_on_empty_line(cx)
21021            && self.has_blame_entries(cx)
21022    }
21023
21024    fn has_blame_entries(&self, cx: &App) -> bool {
21025        self.blame()
21026            .is_some_and(|blame| blame.read(cx).has_generated_entries())
21027    }
21028
21029    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
21030        let cursor_anchor = self.selections.newest_anchor().head();
21031
21032        let snapshot = self.buffer.read(cx).snapshot(cx);
21033        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
21034
21035        snapshot.line_len(buffer_row) == 0
21036    }
21037
21038    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
21039        let buffer_and_selection = maybe!({
21040            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
21041            let selection_range = selection.range();
21042
21043            let multi_buffer = self.buffer().read(cx);
21044            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
21045            let buffer_ranges = multi_buffer_snapshot.range_to_buffer_ranges(selection_range);
21046
21047            let (buffer, range, _) = if selection.reversed {
21048                buffer_ranges.first()
21049            } else {
21050                buffer_ranges.last()
21051            }?;
21052
21053            let start_row_in_buffer = text::ToPoint::to_point(&range.start, buffer).row;
21054            let end_row_in_buffer = text::ToPoint::to_point(&range.end, buffer).row;
21055
21056            let Some(buffer_diff) = multi_buffer.diff_for(buffer.remote_id()) else {
21057                let selection = start_row_in_buffer..end_row_in_buffer;
21058
21059                return Some((multi_buffer.buffer(buffer.remote_id()).unwrap(), selection));
21060            };
21061
21062            let buffer_diff_snapshot = buffer_diff.read(cx).snapshot(cx);
21063
21064            Some((
21065                multi_buffer.buffer(buffer.remote_id()).unwrap(),
21066                buffer_diff_snapshot.row_to_base_text_row(start_row_in_buffer, buffer)
21067                    ..buffer_diff_snapshot.row_to_base_text_row(end_row_in_buffer, buffer),
21068            ))
21069        });
21070
21071        let Some((buffer, selection)) = buffer_and_selection else {
21072            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
21073        };
21074
21075        let Some(project) = self.project() else {
21076            return Task::ready(Err(anyhow!("editor does not have project")));
21077        };
21078
21079        project.update(cx, |project, cx| {
21080            project.get_permalink_to_line(&buffer, selection, cx)
21081        })
21082    }
21083
21084    pub fn copy_permalink_to_line(
21085        &mut self,
21086        _: &CopyPermalinkToLine,
21087        window: &mut Window,
21088        cx: &mut Context<Self>,
21089    ) {
21090        let permalink_task = self.get_permalink_to_line(cx);
21091        let workspace = self.workspace();
21092
21093        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
21094            Ok(permalink) => {
21095                cx.update(|_, cx| {
21096                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
21097                })
21098                .ok();
21099            }
21100            Err(err) => {
21101                let message = format!("Failed to copy permalink: {err}");
21102
21103                anyhow::Result::<()>::Err(err).log_err();
21104
21105                if let Some(workspace) = workspace {
21106                    workspace
21107                        .update_in(cx, |workspace, _, cx| {
21108                            struct CopyPermalinkToLine;
21109
21110                            workspace.show_toast(
21111                                Toast::new(
21112                                    NotificationId::unique::<CopyPermalinkToLine>(),
21113                                    message,
21114                                ),
21115                                cx,
21116                            )
21117                        })
21118                        .ok();
21119                }
21120            }
21121        })
21122        .detach();
21123    }
21124
21125    pub fn copy_file_location(
21126        &mut self,
21127        _: &CopyFileLocation,
21128        _: &mut Window,
21129        cx: &mut Context<Self>,
21130    ) {
21131        let selection = self
21132            .selections
21133            .newest::<Point>(&self.display_snapshot(cx))
21134            .start
21135            .row
21136            + 1;
21137        if let Some(file_location) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
21138            let project = self.project()?.read(cx);
21139            let file = buffer.read(cx).file()?;
21140            let path = file.path().display(project.path_style(cx));
21141
21142            Some(format!("{path}:{selection}"))
21143        }) {
21144            cx.write_to_clipboard(ClipboardItem::new_string(file_location));
21145        }
21146    }
21147
21148    pub fn open_permalink_to_line(
21149        &mut self,
21150        _: &OpenPermalinkToLine,
21151        window: &mut Window,
21152        cx: &mut Context<Self>,
21153    ) {
21154        let permalink_task = self.get_permalink_to_line(cx);
21155        let workspace = self.workspace();
21156
21157        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
21158            Ok(permalink) => {
21159                cx.update(|_, cx| {
21160                    cx.open_url(permalink.as_ref());
21161                })
21162                .ok();
21163            }
21164            Err(err) => {
21165                let message = format!("Failed to open permalink: {err}");
21166
21167                anyhow::Result::<()>::Err(err).log_err();
21168
21169                if let Some(workspace) = workspace {
21170                    workspace
21171                        .update(cx, |workspace, cx| {
21172                            struct OpenPermalinkToLine;
21173
21174                            workspace.show_toast(
21175                                Toast::new(
21176                                    NotificationId::unique::<OpenPermalinkToLine>(),
21177                                    message,
21178                                ),
21179                                cx,
21180                            )
21181                        })
21182                        .ok();
21183                }
21184            }
21185        })
21186        .detach();
21187    }
21188
21189    pub fn insert_uuid_v4(
21190        &mut self,
21191        _: &InsertUuidV4,
21192        window: &mut Window,
21193        cx: &mut Context<Self>,
21194    ) {
21195        self.insert_uuid(UuidVersion::V4, window, cx);
21196    }
21197
21198    pub fn insert_uuid_v7(
21199        &mut self,
21200        _: &InsertUuidV7,
21201        window: &mut Window,
21202        cx: &mut Context<Self>,
21203    ) {
21204        self.insert_uuid(UuidVersion::V7, window, cx);
21205    }
21206
21207    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
21208        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
21209        self.transact(window, cx, |this, window, cx| {
21210            let edits = this
21211                .selections
21212                .all::<Point>(&this.display_snapshot(cx))
21213                .into_iter()
21214                .map(|selection| {
21215                    let uuid = match version {
21216                        UuidVersion::V4 => uuid::Uuid::new_v4(),
21217                        UuidVersion::V7 => uuid::Uuid::now_v7(),
21218                    };
21219
21220                    (selection.range(), uuid.to_string())
21221                });
21222            this.edit(edits, cx);
21223            this.refresh_edit_prediction(true, false, window, cx);
21224        });
21225    }
21226
21227    pub fn open_selections_in_multibuffer(
21228        &mut self,
21229        _: &OpenSelectionsInMultibuffer,
21230        window: &mut Window,
21231        cx: &mut Context<Self>,
21232    ) {
21233        let multibuffer = self.buffer.read(cx);
21234
21235        let Some(buffer) = multibuffer.as_singleton() else {
21236            return;
21237        };
21238
21239        let Some(workspace) = self.workspace() else {
21240            return;
21241        };
21242
21243        let title = multibuffer.title(cx).to_string();
21244
21245        let locations = self
21246            .selections
21247            .all_anchors(&self.display_snapshot(cx))
21248            .iter()
21249            .map(|selection| {
21250                (
21251                    buffer.clone(),
21252                    (selection.start.text_anchor..selection.end.text_anchor)
21253                        .to_point(buffer.read(cx)),
21254                )
21255            })
21256            .into_group_map();
21257
21258        cx.spawn_in(window, async move |_, cx| {
21259            workspace.update_in(cx, |workspace, window, cx| {
21260                Self::open_locations_in_multibuffer(
21261                    workspace,
21262                    locations,
21263                    format!("Selections for '{title}'"),
21264                    false,
21265                    false,
21266                    MultibufferSelectionMode::All,
21267                    window,
21268                    cx,
21269                );
21270            })
21271        })
21272        .detach();
21273    }
21274
21275    /// Adds a row highlight for the given range. If a row has multiple highlights, the
21276    /// last highlight added will be used.
21277    ///
21278    /// If the range ends at the beginning of a line, then that line will not be highlighted.
21279    pub fn highlight_rows<T: 'static>(
21280        &mut self,
21281        range: Range<Anchor>,
21282        color: Hsla,
21283        options: RowHighlightOptions,
21284        cx: &mut Context<Self>,
21285    ) {
21286        let snapshot = self.buffer().read(cx).snapshot(cx);
21287        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
21288        let ix = row_highlights.binary_search_by(|highlight| {
21289            Ordering::Equal
21290                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
21291                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
21292        });
21293
21294        if let Err(mut ix) = ix {
21295            let index = post_inc(&mut self.highlight_order);
21296
21297            // If this range intersects with the preceding highlight, then merge it with
21298            // the preceding highlight. Otherwise insert a new highlight.
21299            let mut merged = false;
21300            if ix > 0 {
21301                let prev_highlight = &mut row_highlights[ix - 1];
21302                if prev_highlight
21303                    .range
21304                    .end
21305                    .cmp(&range.start, &snapshot)
21306                    .is_ge()
21307                {
21308                    ix -= 1;
21309                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
21310                        prev_highlight.range.end = range.end;
21311                    }
21312                    merged = true;
21313                    prev_highlight.index = index;
21314                    prev_highlight.color = color;
21315                    prev_highlight.options = options;
21316                }
21317            }
21318
21319            if !merged {
21320                row_highlights.insert(
21321                    ix,
21322                    RowHighlight {
21323                        range,
21324                        index,
21325                        color,
21326                        options,
21327                        type_id: TypeId::of::<T>(),
21328                    },
21329                );
21330            }
21331
21332            // If any of the following highlights intersect with this one, merge them.
21333            while let Some(next_highlight) = row_highlights.get(ix + 1) {
21334                let highlight = &row_highlights[ix];
21335                if next_highlight
21336                    .range
21337                    .start
21338                    .cmp(&highlight.range.end, &snapshot)
21339                    .is_le()
21340                {
21341                    if next_highlight
21342                        .range
21343                        .end
21344                        .cmp(&highlight.range.end, &snapshot)
21345                        .is_gt()
21346                    {
21347                        row_highlights[ix].range.end = next_highlight.range.end;
21348                    }
21349                    row_highlights.remove(ix + 1);
21350                } else {
21351                    break;
21352                }
21353            }
21354        }
21355    }
21356
21357    /// Remove any highlighted row ranges of the given type that intersect the
21358    /// given ranges.
21359    pub fn remove_highlighted_rows<T: 'static>(
21360        &mut self,
21361        ranges_to_remove: Vec<Range<Anchor>>,
21362        cx: &mut Context<Self>,
21363    ) {
21364        let snapshot = self.buffer().read(cx).snapshot(cx);
21365        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
21366        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
21367        row_highlights.retain(|highlight| {
21368            while let Some(range_to_remove) = ranges_to_remove.peek() {
21369                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
21370                    Ordering::Less | Ordering::Equal => {
21371                        ranges_to_remove.next();
21372                    }
21373                    Ordering::Greater => {
21374                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
21375                            Ordering::Less | Ordering::Equal => {
21376                                return false;
21377                            }
21378                            Ordering::Greater => break,
21379                        }
21380                    }
21381                }
21382            }
21383
21384            true
21385        })
21386    }
21387
21388    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
21389    pub fn clear_row_highlights<T: 'static>(&mut self) {
21390        self.highlighted_rows.remove(&TypeId::of::<T>());
21391    }
21392
21393    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
21394    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
21395        self.highlighted_rows
21396            .get(&TypeId::of::<T>())
21397            .map_or(&[] as &[_], |vec| vec.as_slice())
21398            .iter()
21399            .map(|highlight| (highlight.range.clone(), highlight.color))
21400    }
21401
21402    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
21403    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
21404    /// Allows to ignore certain kinds of highlights.
21405    pub fn highlighted_display_rows(
21406        &self,
21407        window: &mut Window,
21408        cx: &mut App,
21409    ) -> BTreeMap<DisplayRow, LineHighlight> {
21410        let snapshot = self.snapshot(window, cx);
21411        let mut used_highlight_orders = HashMap::default();
21412        self.highlighted_rows
21413            .iter()
21414            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
21415            .fold(
21416                BTreeMap::<DisplayRow, LineHighlight>::new(),
21417                |mut unique_rows, highlight| {
21418                    let start = highlight.range.start.to_display_point(&snapshot);
21419                    let end = highlight.range.end.to_display_point(&snapshot);
21420                    let start_row = start.row().0;
21421                    let end_row = if !highlight.range.end.text_anchor.is_max() && end.column() == 0
21422                    {
21423                        end.row().0.saturating_sub(1)
21424                    } else {
21425                        end.row().0
21426                    };
21427                    for row in start_row..=end_row {
21428                        let used_index =
21429                            used_highlight_orders.entry(row).or_insert(highlight.index);
21430                        if highlight.index >= *used_index {
21431                            *used_index = highlight.index;
21432                            unique_rows.insert(
21433                                DisplayRow(row),
21434                                LineHighlight {
21435                                    include_gutter: highlight.options.include_gutter,
21436                                    border: None,
21437                                    background: highlight.color.into(),
21438                                    type_id: Some(highlight.type_id),
21439                                },
21440                            );
21441                        }
21442                    }
21443                    unique_rows
21444                },
21445            )
21446    }
21447
21448    pub fn highlighted_display_row_for_autoscroll(
21449        &self,
21450        snapshot: &DisplaySnapshot,
21451    ) -> Option<DisplayRow> {
21452        self.highlighted_rows
21453            .values()
21454            .flat_map(|highlighted_rows| highlighted_rows.iter())
21455            .filter_map(|highlight| {
21456                if highlight.options.autoscroll {
21457                    Some(highlight.range.start.to_display_point(snapshot).row())
21458                } else {
21459                    None
21460                }
21461            })
21462            .min()
21463    }
21464
21465    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
21466        self.highlight_background::<SearchWithinRange>(
21467            ranges,
21468            |_, colors| colors.colors().editor_document_highlight_read_background,
21469            cx,
21470        )
21471    }
21472
21473    pub fn set_breadcrumb_header(&mut self, new_header: String) {
21474        self.breadcrumb_header = Some(new_header);
21475    }
21476
21477    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
21478        self.clear_background_highlights::<SearchWithinRange>(cx);
21479    }
21480
21481    pub fn highlight_background<T: 'static>(
21482        &mut self,
21483        ranges: &[Range<Anchor>],
21484        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
21485        cx: &mut Context<Self>,
21486    ) {
21487        self.background_highlights.insert(
21488            HighlightKey::Type(TypeId::of::<T>()),
21489            (Arc::new(color_fetcher), Arc::from(ranges)),
21490        );
21491        self.scrollbar_marker_state.dirty = true;
21492        cx.notify();
21493    }
21494
21495    pub fn highlight_background_key<T: 'static>(
21496        &mut self,
21497        key: usize,
21498        ranges: &[Range<Anchor>],
21499        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
21500        cx: &mut Context<Self>,
21501    ) {
21502        self.background_highlights.insert(
21503            HighlightKey::TypePlus(TypeId::of::<T>(), key),
21504            (Arc::new(color_fetcher), Arc::from(ranges)),
21505        );
21506        self.scrollbar_marker_state.dirty = true;
21507        cx.notify();
21508    }
21509
21510    pub fn clear_background_highlights<T: 'static>(
21511        &mut self,
21512        cx: &mut Context<Self>,
21513    ) -> Option<BackgroundHighlight> {
21514        let text_highlights = self
21515            .background_highlights
21516            .remove(&HighlightKey::Type(TypeId::of::<T>()))?;
21517        if !text_highlights.1.is_empty() {
21518            self.scrollbar_marker_state.dirty = true;
21519            cx.notify();
21520        }
21521        Some(text_highlights)
21522    }
21523
21524    pub fn highlight_gutter<T: 'static>(
21525        &mut self,
21526        ranges: impl Into<Vec<Range<Anchor>>>,
21527        color_fetcher: fn(&App) -> Hsla,
21528        cx: &mut Context<Self>,
21529    ) {
21530        self.gutter_highlights
21531            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
21532        cx.notify();
21533    }
21534
21535    pub fn clear_gutter_highlights<T: 'static>(
21536        &mut self,
21537        cx: &mut Context<Self>,
21538    ) -> Option<GutterHighlight> {
21539        cx.notify();
21540        self.gutter_highlights.remove(&TypeId::of::<T>())
21541    }
21542
21543    pub fn insert_gutter_highlight<T: 'static>(
21544        &mut self,
21545        range: Range<Anchor>,
21546        color_fetcher: fn(&App) -> Hsla,
21547        cx: &mut Context<Self>,
21548    ) {
21549        let snapshot = self.buffer().read(cx).snapshot(cx);
21550        let mut highlights = self
21551            .gutter_highlights
21552            .remove(&TypeId::of::<T>())
21553            .map(|(_, highlights)| highlights)
21554            .unwrap_or_default();
21555        let ix = highlights.binary_search_by(|highlight| {
21556            Ordering::Equal
21557                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
21558                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
21559        });
21560        if let Err(ix) = ix {
21561            highlights.insert(ix, range);
21562        }
21563        self.gutter_highlights
21564            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
21565    }
21566
21567    pub fn remove_gutter_highlights<T: 'static>(
21568        &mut self,
21569        ranges_to_remove: Vec<Range<Anchor>>,
21570        cx: &mut Context<Self>,
21571    ) {
21572        let snapshot = self.buffer().read(cx).snapshot(cx);
21573        let Some((color_fetcher, mut gutter_highlights)) =
21574            self.gutter_highlights.remove(&TypeId::of::<T>())
21575        else {
21576            return;
21577        };
21578        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
21579        gutter_highlights.retain(|highlight| {
21580            while let Some(range_to_remove) = ranges_to_remove.peek() {
21581                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
21582                    Ordering::Less | Ordering::Equal => {
21583                        ranges_to_remove.next();
21584                    }
21585                    Ordering::Greater => {
21586                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
21587                            Ordering::Less | Ordering::Equal => {
21588                                return false;
21589                            }
21590                            Ordering::Greater => break,
21591                        }
21592                    }
21593                }
21594            }
21595
21596            true
21597        });
21598        self.gutter_highlights
21599            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
21600    }
21601
21602    #[cfg(feature = "test-support")]
21603    pub fn all_text_highlights(
21604        &self,
21605        window: &mut Window,
21606        cx: &mut Context<Self>,
21607    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
21608        let snapshot = self.snapshot(window, cx);
21609        self.display_map.update(cx, |display_map, _| {
21610            display_map
21611                .all_text_highlights()
21612                .map(|highlight| {
21613                    let (style, ranges) = highlight.as_ref();
21614                    (
21615                        *style,
21616                        ranges
21617                            .iter()
21618                            .map(|range| range.clone().to_display_points(&snapshot))
21619                            .collect(),
21620                    )
21621                })
21622                .collect()
21623        })
21624    }
21625
21626    #[cfg(feature = "test-support")]
21627    pub fn all_text_background_highlights(
21628        &self,
21629        window: &mut Window,
21630        cx: &mut Context<Self>,
21631    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21632        let snapshot = self.snapshot(window, cx);
21633        let buffer = &snapshot.buffer_snapshot();
21634        let start = buffer.anchor_before(MultiBufferOffset(0));
21635        let end = buffer.anchor_after(buffer.len());
21636        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
21637    }
21638
21639    #[cfg(any(test, feature = "test-support"))]
21640    pub fn sorted_background_highlights_in_range(
21641        &self,
21642        search_range: Range<Anchor>,
21643        display_snapshot: &DisplaySnapshot,
21644        theme: &Theme,
21645    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21646        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
21647        res.sort_by(|a, b| {
21648            a.0.start
21649                .cmp(&b.0.start)
21650                .then_with(|| a.0.end.cmp(&b.0.end))
21651                .then_with(|| a.1.cmp(&b.1))
21652        });
21653        res
21654    }
21655
21656    #[cfg(feature = "test-support")]
21657    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
21658        let snapshot = self.buffer().read(cx).snapshot(cx);
21659
21660        let highlights = self
21661            .background_highlights
21662            .get(&HighlightKey::Type(TypeId::of::<
21663                items::BufferSearchHighlights,
21664            >()));
21665
21666        if let Some((_color, ranges)) = highlights {
21667            ranges
21668                .iter()
21669                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
21670                .collect_vec()
21671        } else {
21672            vec![]
21673        }
21674    }
21675
21676    fn document_highlights_for_position<'a>(
21677        &'a self,
21678        position: Anchor,
21679        buffer: &'a MultiBufferSnapshot,
21680    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
21681        let read_highlights = self
21682            .background_highlights
21683            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightRead>()))
21684            .map(|h| &h.1);
21685        let write_highlights = self
21686            .background_highlights
21687            .get(&HighlightKey::Type(TypeId::of::<DocumentHighlightWrite>()))
21688            .map(|h| &h.1);
21689        let left_position = position.bias_left(buffer);
21690        let right_position = position.bias_right(buffer);
21691        read_highlights
21692            .into_iter()
21693            .chain(write_highlights)
21694            .flat_map(move |ranges| {
21695                let start_ix = match ranges.binary_search_by(|probe| {
21696                    let cmp = probe.end.cmp(&left_position, buffer);
21697                    if cmp.is_ge() {
21698                        Ordering::Greater
21699                    } else {
21700                        Ordering::Less
21701                    }
21702                }) {
21703                    Ok(i) | Err(i) => i,
21704                };
21705
21706                ranges[start_ix..]
21707                    .iter()
21708                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
21709            })
21710    }
21711
21712    pub fn has_background_highlights<T: 'static>(&self) -> bool {
21713        self.background_highlights
21714            .get(&HighlightKey::Type(TypeId::of::<T>()))
21715            .is_some_and(|(_, highlights)| !highlights.is_empty())
21716    }
21717
21718    /// Returns all background highlights for a given range.
21719    ///
21720    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
21721    pub fn background_highlights_in_range(
21722        &self,
21723        search_range: Range<Anchor>,
21724        display_snapshot: &DisplaySnapshot,
21725        theme: &Theme,
21726    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21727        let mut results = Vec::new();
21728        for (color_fetcher, ranges) in self.background_highlights.values() {
21729            let start_ix = match ranges.binary_search_by(|probe| {
21730                let cmp = probe
21731                    .end
21732                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21733                if cmp.is_gt() {
21734                    Ordering::Greater
21735                } else {
21736                    Ordering::Less
21737                }
21738            }) {
21739                Ok(i) | Err(i) => i,
21740            };
21741            for (index, range) in ranges[start_ix..].iter().enumerate() {
21742                if range
21743                    .start
21744                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21745                    .is_ge()
21746                {
21747                    break;
21748                }
21749
21750                let color = color_fetcher(&(start_ix + index), theme);
21751                let start = range.start.to_display_point(display_snapshot);
21752                let end = range.end.to_display_point(display_snapshot);
21753                results.push((start..end, color))
21754            }
21755        }
21756        results
21757    }
21758
21759    pub fn gutter_highlights_in_range(
21760        &self,
21761        search_range: Range<Anchor>,
21762        display_snapshot: &DisplaySnapshot,
21763        cx: &App,
21764    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
21765        let mut results = Vec::new();
21766        for (color_fetcher, ranges) in self.gutter_highlights.values() {
21767            let color = color_fetcher(cx);
21768            let start_ix = match ranges.binary_search_by(|probe| {
21769                let cmp = probe
21770                    .end
21771                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
21772                if cmp.is_gt() {
21773                    Ordering::Greater
21774                } else {
21775                    Ordering::Less
21776                }
21777            }) {
21778                Ok(i) | Err(i) => i,
21779            };
21780            for range in &ranges[start_ix..] {
21781                if range
21782                    .start
21783                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
21784                    .is_ge()
21785                {
21786                    break;
21787                }
21788
21789                let start = range.start.to_display_point(display_snapshot);
21790                let end = range.end.to_display_point(display_snapshot);
21791                results.push((start..end, color))
21792            }
21793        }
21794        results
21795    }
21796
21797    /// Get the text ranges corresponding to the redaction query
21798    pub fn redacted_ranges(
21799        &self,
21800        search_range: Range<Anchor>,
21801        display_snapshot: &DisplaySnapshot,
21802        cx: &App,
21803    ) -> Vec<Range<DisplayPoint>> {
21804        display_snapshot
21805            .buffer_snapshot()
21806            .redacted_ranges(search_range, |file| {
21807                if let Some(file) = file {
21808                    file.is_private()
21809                        && EditorSettings::get(
21810                            Some(SettingsLocation {
21811                                worktree_id: file.worktree_id(cx),
21812                                path: file.path().as_ref(),
21813                            }),
21814                            cx,
21815                        )
21816                        .redact_private_values
21817                } else {
21818                    false
21819                }
21820            })
21821            .map(|range| {
21822                range.start.to_display_point(display_snapshot)
21823                    ..range.end.to_display_point(display_snapshot)
21824            })
21825            .collect()
21826    }
21827
21828    pub fn highlight_text_key<T: 'static>(
21829        &mut self,
21830        key: usize,
21831        ranges: Vec<Range<Anchor>>,
21832        style: HighlightStyle,
21833        merge: bool,
21834        cx: &mut Context<Self>,
21835    ) {
21836        self.display_map.update(cx, |map, cx| {
21837            map.highlight_text(
21838                HighlightKey::TypePlus(TypeId::of::<T>(), key),
21839                ranges,
21840                style,
21841                merge,
21842                cx,
21843            );
21844        });
21845        cx.notify();
21846    }
21847
21848    pub fn highlight_text<T: 'static>(
21849        &mut self,
21850        ranges: Vec<Range<Anchor>>,
21851        style: HighlightStyle,
21852        cx: &mut Context<Self>,
21853    ) {
21854        self.display_map.update(cx, |map, cx| {
21855            map.highlight_text(
21856                HighlightKey::Type(TypeId::of::<T>()),
21857                ranges,
21858                style,
21859                false,
21860                cx,
21861            )
21862        });
21863        cx.notify();
21864    }
21865
21866    pub fn text_highlights<'a, T: 'static>(
21867        &'a self,
21868        cx: &'a App,
21869    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
21870        self.display_map.read(cx).text_highlights(TypeId::of::<T>())
21871    }
21872
21873    pub fn clear_highlights<T: 'static>(&mut self, cx: &mut Context<Self>) {
21874        let cleared = self
21875            .display_map
21876            .update(cx, |map, _| map.clear_highlights(TypeId::of::<T>()));
21877        if cleared {
21878            cx.notify();
21879        }
21880    }
21881
21882    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
21883        (self.read_only(cx) || self.blink_manager.read(cx).visible())
21884            && self.focus_handle.is_focused(window)
21885    }
21886
21887    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
21888        self.show_cursor_when_unfocused = is_enabled;
21889        cx.notify();
21890    }
21891
21892    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
21893        cx.notify();
21894    }
21895
21896    fn on_debug_session_event(
21897        &mut self,
21898        _session: Entity<Session>,
21899        event: &SessionEvent,
21900        cx: &mut Context<Self>,
21901    ) {
21902        if let SessionEvent::InvalidateInlineValue = event {
21903            self.refresh_inline_values(cx);
21904        }
21905    }
21906
21907    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
21908        let Some(project) = self.project.clone() else {
21909            return;
21910        };
21911
21912        if !self.inline_value_cache.enabled {
21913            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
21914            self.splice_inlays(&inlays, Vec::new(), cx);
21915            return;
21916        }
21917
21918        let current_execution_position = self
21919            .highlighted_rows
21920            .get(&TypeId::of::<ActiveDebugLine>())
21921            .and_then(|lines| lines.last().map(|line| line.range.end));
21922
21923        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
21924            let inline_values = editor
21925                .update(cx, |editor, cx| {
21926                    let Some(current_execution_position) = current_execution_position else {
21927                        return Some(Task::ready(Ok(Vec::new())));
21928                    };
21929
21930                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
21931                        let snapshot = buffer.snapshot(cx);
21932
21933                        let excerpt = snapshot.excerpt_containing(
21934                            current_execution_position..current_execution_position,
21935                        )?;
21936
21937                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
21938                    })?;
21939
21940                    let range =
21941                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
21942
21943                    project.inline_values(buffer, range, cx)
21944                })
21945                .ok()
21946                .flatten()?
21947                .await
21948                .context("refreshing debugger inlays")
21949                .log_err()?;
21950
21951            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
21952
21953            for (buffer_id, inline_value) in inline_values
21954                .into_iter()
21955                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
21956            {
21957                buffer_inline_values
21958                    .entry(buffer_id)
21959                    .or_default()
21960                    .push(inline_value);
21961            }
21962
21963            editor
21964                .update(cx, |editor, cx| {
21965                    let snapshot = editor.buffer.read(cx).snapshot(cx);
21966                    let mut new_inlays = Vec::default();
21967
21968                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
21969                        let buffer_id = buffer_snapshot.remote_id();
21970                        buffer_inline_values
21971                            .get(&buffer_id)
21972                            .into_iter()
21973                            .flatten()
21974                            .for_each(|hint| {
21975                                let inlay = Inlay::debugger(
21976                                    post_inc(&mut editor.next_inlay_id),
21977                                    Anchor::in_buffer(excerpt_id, hint.position),
21978                                    hint.text(),
21979                                );
21980                                if !inlay.text().chars().contains(&'\n') {
21981                                    new_inlays.push(inlay);
21982                                }
21983                            });
21984                    }
21985
21986                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
21987                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
21988
21989                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
21990                })
21991                .ok()?;
21992            Some(())
21993        });
21994    }
21995
21996    fn on_buffer_event(
21997        &mut self,
21998        multibuffer: &Entity<MultiBuffer>,
21999        event: &multi_buffer::Event,
22000        window: &mut Window,
22001        cx: &mut Context<Self>,
22002    ) {
22003        match event {
22004            multi_buffer::Event::Edited { edited_buffer } => {
22005                self.scrollbar_marker_state.dirty = true;
22006                self.active_indent_guides_state.dirty = true;
22007                self.refresh_active_diagnostics(cx);
22008                self.refresh_code_actions(window, cx);
22009                self.refresh_single_line_folds(window, cx);
22010                self.refresh_matching_bracket_highlights(window, cx);
22011                if self.has_active_edit_prediction() {
22012                    self.update_visible_edit_prediction(window, cx);
22013                }
22014
22015                if let Some(buffer) = edited_buffer {
22016                    if buffer.read(cx).file().is_none() {
22017                        cx.emit(EditorEvent::TitleChanged);
22018                    }
22019
22020                    if self.project.is_some() {
22021                        let buffer_id = buffer.read(cx).remote_id();
22022                        self.register_buffer(buffer_id, cx);
22023                        self.update_lsp_data(Some(buffer_id), window, cx);
22024                        self.refresh_inlay_hints(
22025                            InlayHintRefreshReason::BufferEdited(buffer_id),
22026                            cx,
22027                        );
22028                    }
22029                }
22030
22031                cx.emit(EditorEvent::BufferEdited);
22032                cx.emit(SearchEvent::MatchesInvalidated);
22033
22034                let Some(project) = &self.project else { return };
22035                let (telemetry, is_via_ssh) = {
22036                    let project = project.read(cx);
22037                    let telemetry = project.client().telemetry().clone();
22038                    let is_via_ssh = project.is_via_remote_server();
22039                    (telemetry, is_via_ssh)
22040                };
22041                telemetry.log_edit_event("editor", is_via_ssh);
22042            }
22043            multi_buffer::Event::ExcerptsAdded {
22044                buffer,
22045                predecessor,
22046                excerpts,
22047            } => {
22048                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22049                let buffer_id = buffer.read(cx).remote_id();
22050                if self.buffer.read(cx).diff_for(buffer_id).is_none()
22051                    && let Some(project) = &self.project
22052                {
22053                    update_uncommitted_diff_for_buffer(
22054                        cx.entity(),
22055                        project,
22056                        [buffer.clone()],
22057                        self.buffer.clone(),
22058                        cx,
22059                    )
22060                    .detach();
22061                }
22062                self.update_lsp_data(Some(buffer_id), window, cx);
22063                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
22064                self.colorize_brackets(false, cx);
22065                cx.emit(EditorEvent::ExcerptsAdded {
22066                    buffer: buffer.clone(),
22067                    predecessor: *predecessor,
22068                    excerpts: excerpts.clone(),
22069                });
22070            }
22071            multi_buffer::Event::ExcerptsRemoved {
22072                ids,
22073                removed_buffer_ids,
22074            } => {
22075                if let Some(inlay_hints) = &mut self.inlay_hints {
22076                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
22077                }
22078                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
22079                for buffer_id in removed_buffer_ids {
22080                    self.registered_buffers.remove(buffer_id);
22081                }
22082                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22083                cx.emit(EditorEvent::ExcerptsRemoved {
22084                    ids: ids.clone(),
22085                    removed_buffer_ids: removed_buffer_ids.clone(),
22086                });
22087            }
22088            multi_buffer::Event::ExcerptsEdited {
22089                excerpt_ids,
22090                buffer_ids,
22091            } => {
22092                self.display_map.update(cx, |map, cx| {
22093                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
22094                });
22095                cx.emit(EditorEvent::ExcerptsEdited {
22096                    ids: excerpt_ids.clone(),
22097                });
22098            }
22099            multi_buffer::Event::ExcerptsExpanded { ids } => {
22100                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
22101                self.refresh_document_highlights(cx);
22102                for id in ids {
22103                    self.fetched_tree_sitter_chunks.remove(id);
22104                }
22105                self.colorize_brackets(false, cx);
22106                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
22107            }
22108            multi_buffer::Event::Reparsed(buffer_id) => {
22109                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22110                self.refresh_selected_text_highlights(true, window, cx);
22111                self.colorize_brackets(true, cx);
22112                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22113
22114                cx.emit(EditorEvent::Reparsed(*buffer_id));
22115            }
22116            multi_buffer::Event::DiffHunksToggled => {
22117                self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22118            }
22119            multi_buffer::Event::LanguageChanged(buffer_id, is_fresh_language) => {
22120                if !is_fresh_language {
22121                    self.registered_buffers.remove(&buffer_id);
22122                }
22123                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
22124                cx.emit(EditorEvent::Reparsed(*buffer_id));
22125                cx.notify();
22126            }
22127            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
22128            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
22129            multi_buffer::Event::FileHandleChanged
22130            | multi_buffer::Event::Reloaded
22131            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
22132            multi_buffer::Event::DiagnosticsUpdated => {
22133                self.update_diagnostics_state(window, cx);
22134            }
22135            _ => {}
22136        };
22137    }
22138
22139    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
22140        if !self.diagnostics_enabled() {
22141            return;
22142        }
22143        self.refresh_active_diagnostics(cx);
22144        self.refresh_inline_diagnostics(true, window, cx);
22145        self.scrollbar_marker_state.dirty = true;
22146        cx.notify();
22147    }
22148
22149    pub fn start_temporary_diff_override(&mut self) {
22150        self.load_diff_task.take();
22151        self.temporary_diff_override = true;
22152    }
22153
22154    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
22155        self.temporary_diff_override = false;
22156        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
22157        self.buffer.update(cx, |buffer, cx| {
22158            buffer.set_all_diff_hunks_collapsed(cx);
22159        });
22160
22161        if let Some(project) = self.project.clone() {
22162            self.load_diff_task = Some(
22163                update_uncommitted_diff_for_buffer(
22164                    cx.entity(),
22165                    &project,
22166                    self.buffer.read(cx).all_buffers(),
22167                    self.buffer.clone(),
22168                    cx,
22169                )
22170                .shared(),
22171            );
22172        }
22173    }
22174
22175    fn on_display_map_changed(
22176        &mut self,
22177        _: Entity<DisplayMap>,
22178        _: &mut Window,
22179        cx: &mut Context<Self>,
22180    ) {
22181        cx.notify();
22182    }
22183
22184    fn fetch_accent_data(&self, cx: &App) -> Option<AccentData> {
22185        if !self.mode.is_full() {
22186            return None;
22187        }
22188
22189        let theme_settings = theme::ThemeSettings::get_global(cx);
22190        let theme = cx.theme();
22191        let accent_colors = theme.accents().clone();
22192
22193        let accent_overrides = theme_settings
22194            .theme_overrides
22195            .get(theme.name.as_ref())
22196            .map(|theme_style| &theme_style.accents)
22197            .into_iter()
22198            .flatten()
22199            .chain(
22200                theme_settings
22201                    .experimental_theme_overrides
22202                    .as_ref()
22203                    .map(|overrides| &overrides.accents)
22204                    .into_iter()
22205                    .flatten(),
22206            )
22207            .flat_map(|accent| accent.0.clone())
22208            .collect();
22209
22210        Some(AccentData {
22211            colors: accent_colors,
22212            overrides: accent_overrides,
22213        })
22214    }
22215
22216    fn fetch_applicable_language_settings(
22217        &self,
22218        cx: &App,
22219    ) -> HashMap<Option<LanguageName>, LanguageSettings> {
22220        if !self.mode.is_full() {
22221            return HashMap::default();
22222        }
22223
22224        self.buffer().read(cx).all_buffers().into_iter().fold(
22225            HashMap::default(),
22226            |mut acc, buffer| {
22227                let buffer = buffer.read(cx);
22228                let language = buffer.language().map(|language| language.name());
22229                if let hash_map::Entry::Vacant(v) = acc.entry(language.clone()) {
22230                    let file = buffer.file();
22231                    v.insert(language_settings(language, file, cx).into_owned());
22232                }
22233                acc
22234            },
22235        )
22236    }
22237
22238    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22239        let new_language_settings = self.fetch_applicable_language_settings(cx);
22240        let language_settings_changed = new_language_settings != self.applicable_language_settings;
22241        self.applicable_language_settings = new_language_settings;
22242
22243        let new_accents = self.fetch_accent_data(cx);
22244        let accents_changed = new_accents != self.accent_data;
22245        self.accent_data = new_accents;
22246
22247        if self.diagnostics_enabled() {
22248            let new_severity = EditorSettings::get_global(cx)
22249                .diagnostics_max_severity
22250                .unwrap_or(DiagnosticSeverity::Hint);
22251            self.set_max_diagnostics_severity(new_severity, cx);
22252        }
22253        self.tasks_update_task = Some(self.refresh_runnables(window, cx));
22254        self.update_edit_prediction_settings(cx);
22255        self.refresh_edit_prediction(true, false, window, cx);
22256        self.refresh_inline_values(cx);
22257        self.refresh_inlay_hints(
22258            InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
22259                self.selections.newest_anchor().head(),
22260                &self.buffer.read(cx).snapshot(cx),
22261                cx,
22262            )),
22263            cx,
22264        );
22265
22266        let old_cursor_shape = self.cursor_shape;
22267        let old_show_breadcrumbs = self.show_breadcrumbs;
22268
22269        {
22270            let editor_settings = EditorSettings::get_global(cx);
22271            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
22272            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
22273            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
22274            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
22275        }
22276
22277        if old_cursor_shape != self.cursor_shape {
22278            cx.emit(EditorEvent::CursorShapeChanged);
22279        }
22280
22281        if old_show_breadcrumbs != self.show_breadcrumbs {
22282            cx.emit(EditorEvent::BreadcrumbsChanged);
22283        }
22284
22285        let project_settings = ProjectSettings::get_global(cx);
22286        self.buffer_serialization = self
22287            .should_serialize_buffer()
22288            .then(|| BufferSerialization::new(project_settings.session.restore_unsaved_buffers));
22289
22290        if self.mode.is_full() {
22291            let show_inline_diagnostics = project_settings.diagnostics.inline.enabled;
22292            let inline_blame_enabled = project_settings.git.inline_blame.enabled;
22293            if self.show_inline_diagnostics != show_inline_diagnostics {
22294                self.show_inline_diagnostics = show_inline_diagnostics;
22295                self.refresh_inline_diagnostics(false, window, cx);
22296            }
22297
22298            if self.git_blame_inline_enabled != inline_blame_enabled {
22299                self.toggle_git_blame_inline_internal(false, window, cx);
22300            }
22301
22302            let minimap_settings = EditorSettings::get_global(cx).minimap;
22303            if self.minimap_visibility != MinimapVisibility::Disabled {
22304                if self.minimap_visibility.settings_visibility()
22305                    != minimap_settings.minimap_enabled()
22306                {
22307                    self.set_minimap_visibility(
22308                        MinimapVisibility::for_mode(self.mode(), cx),
22309                        window,
22310                        cx,
22311                    );
22312                } else if let Some(minimap_entity) = self.minimap.as_ref() {
22313                    minimap_entity.update(cx, |minimap_editor, cx| {
22314                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
22315                    })
22316                }
22317            }
22318
22319            if language_settings_changed || accents_changed {
22320                self.colorize_brackets(true, cx);
22321            }
22322
22323            if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
22324                colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
22325            }) {
22326                if !inlay_splice.is_empty() {
22327                    self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
22328                }
22329                self.refresh_colors_for_visible_range(None, window, cx);
22330            }
22331        }
22332
22333        cx.notify();
22334    }
22335
22336    pub fn set_searchable(&mut self, searchable: bool) {
22337        self.searchable = searchable;
22338    }
22339
22340    pub fn searchable(&self) -> bool {
22341        self.searchable
22342    }
22343
22344    pub fn open_excerpts_in_split(
22345        &mut self,
22346        _: &OpenExcerptsSplit,
22347        window: &mut Window,
22348        cx: &mut Context<Self>,
22349    ) {
22350        self.open_excerpts_common(None, true, window, cx)
22351    }
22352
22353    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
22354        self.open_excerpts_common(None, false, window, cx)
22355    }
22356
22357    fn open_excerpts_common(
22358        &mut self,
22359        jump_data: Option<JumpData>,
22360        split: bool,
22361        window: &mut Window,
22362        cx: &mut Context<Self>,
22363    ) {
22364        let Some(workspace) = self.workspace() else {
22365            cx.propagate();
22366            return;
22367        };
22368
22369        if self.buffer.read(cx).is_singleton() {
22370            cx.propagate();
22371            return;
22372        }
22373
22374        let mut new_selections_by_buffer = HashMap::default();
22375        match &jump_data {
22376            Some(JumpData::MultiBufferPoint {
22377                excerpt_id,
22378                position,
22379                anchor,
22380                line_offset_from_top,
22381            }) => {
22382                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
22383                if let Some(buffer) = multi_buffer_snapshot
22384                    .buffer_id_for_excerpt(*excerpt_id)
22385                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
22386                {
22387                    let buffer_snapshot = buffer.read(cx).snapshot();
22388                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
22389                        language::ToPoint::to_point(anchor, &buffer_snapshot)
22390                    } else {
22391                        buffer_snapshot.clip_point(*position, Bias::Left)
22392                    };
22393                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
22394                    new_selections_by_buffer.insert(
22395                        buffer,
22396                        (
22397                            vec![BufferOffset(jump_to_offset)..BufferOffset(jump_to_offset)],
22398                            Some(*line_offset_from_top),
22399                        ),
22400                    );
22401                }
22402            }
22403            Some(JumpData::MultiBufferRow {
22404                row,
22405                line_offset_from_top,
22406            }) => {
22407                let point = MultiBufferPoint::new(row.0, 0);
22408                if let Some((buffer, buffer_point, _)) =
22409                    self.buffer.read(cx).point_to_buffer_point(point, cx)
22410                {
22411                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
22412                    new_selections_by_buffer
22413                        .entry(buffer)
22414                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
22415                        .0
22416                        .push(BufferOffset(buffer_offset)..BufferOffset(buffer_offset))
22417                }
22418            }
22419            None => {
22420                let selections = self
22421                    .selections
22422                    .all::<MultiBufferOffset>(&self.display_snapshot(cx));
22423                let multi_buffer = self.buffer.read(cx);
22424                for selection in selections {
22425                    for (snapshot, range, _, anchor) in multi_buffer
22426                        .snapshot(cx)
22427                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
22428                    {
22429                        if let Some(anchor) = anchor {
22430                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
22431                            else {
22432                                continue;
22433                            };
22434                            let offset = text::ToOffset::to_offset(
22435                                &anchor.text_anchor,
22436                                &buffer_handle.read(cx).snapshot(),
22437                            );
22438                            let range = BufferOffset(offset)..BufferOffset(offset);
22439                            new_selections_by_buffer
22440                                .entry(buffer_handle)
22441                                .or_insert((Vec::new(), None))
22442                                .0
22443                                .push(range)
22444                        } else {
22445                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
22446                            else {
22447                                continue;
22448                            };
22449                            new_selections_by_buffer
22450                                .entry(buffer_handle)
22451                                .or_insert((Vec::new(), None))
22452                                .0
22453                                .push(range)
22454                        }
22455                    }
22456                }
22457            }
22458        }
22459
22460        new_selections_by_buffer
22461            .retain(|buffer, _| Self::can_open_excerpts_in_file(buffer.read(cx).file()));
22462
22463        if new_selections_by_buffer.is_empty() {
22464            return;
22465        }
22466
22467        // We defer the pane interaction because we ourselves are a workspace item
22468        // and activating a new item causes the pane to call a method on us reentrantly,
22469        // which panics if we're on the stack.
22470        window.defer(cx, move |window, cx| {
22471            workspace.update(cx, |workspace, cx| {
22472                let pane = if split {
22473                    workspace.adjacent_pane(window, cx)
22474                } else {
22475                    workspace.active_pane().clone()
22476                };
22477
22478                for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
22479                    let buffer_read = buffer.read(cx);
22480                    let (has_file, is_project_file) = if let Some(file) = buffer_read.file() {
22481                        (true, project::File::from_dyn(Some(file)).is_some())
22482                    } else {
22483                        (false, false)
22484                    };
22485
22486                    // If project file is none workspace.open_project_item will fail to open the excerpt
22487                    // in a pre existing workspace item if one exists, because Buffer entity_id will be None
22488                    // so we check if there's a tab match in that case first
22489                    let editor = (!has_file || !is_project_file)
22490                        .then(|| {
22491                            // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
22492                            // so `workspace.open_project_item` will never find them, always opening a new editor.
22493                            // Instead, we try to activate the existing editor in the pane first.
22494                            let (editor, pane_item_index, pane_item_id) =
22495                                pane.read(cx).items().enumerate().find_map(|(i, item)| {
22496                                    let editor = item.downcast::<Editor>()?;
22497                                    let singleton_buffer =
22498                                        editor.read(cx).buffer().read(cx).as_singleton()?;
22499                                    if singleton_buffer == buffer {
22500                                        Some((editor, i, item.item_id()))
22501                                    } else {
22502                                        None
22503                                    }
22504                                })?;
22505                            pane.update(cx, |pane, cx| {
22506                                pane.activate_item(pane_item_index, true, true, window, cx);
22507                                if !PreviewTabsSettings::get_global(cx)
22508                                    .enable_preview_from_multibuffer
22509                                {
22510                                    pane.unpreview_item_if_preview(pane_item_id);
22511                                }
22512                            });
22513                            Some(editor)
22514                        })
22515                        .flatten()
22516                        .unwrap_or_else(|| {
22517                            let keep_old_preview = PreviewTabsSettings::get_global(cx)
22518                                .enable_keep_preview_on_code_navigation;
22519                            let allow_new_preview =
22520                                PreviewTabsSettings::get_global(cx).enable_preview_from_multibuffer;
22521                            workspace.open_project_item::<Self>(
22522                                pane.clone(),
22523                                buffer,
22524                                true,
22525                                true,
22526                                keep_old_preview,
22527                                allow_new_preview,
22528                                window,
22529                                cx,
22530                            )
22531                        });
22532
22533                    editor.update(cx, |editor, cx| {
22534                        if has_file && !is_project_file {
22535                            editor.set_read_only(true);
22536                        }
22537                        let autoscroll = match scroll_offset {
22538                            Some(scroll_offset) => Autoscroll::top_relative(scroll_offset as usize),
22539                            None => Autoscroll::newest(),
22540                        };
22541                        let nav_history = editor.nav_history.take();
22542                        let multibuffer_snapshot = editor.buffer().read(cx).snapshot(cx);
22543                        let Some((&excerpt_id, _, buffer_snapshot)) =
22544                            multibuffer_snapshot.as_singleton()
22545                        else {
22546                            return;
22547                        };
22548                        editor.change_selections(
22549                            SelectionEffects::scroll(autoscroll),
22550                            window,
22551                            cx,
22552                            |s| {
22553                                s.select_ranges(ranges.into_iter().map(|range| {
22554                                    let range = buffer_snapshot.anchor_before(range.start)
22555                                        ..buffer_snapshot.anchor_after(range.end);
22556                                    multibuffer_snapshot
22557                                        .anchor_range_in_excerpt(excerpt_id, range)
22558                                        .unwrap()
22559                                }));
22560                            },
22561                        );
22562                        editor.nav_history = nav_history;
22563                    });
22564                }
22565            })
22566        });
22567    }
22568
22569    // Allow opening excerpts for buffers that either belong to the current project
22570    // or represent synthetic/non-local files (e.g., git blobs). File-less buffers
22571    // are also supported so tests and other in-memory views keep working.
22572    fn can_open_excerpts_in_file(file: Option<&Arc<dyn language::File>>) -> bool {
22573        file.is_none_or(|file| project::File::from_dyn(Some(file)).is_some() || !file.is_local())
22574    }
22575
22576    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<MultiBufferOffsetUtf16>>> {
22577        let snapshot = self.buffer.read(cx).read(cx);
22578        let (_, ranges) = self.text_highlights::<InputComposition>(cx)?;
22579        Some(
22580            ranges
22581                .iter()
22582                .map(move |range| {
22583                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
22584                })
22585                .collect(),
22586        )
22587    }
22588
22589    fn selection_replacement_ranges(
22590        &self,
22591        range: Range<MultiBufferOffsetUtf16>,
22592        cx: &mut App,
22593    ) -> Vec<Range<MultiBufferOffsetUtf16>> {
22594        let selections = self
22595            .selections
22596            .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22597        let newest_selection = selections
22598            .iter()
22599            .max_by_key(|selection| selection.id)
22600            .unwrap();
22601        let start_delta = range.start.0.0 as isize - newest_selection.start.0.0 as isize;
22602        let end_delta = range.end.0.0 as isize - newest_selection.end.0.0 as isize;
22603        let snapshot = self.buffer.read(cx).read(cx);
22604        selections
22605            .into_iter()
22606            .map(|mut selection| {
22607                selection.start.0.0 =
22608                    (selection.start.0.0 as isize).saturating_add(start_delta) as usize;
22609                selection.end.0.0 = (selection.end.0.0 as isize).saturating_add(end_delta) as usize;
22610                snapshot.clip_offset_utf16(selection.start, Bias::Left)
22611                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
22612            })
22613            .collect()
22614    }
22615
22616    fn report_editor_event(
22617        &self,
22618        reported_event: ReportEditorEvent,
22619        file_extension: Option<String>,
22620        cx: &App,
22621    ) {
22622        if cfg!(any(test, feature = "test-support")) {
22623            return;
22624        }
22625
22626        let Some(project) = &self.project else { return };
22627
22628        // If None, we are in a file without an extension
22629        let file = self
22630            .buffer
22631            .read(cx)
22632            .as_singleton()
22633            .and_then(|b| b.read(cx).file());
22634        let file_extension = file_extension.or(file
22635            .as_ref()
22636            .and_then(|file| Path::new(file.file_name(cx)).extension())
22637            .and_then(|e| e.to_str())
22638            .map(|a| a.to_string()));
22639
22640        let vim_mode_enabled = self.is_vim_mode_enabled(cx);
22641        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
22642        let copilot_enabled = edit_predictions_provider
22643            == language::language_settings::EditPredictionProvider::Copilot;
22644        let copilot_enabled_for_language = self
22645            .buffer
22646            .read(cx)
22647            .language_settings(cx)
22648            .show_edit_predictions;
22649
22650        let project = project.read(cx);
22651        let event_type = reported_event.event_type();
22652
22653        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
22654            telemetry::event!(
22655                event_type,
22656                type = if auto_saved {"autosave"} else {"manual"},
22657                file_extension,
22658                vim_mode_enabled,
22659                copilot_enabled,
22660                copilot_enabled_for_language,
22661                edit_predictions_provider,
22662                is_via_ssh = project.is_via_remote_server(),
22663            );
22664        } else {
22665            telemetry::event!(
22666                event_type,
22667                file_extension,
22668                vim_mode_enabled,
22669                copilot_enabled,
22670                copilot_enabled_for_language,
22671                edit_predictions_provider,
22672                is_via_ssh = project.is_via_remote_server(),
22673            );
22674        };
22675    }
22676
22677    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
22678    /// with each line being an array of {text, highlight} objects.
22679    fn copy_highlight_json(
22680        &mut self,
22681        _: &CopyHighlightJson,
22682        window: &mut Window,
22683        cx: &mut Context<Self>,
22684    ) {
22685        #[derive(Serialize)]
22686        struct Chunk<'a> {
22687            text: String,
22688            highlight: Option<&'a str>,
22689        }
22690
22691        let snapshot = self.buffer.read(cx).snapshot(cx);
22692        let range = self
22693            .selected_text_range(false, window, cx)
22694            .and_then(|selection| {
22695                if selection.range.is_empty() {
22696                    None
22697                } else {
22698                    Some(
22699                        snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22700                            selection.range.start,
22701                        )))
22702                            ..snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
22703                                selection.range.end,
22704                            ))),
22705                    )
22706                }
22707            })
22708            .unwrap_or_else(|| MultiBufferOffset(0)..snapshot.len());
22709
22710        let chunks = snapshot.chunks(range, true);
22711        let mut lines = Vec::new();
22712        let mut line: VecDeque<Chunk> = VecDeque::new();
22713
22714        let Some(style) = self.style.as_ref() else {
22715            return;
22716        };
22717
22718        for chunk in chunks {
22719            let highlight = chunk
22720                .syntax_highlight_id
22721                .and_then(|id| id.name(&style.syntax));
22722            let mut chunk_lines = chunk.text.split('\n').peekable();
22723            while let Some(text) = chunk_lines.next() {
22724                let mut merged_with_last_token = false;
22725                if let Some(last_token) = line.back_mut()
22726                    && last_token.highlight == highlight
22727                {
22728                    last_token.text.push_str(text);
22729                    merged_with_last_token = true;
22730                }
22731
22732                if !merged_with_last_token {
22733                    line.push_back(Chunk {
22734                        text: text.into(),
22735                        highlight,
22736                    });
22737                }
22738
22739                if chunk_lines.peek().is_some() {
22740                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
22741                        line.pop_front();
22742                    }
22743                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
22744                        line.pop_back();
22745                    }
22746
22747                    lines.push(mem::take(&mut line));
22748                }
22749            }
22750        }
22751
22752        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
22753            return;
22754        };
22755        cx.write_to_clipboard(ClipboardItem::new_string(lines));
22756    }
22757
22758    pub fn open_context_menu(
22759        &mut self,
22760        _: &OpenContextMenu,
22761        window: &mut Window,
22762        cx: &mut Context<Self>,
22763    ) {
22764        self.request_autoscroll(Autoscroll::newest(), cx);
22765        let position = self
22766            .selections
22767            .newest_display(&self.display_snapshot(cx))
22768            .start;
22769        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
22770    }
22771
22772    pub fn replay_insert_event(
22773        &mut self,
22774        text: &str,
22775        relative_utf16_range: Option<Range<isize>>,
22776        window: &mut Window,
22777        cx: &mut Context<Self>,
22778    ) {
22779        if !self.input_enabled {
22780            cx.emit(EditorEvent::InputIgnored { text: text.into() });
22781            return;
22782        }
22783        if let Some(relative_utf16_range) = relative_utf16_range {
22784            let selections = self
22785                .selections
22786                .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
22787            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22788                let new_ranges = selections.into_iter().map(|range| {
22789                    let start = MultiBufferOffsetUtf16(OffsetUtf16(
22790                        range
22791                            .head()
22792                            .0
22793                            .0
22794                            .saturating_add_signed(relative_utf16_range.start),
22795                    ));
22796                    let end = MultiBufferOffsetUtf16(OffsetUtf16(
22797                        range
22798                            .head()
22799                            .0
22800                            .0
22801                            .saturating_add_signed(relative_utf16_range.end),
22802                    ));
22803                    start..end
22804                });
22805                s.select_ranges(new_ranges);
22806            });
22807        }
22808
22809        self.handle_input(text, window, cx);
22810    }
22811
22812    pub fn is_focused(&self, window: &Window) -> bool {
22813        self.focus_handle.is_focused(window)
22814    }
22815
22816    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22817        cx.emit(EditorEvent::Focused);
22818
22819        if let Some(descendant) = self
22820            .last_focused_descendant
22821            .take()
22822            .and_then(|descendant| descendant.upgrade())
22823        {
22824            window.focus(&descendant);
22825        } else {
22826            if let Some(blame) = self.blame.as_ref() {
22827                blame.update(cx, GitBlame::focus)
22828            }
22829
22830            self.blink_manager.update(cx, BlinkManager::enable);
22831            self.show_cursor_names(window, cx);
22832            self.buffer.update(cx, |buffer, cx| {
22833                buffer.finalize_last_transaction(cx);
22834                if self.leader_id.is_none() {
22835                    buffer.set_active_selections(
22836                        &self.selections.disjoint_anchors_arc(),
22837                        self.selections.line_mode(),
22838                        self.cursor_shape,
22839                        cx,
22840                    );
22841                }
22842            });
22843
22844            if let Some(position_map) = self.last_position_map.clone() {
22845                EditorElement::mouse_moved(
22846                    self,
22847                    &MouseMoveEvent {
22848                        position: window.mouse_position(),
22849                        pressed_button: None,
22850                        modifiers: window.modifiers(),
22851                    },
22852                    &position_map,
22853                    window,
22854                    cx,
22855                );
22856            }
22857        }
22858    }
22859
22860    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
22861        cx.emit(EditorEvent::FocusedIn)
22862    }
22863
22864    fn handle_focus_out(
22865        &mut self,
22866        event: FocusOutEvent,
22867        _window: &mut Window,
22868        cx: &mut Context<Self>,
22869    ) {
22870        if event.blurred != self.focus_handle {
22871            self.last_focused_descendant = Some(event.blurred);
22872        }
22873        self.selection_drag_state = SelectionDragState::None;
22874        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
22875    }
22876
22877    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22878        self.blink_manager.update(cx, BlinkManager::disable);
22879        self.buffer
22880            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
22881
22882        if let Some(blame) = self.blame.as_ref() {
22883            blame.update(cx, GitBlame::blur)
22884        }
22885        if !self.hover_state.focused(window, cx) {
22886            hide_hover(self, cx);
22887        }
22888        if !self
22889            .context_menu
22890            .borrow()
22891            .as_ref()
22892            .is_some_and(|context_menu| context_menu.focused(window, cx))
22893        {
22894            self.hide_context_menu(window, cx);
22895        }
22896        self.take_active_edit_prediction(cx);
22897        cx.emit(EditorEvent::Blurred);
22898        cx.notify();
22899    }
22900
22901    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22902        let mut pending: String = window
22903            .pending_input_keystrokes()
22904            .into_iter()
22905            .flatten()
22906            .filter_map(|keystroke| keystroke.key_char.clone())
22907            .collect();
22908
22909        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
22910            pending = "".to_string();
22911        }
22912
22913        let existing_pending = self
22914            .text_highlights::<PendingInput>(cx)
22915            .map(|(_, ranges)| ranges.to_vec());
22916        if existing_pending.is_none() && pending.is_empty() {
22917            return;
22918        }
22919        let transaction =
22920            self.transact(window, cx, |this, window, cx| {
22921                let selections = this
22922                    .selections
22923                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
22924                let edits = selections
22925                    .iter()
22926                    .map(|selection| (selection.end..selection.end, pending.clone()));
22927                this.edit(edits, cx);
22928                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
22929                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
22930                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
22931                    }));
22932                });
22933                if let Some(existing_ranges) = existing_pending {
22934                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
22935                    this.edit(edits, cx);
22936                }
22937            });
22938
22939        let snapshot = self.snapshot(window, cx);
22940        let ranges = self
22941            .selections
22942            .all::<MultiBufferOffset>(&snapshot.display_snapshot)
22943            .into_iter()
22944            .map(|selection| {
22945                snapshot.buffer_snapshot().anchor_after(selection.end)
22946                    ..snapshot
22947                        .buffer_snapshot()
22948                        .anchor_before(selection.end + pending.len())
22949            })
22950            .collect();
22951
22952        if pending.is_empty() {
22953            self.clear_highlights::<PendingInput>(cx);
22954        } else {
22955            self.highlight_text::<PendingInput>(
22956                ranges,
22957                HighlightStyle {
22958                    underline: Some(UnderlineStyle {
22959                        thickness: px(1.),
22960                        color: None,
22961                        wavy: false,
22962                    }),
22963                    ..Default::default()
22964                },
22965                cx,
22966            );
22967        }
22968
22969        self.ime_transaction = self.ime_transaction.or(transaction);
22970        if let Some(transaction) = self.ime_transaction {
22971            self.buffer.update(cx, |buffer, cx| {
22972                buffer.group_until_transaction(transaction, cx);
22973            });
22974        }
22975
22976        if self.text_highlights::<PendingInput>(cx).is_none() {
22977            self.ime_transaction.take();
22978        }
22979    }
22980
22981    pub fn register_action_renderer(
22982        &mut self,
22983        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
22984    ) -> Subscription {
22985        let id = self.next_editor_action_id.post_inc();
22986        self.editor_actions
22987            .borrow_mut()
22988            .insert(id, Box::new(listener));
22989
22990        let editor_actions = self.editor_actions.clone();
22991        Subscription::new(move || {
22992            editor_actions.borrow_mut().remove(&id);
22993        })
22994    }
22995
22996    pub fn register_action<A: Action>(
22997        &mut self,
22998        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
22999    ) -> Subscription {
23000        let id = self.next_editor_action_id.post_inc();
23001        let listener = Arc::new(listener);
23002        self.editor_actions.borrow_mut().insert(
23003            id,
23004            Box::new(move |_, window, _| {
23005                let listener = listener.clone();
23006                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
23007                    let action = action.downcast_ref().unwrap();
23008                    if phase == DispatchPhase::Bubble {
23009                        listener(action, window, cx)
23010                    }
23011                })
23012            }),
23013        );
23014
23015        let editor_actions = self.editor_actions.clone();
23016        Subscription::new(move || {
23017            editor_actions.borrow_mut().remove(&id);
23018        })
23019    }
23020
23021    pub fn file_header_size(&self) -> u32 {
23022        FILE_HEADER_HEIGHT
23023    }
23024
23025    pub fn restore(
23026        &mut self,
23027        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
23028        window: &mut Window,
23029        cx: &mut Context<Self>,
23030    ) {
23031        self.buffer().update(cx, |multi_buffer, cx| {
23032            for (buffer_id, changes) in revert_changes {
23033                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
23034                    buffer.update(cx, |buffer, cx| {
23035                        buffer.edit(
23036                            changes
23037                                .into_iter()
23038                                .map(|(range, text)| (range, text.to_string())),
23039                            None,
23040                            cx,
23041                        );
23042                    });
23043                }
23044            }
23045        });
23046        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
23047            selections.refresh()
23048        });
23049    }
23050
23051    pub fn to_pixel_point(
23052        &mut self,
23053        source: multi_buffer::Anchor,
23054        editor_snapshot: &EditorSnapshot,
23055        window: &mut Window,
23056        cx: &App,
23057    ) -> Option<gpui::Point<Pixels>> {
23058        let source_point = source.to_display_point(editor_snapshot);
23059        self.display_to_pixel_point(source_point, editor_snapshot, window, cx)
23060    }
23061
23062    pub fn display_to_pixel_point(
23063        &mut self,
23064        source: DisplayPoint,
23065        editor_snapshot: &EditorSnapshot,
23066        window: &mut Window,
23067        cx: &App,
23068    ) -> Option<gpui::Point<Pixels>> {
23069        let line_height = self.style(cx).text.line_height_in_pixels(window.rem_size());
23070        let text_layout_details = self.text_layout_details(window);
23071        let scroll_top = text_layout_details
23072            .scroll_anchor
23073            .scroll_position(editor_snapshot)
23074            .y;
23075
23076        if source.row().as_f64() < scroll_top.floor() {
23077            return None;
23078        }
23079        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
23080        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
23081        Some(gpui::Point::new(source_x, source_y))
23082    }
23083
23084    pub fn has_visible_completions_menu(&self) -> bool {
23085        !self.edit_prediction_preview_is_active()
23086            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
23087                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
23088            })
23089    }
23090
23091    pub fn register_addon<T: Addon>(&mut self, instance: T) {
23092        if self.mode.is_minimap() {
23093            return;
23094        }
23095        self.addons
23096            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
23097    }
23098
23099    pub fn unregister_addon<T: Addon>(&mut self) {
23100        self.addons.remove(&std::any::TypeId::of::<T>());
23101    }
23102
23103    pub fn addon<T: Addon>(&self) -> Option<&T> {
23104        let type_id = std::any::TypeId::of::<T>();
23105        self.addons
23106            .get(&type_id)
23107            .and_then(|item| item.to_any().downcast_ref::<T>())
23108    }
23109
23110    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
23111        let type_id = std::any::TypeId::of::<T>();
23112        self.addons
23113            .get_mut(&type_id)
23114            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
23115    }
23116
23117    fn character_dimensions(&self, window: &mut Window) -> CharacterDimensions {
23118        let text_layout_details = self.text_layout_details(window);
23119        let style = &text_layout_details.editor_style;
23120        let font_id = window.text_system().resolve_font(&style.text.font());
23121        let font_size = style.text.font_size.to_pixels(window.rem_size());
23122        let line_height = style.text.line_height_in_pixels(window.rem_size());
23123        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
23124        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
23125
23126        CharacterDimensions {
23127            em_width,
23128            em_advance,
23129            line_height,
23130        }
23131    }
23132
23133    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
23134        self.load_diff_task.clone()
23135    }
23136
23137    fn read_metadata_from_db(
23138        &mut self,
23139        item_id: u64,
23140        workspace_id: WorkspaceId,
23141        window: &mut Window,
23142        cx: &mut Context<Editor>,
23143    ) {
23144        if self.buffer_kind(cx) == ItemBufferKind::Singleton
23145            && !self.mode.is_minimap()
23146            && WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
23147        {
23148            let buffer_snapshot = OnceCell::new();
23149
23150            if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
23151                && !folds.is_empty()
23152            {
23153                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
23154                self.fold_ranges(
23155                    folds
23156                        .into_iter()
23157                        .map(|(start, end)| {
23158                            snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
23159                                ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
23160                        })
23161                        .collect(),
23162                    false,
23163                    window,
23164                    cx,
23165                );
23166            }
23167
23168            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
23169                && !selections.is_empty()
23170            {
23171                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
23172                // skip adding the initial selection to selection history
23173                self.selection_history.mode = SelectionHistoryMode::Skipping;
23174                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
23175                    s.select_ranges(selections.into_iter().map(|(start, end)| {
23176                        snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
23177                            ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
23178                    }));
23179                });
23180                self.selection_history.mode = SelectionHistoryMode::Normal;
23181            };
23182        }
23183
23184        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
23185    }
23186
23187    fn update_lsp_data(
23188        &mut self,
23189        for_buffer: Option<BufferId>,
23190        window: &mut Window,
23191        cx: &mut Context<'_, Self>,
23192    ) {
23193        self.pull_diagnostics(for_buffer, window, cx);
23194        self.refresh_colors_for_visible_range(for_buffer, window, cx);
23195    }
23196
23197    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
23198        if self.ignore_lsp_data() {
23199            return;
23200        }
23201        for (_, (visible_buffer, _, _)) in self.visible_excerpts(true, cx) {
23202            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
23203        }
23204    }
23205
23206    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
23207        if self.ignore_lsp_data() {
23208            return;
23209        }
23210
23211        if !self.registered_buffers.contains_key(&buffer_id)
23212            && let Some(project) = self.project.as_ref()
23213        {
23214            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
23215                project.update(cx, |project, cx| {
23216                    self.registered_buffers.insert(
23217                        buffer_id,
23218                        project.register_buffer_with_language_servers(&buffer, cx),
23219                    );
23220                });
23221            } else {
23222                self.registered_buffers.remove(&buffer_id);
23223            }
23224        }
23225    }
23226
23227    fn ignore_lsp_data(&self) -> bool {
23228        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
23229        // skip any LSP updates for it.
23230        self.active_diagnostics == ActiveDiagnostic::All || !self.mode().is_full()
23231    }
23232
23233    fn create_style(&self, cx: &App) -> EditorStyle {
23234        let settings = ThemeSettings::get_global(cx);
23235
23236        let mut text_style = match self.mode {
23237            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
23238                color: cx.theme().colors().editor_foreground,
23239                font_family: settings.ui_font.family.clone(),
23240                font_features: settings.ui_font.features.clone(),
23241                font_fallbacks: settings.ui_font.fallbacks.clone(),
23242                font_size: rems(0.875).into(),
23243                font_weight: settings.ui_font.weight,
23244                line_height: relative(settings.buffer_line_height.value()),
23245                ..Default::default()
23246            },
23247            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
23248                color: cx.theme().colors().editor_foreground,
23249                font_family: settings.buffer_font.family.clone(),
23250                font_features: settings.buffer_font.features.clone(),
23251                font_fallbacks: settings.buffer_font.fallbacks.clone(),
23252                font_size: settings.buffer_font_size(cx).into(),
23253                font_weight: settings.buffer_font.weight,
23254                line_height: relative(settings.buffer_line_height.value()),
23255                ..Default::default()
23256            },
23257        };
23258        if let Some(text_style_refinement) = &self.text_style_refinement {
23259            text_style.refine(text_style_refinement)
23260        }
23261
23262        let background = match self.mode {
23263            EditorMode::SingleLine => cx.theme().system().transparent,
23264            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
23265            EditorMode::Full { .. } => cx.theme().colors().editor_background,
23266            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
23267        };
23268
23269        EditorStyle {
23270            background,
23271            border: cx.theme().colors().border,
23272            local_player: cx.theme().players().local(),
23273            text: text_style,
23274            scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
23275            syntax: cx.theme().syntax().clone(),
23276            status: cx.theme().status().clone(),
23277            inlay_hints_style: make_inlay_hints_style(cx),
23278            edit_prediction_styles: make_suggestion_styles(cx),
23279            unnecessary_code_fade: settings.unnecessary_code_fade,
23280            show_underlines: self.diagnostics_enabled(),
23281        }
23282    }
23283
23284    /// Returns the value of the `vim_mode` setting, defaulting `false` if the
23285    /// setting is not set.
23286    pub(crate) fn is_vim_mode_enabled(&self, cx: &App) -> bool {
23287        VimModeSetting::try_get(cx)
23288            .map(|vim_mode| vim_mode.0)
23289            .unwrap_or(false)
23290    }
23291}
23292
23293fn edit_for_markdown_paste<'a>(
23294    buffer: &MultiBufferSnapshot,
23295    range: Range<MultiBufferOffset>,
23296    to_insert: &'a str,
23297    url: Option<url::Url>,
23298) -> (Range<MultiBufferOffset>, Cow<'a, str>) {
23299    if url.is_none() {
23300        return (range, Cow::Borrowed(to_insert));
23301    };
23302
23303    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
23304
23305    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
23306        Cow::Borrowed(to_insert)
23307    } else {
23308        Cow::Owned(format!("[{old_text}]({to_insert})"))
23309    };
23310    (range, new_text)
23311}
23312
23313fn process_completion_for_edit(
23314    completion: &Completion,
23315    intent: CompletionIntent,
23316    buffer: &Entity<Buffer>,
23317    cursor_position: &text::Anchor,
23318    cx: &mut Context<Editor>,
23319) -> CompletionEdit {
23320    let buffer = buffer.read(cx);
23321    let buffer_snapshot = buffer.snapshot();
23322    let (snippet, new_text) = if completion.is_snippet() {
23323        let mut snippet_source = completion.new_text.clone();
23324        // Workaround for typescript language server issues so that methods don't expand within
23325        // strings and functions with type expressions. The previous point is used because the query
23326        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
23327        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
23328        let previous_point = if previous_point.column > 0 {
23329            cursor_position.to_previous_offset(&buffer_snapshot)
23330        } else {
23331            cursor_position.to_offset(&buffer_snapshot)
23332        };
23333        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
23334            && scope.prefers_label_for_snippet_in_completion()
23335            && let Some(label) = completion.label()
23336            && matches!(
23337                completion.kind(),
23338                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
23339            )
23340        {
23341            snippet_source = label;
23342        }
23343        match Snippet::parse(&snippet_source).log_err() {
23344            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
23345            None => (None, completion.new_text.clone()),
23346        }
23347    } else {
23348        (None, completion.new_text.clone())
23349    };
23350
23351    let mut range_to_replace = {
23352        let replace_range = &completion.replace_range;
23353        if let CompletionSource::Lsp {
23354            insert_range: Some(insert_range),
23355            ..
23356        } = &completion.source
23357        {
23358            debug_assert_eq!(
23359                insert_range.start, replace_range.start,
23360                "insert_range and replace_range should start at the same position"
23361            );
23362            debug_assert!(
23363                insert_range
23364                    .start
23365                    .cmp(cursor_position, &buffer_snapshot)
23366                    .is_le(),
23367                "insert_range should start before or at cursor position"
23368            );
23369            debug_assert!(
23370                replace_range
23371                    .start
23372                    .cmp(cursor_position, &buffer_snapshot)
23373                    .is_le(),
23374                "replace_range should start before or at cursor position"
23375            );
23376
23377            let should_replace = match intent {
23378                CompletionIntent::CompleteWithInsert => false,
23379                CompletionIntent::CompleteWithReplace => true,
23380                CompletionIntent::Complete | CompletionIntent::Compose => {
23381                    let insert_mode =
23382                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
23383                            .completions
23384                            .lsp_insert_mode;
23385                    match insert_mode {
23386                        LspInsertMode::Insert => false,
23387                        LspInsertMode::Replace => true,
23388                        LspInsertMode::ReplaceSubsequence => {
23389                            let mut text_to_replace = buffer.chars_for_range(
23390                                buffer.anchor_before(replace_range.start)
23391                                    ..buffer.anchor_after(replace_range.end),
23392                            );
23393                            let mut current_needle = text_to_replace.next();
23394                            for haystack_ch in completion.label.text.chars() {
23395                                if let Some(needle_ch) = current_needle
23396                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
23397                                {
23398                                    current_needle = text_to_replace.next();
23399                                }
23400                            }
23401                            current_needle.is_none()
23402                        }
23403                        LspInsertMode::ReplaceSuffix => {
23404                            if replace_range
23405                                .end
23406                                .cmp(cursor_position, &buffer_snapshot)
23407                                .is_gt()
23408                            {
23409                                let range_after_cursor = *cursor_position..replace_range.end;
23410                                let text_after_cursor = buffer
23411                                    .text_for_range(
23412                                        buffer.anchor_before(range_after_cursor.start)
23413                                            ..buffer.anchor_after(range_after_cursor.end),
23414                                    )
23415                                    .collect::<String>()
23416                                    .to_ascii_lowercase();
23417                                completion
23418                                    .label
23419                                    .text
23420                                    .to_ascii_lowercase()
23421                                    .ends_with(&text_after_cursor)
23422                            } else {
23423                                true
23424                            }
23425                        }
23426                    }
23427                }
23428            };
23429
23430            if should_replace {
23431                replace_range.clone()
23432            } else {
23433                insert_range.clone()
23434            }
23435        } else {
23436            replace_range.clone()
23437        }
23438    };
23439
23440    if range_to_replace
23441        .end
23442        .cmp(cursor_position, &buffer_snapshot)
23443        .is_lt()
23444    {
23445        range_to_replace.end = *cursor_position;
23446    }
23447
23448    let replace_range = range_to_replace.to_offset(buffer);
23449    CompletionEdit {
23450        new_text,
23451        replace_range: BufferOffset(replace_range.start)..BufferOffset(replace_range.end),
23452        snippet,
23453    }
23454}
23455
23456struct CompletionEdit {
23457    new_text: String,
23458    replace_range: Range<BufferOffset>,
23459    snippet: Option<Snippet>,
23460}
23461
23462fn insert_extra_newline_brackets(
23463    buffer: &MultiBufferSnapshot,
23464    range: Range<MultiBufferOffset>,
23465    language: &language::LanguageScope,
23466) -> bool {
23467    let leading_whitespace_len = buffer
23468        .reversed_chars_at(range.start)
23469        .take_while(|c| c.is_whitespace() && *c != '\n')
23470        .map(|c| c.len_utf8())
23471        .sum::<usize>();
23472    let trailing_whitespace_len = buffer
23473        .chars_at(range.end)
23474        .take_while(|c| c.is_whitespace() && *c != '\n')
23475        .map(|c| c.len_utf8())
23476        .sum::<usize>();
23477    let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
23478
23479    language.brackets().any(|(pair, enabled)| {
23480        let pair_start = pair.start.trim_end();
23481        let pair_end = pair.end.trim_start();
23482
23483        enabled
23484            && pair.newline
23485            && buffer.contains_str_at(range.end, pair_end)
23486            && buffer.contains_str_at(
23487                range.start.saturating_sub_usize(pair_start.len()),
23488                pair_start,
23489            )
23490    })
23491}
23492
23493fn insert_extra_newline_tree_sitter(
23494    buffer: &MultiBufferSnapshot,
23495    range: Range<MultiBufferOffset>,
23496) -> bool {
23497    let (buffer, range) = match buffer.range_to_buffer_ranges(range).as_slice() {
23498        [(buffer, range, _)] => (*buffer, range.clone()),
23499        _ => return false,
23500    };
23501    let pair = {
23502        let mut result: Option<BracketMatch<usize>> = None;
23503
23504        for pair in buffer
23505            .all_bracket_ranges(range.start.0..range.end.0)
23506            .filter(move |pair| {
23507                pair.open_range.start <= range.start.0 && pair.close_range.end >= range.end.0
23508            })
23509        {
23510            let len = pair.close_range.end - pair.open_range.start;
23511
23512            if let Some(existing) = &result {
23513                let existing_len = existing.close_range.end - existing.open_range.start;
23514                if len > existing_len {
23515                    continue;
23516                }
23517            }
23518
23519            result = Some(pair);
23520        }
23521
23522        result
23523    };
23524    let Some(pair) = pair else {
23525        return false;
23526    };
23527    pair.newline_only
23528        && buffer
23529            .chars_for_range(pair.open_range.end..range.start.0)
23530            .chain(buffer.chars_for_range(range.end.0..pair.close_range.start))
23531            .all(|c| c.is_whitespace() && c != '\n')
23532}
23533
23534fn update_uncommitted_diff_for_buffer(
23535    editor: Entity<Editor>,
23536    project: &Entity<Project>,
23537    buffers: impl IntoIterator<Item = Entity<Buffer>>,
23538    buffer: Entity<MultiBuffer>,
23539    cx: &mut App,
23540) -> Task<()> {
23541    let mut tasks = Vec::new();
23542    project.update(cx, |project, cx| {
23543        for buffer in buffers {
23544            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
23545                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
23546            }
23547        }
23548    });
23549    cx.spawn(async move |cx| {
23550        let diffs = future::join_all(tasks).await;
23551        if editor
23552            .read_with(cx, |editor, _cx| editor.temporary_diff_override)
23553            .unwrap_or(false)
23554        {
23555            return;
23556        }
23557
23558        buffer
23559            .update(cx, |buffer, cx| {
23560                for diff in diffs.into_iter().flatten() {
23561                    buffer.add_diff(diff, cx);
23562                }
23563            })
23564            .ok();
23565    })
23566}
23567
23568fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
23569    let tab_size = tab_size.get() as usize;
23570    let mut width = offset;
23571
23572    for ch in text.chars() {
23573        width += if ch == '\t' {
23574            tab_size - (width % tab_size)
23575        } else {
23576            1
23577        };
23578    }
23579
23580    width - offset
23581}
23582
23583#[cfg(test)]
23584mod tests {
23585    use super::*;
23586
23587    #[test]
23588    fn test_string_size_with_expanded_tabs() {
23589        let nz = |val| NonZeroU32::new(val).unwrap();
23590        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
23591        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
23592        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
23593        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
23594        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
23595        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
23596        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
23597        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
23598    }
23599}
23600
23601/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
23602struct WordBreakingTokenizer<'a> {
23603    input: &'a str,
23604}
23605
23606impl<'a> WordBreakingTokenizer<'a> {
23607    fn new(input: &'a str) -> Self {
23608        Self { input }
23609    }
23610}
23611
23612fn is_char_ideographic(ch: char) -> bool {
23613    use unicode_script::Script::*;
23614    use unicode_script::UnicodeScript;
23615    matches!(ch.script(), Han | Tangut | Yi)
23616}
23617
23618fn is_grapheme_ideographic(text: &str) -> bool {
23619    text.chars().any(is_char_ideographic)
23620}
23621
23622fn is_grapheme_whitespace(text: &str) -> bool {
23623    text.chars().any(|x| x.is_whitespace())
23624}
23625
23626fn should_stay_with_preceding_ideograph(text: &str) -> bool {
23627    text.chars()
23628        .next()
23629        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
23630}
23631
23632#[derive(PartialEq, Eq, Debug, Clone, Copy)]
23633enum WordBreakToken<'a> {
23634    Word { token: &'a str, grapheme_len: usize },
23635    InlineWhitespace { token: &'a str, grapheme_len: usize },
23636    Newline,
23637}
23638
23639impl<'a> Iterator for WordBreakingTokenizer<'a> {
23640    /// Yields a span, the count of graphemes in the token, and whether it was
23641    /// whitespace. Note that it also breaks at word boundaries.
23642    type Item = WordBreakToken<'a>;
23643
23644    fn next(&mut self) -> Option<Self::Item> {
23645        use unicode_segmentation::UnicodeSegmentation;
23646        if self.input.is_empty() {
23647            return None;
23648        }
23649
23650        let mut iter = self.input.graphemes(true).peekable();
23651        let mut offset = 0;
23652        let mut grapheme_len = 0;
23653        if let Some(first_grapheme) = iter.next() {
23654            let is_newline = first_grapheme == "\n";
23655            let is_whitespace = is_grapheme_whitespace(first_grapheme);
23656            offset += first_grapheme.len();
23657            grapheme_len += 1;
23658            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
23659                if let Some(grapheme) = iter.peek().copied()
23660                    && should_stay_with_preceding_ideograph(grapheme)
23661                {
23662                    offset += grapheme.len();
23663                    grapheme_len += 1;
23664                }
23665            } else {
23666                let mut words = self.input[offset..].split_word_bound_indices().peekable();
23667                let mut next_word_bound = words.peek().copied();
23668                if next_word_bound.is_some_and(|(i, _)| i == 0) {
23669                    next_word_bound = words.next();
23670                }
23671                while let Some(grapheme) = iter.peek().copied() {
23672                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
23673                        break;
23674                    };
23675                    if is_grapheme_whitespace(grapheme) != is_whitespace
23676                        || (grapheme == "\n") != is_newline
23677                    {
23678                        break;
23679                    };
23680                    offset += grapheme.len();
23681                    grapheme_len += 1;
23682                    iter.next();
23683                }
23684            }
23685            let token = &self.input[..offset];
23686            self.input = &self.input[offset..];
23687            if token == "\n" {
23688                Some(WordBreakToken::Newline)
23689            } else if is_whitespace {
23690                Some(WordBreakToken::InlineWhitespace {
23691                    token,
23692                    grapheme_len,
23693                })
23694            } else {
23695                Some(WordBreakToken::Word {
23696                    token,
23697                    grapheme_len,
23698                })
23699            }
23700        } else {
23701            None
23702        }
23703    }
23704}
23705
23706#[test]
23707fn test_word_breaking_tokenizer() {
23708    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
23709        ("", &[]),
23710        ("  ", &[whitespace("  ", 2)]),
23711        ("Ʒ", &[word("Ʒ", 1)]),
23712        ("Ǽ", &[word("Ǽ", 1)]),
23713        ("", &[word("", 1)]),
23714        ("⋑⋑", &[word("⋑⋑", 2)]),
23715        (
23716            "原理,进而",
23717            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
23718        ),
23719        (
23720            "hello world",
23721            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
23722        ),
23723        (
23724            "hello, world",
23725            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
23726        ),
23727        (
23728            "  hello world",
23729            &[
23730                whitespace("  ", 2),
23731                word("hello", 5),
23732                whitespace(" ", 1),
23733                word("world", 5),
23734            ],
23735        ),
23736        (
23737            "这是什么 \n 钢笔",
23738            &[
23739                word("", 1),
23740                word("", 1),
23741                word("", 1),
23742                word("", 1),
23743                whitespace(" ", 1),
23744                newline(),
23745                whitespace(" ", 1),
23746                word("", 1),
23747                word("", 1),
23748            ],
23749        ),
23750        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
23751    ];
23752
23753    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
23754        WordBreakToken::Word {
23755            token,
23756            grapheme_len,
23757        }
23758    }
23759
23760    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
23761        WordBreakToken::InlineWhitespace {
23762            token,
23763            grapheme_len,
23764        }
23765    }
23766
23767    fn newline() -> WordBreakToken<'static> {
23768        WordBreakToken::Newline
23769    }
23770
23771    for (input, result) in tests {
23772        assert_eq!(
23773            WordBreakingTokenizer::new(input)
23774                .collect::<Vec<_>>()
23775                .as_slice(),
23776            *result,
23777        );
23778    }
23779}
23780
23781fn wrap_with_prefix(
23782    first_line_prefix: String,
23783    subsequent_lines_prefix: String,
23784    unwrapped_text: String,
23785    wrap_column: usize,
23786    tab_size: NonZeroU32,
23787    preserve_existing_whitespace: bool,
23788) -> String {
23789    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
23790    let subsequent_lines_prefix_len =
23791        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
23792    let mut wrapped_text = String::new();
23793    let mut current_line = first_line_prefix;
23794    let mut is_first_line = true;
23795
23796    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
23797    let mut current_line_len = first_line_prefix_len;
23798    let mut in_whitespace = false;
23799    for token in tokenizer {
23800        let have_preceding_whitespace = in_whitespace;
23801        match token {
23802            WordBreakToken::Word {
23803                token,
23804                grapheme_len,
23805            } => {
23806                in_whitespace = false;
23807                let current_prefix_len = if is_first_line {
23808                    first_line_prefix_len
23809                } else {
23810                    subsequent_lines_prefix_len
23811                };
23812                if current_line_len + grapheme_len > wrap_column
23813                    && current_line_len != current_prefix_len
23814                {
23815                    wrapped_text.push_str(current_line.trim_end());
23816                    wrapped_text.push('\n');
23817                    is_first_line = false;
23818                    current_line = subsequent_lines_prefix.clone();
23819                    current_line_len = subsequent_lines_prefix_len;
23820                }
23821                current_line.push_str(token);
23822                current_line_len += grapheme_len;
23823            }
23824            WordBreakToken::InlineWhitespace {
23825                mut token,
23826                mut grapheme_len,
23827            } => {
23828                in_whitespace = true;
23829                if have_preceding_whitespace && !preserve_existing_whitespace {
23830                    continue;
23831                }
23832                if !preserve_existing_whitespace {
23833                    // Keep a single whitespace grapheme as-is
23834                    if let Some(first) =
23835                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
23836                    {
23837                        token = first;
23838                    } else {
23839                        token = " ";
23840                    }
23841                    grapheme_len = 1;
23842                }
23843                let current_prefix_len = if is_first_line {
23844                    first_line_prefix_len
23845                } else {
23846                    subsequent_lines_prefix_len
23847                };
23848                if current_line_len + grapheme_len > wrap_column {
23849                    wrapped_text.push_str(current_line.trim_end());
23850                    wrapped_text.push('\n');
23851                    is_first_line = false;
23852                    current_line = subsequent_lines_prefix.clone();
23853                    current_line_len = subsequent_lines_prefix_len;
23854                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
23855                    current_line.push_str(token);
23856                    current_line_len += grapheme_len;
23857                }
23858            }
23859            WordBreakToken::Newline => {
23860                in_whitespace = true;
23861                let current_prefix_len = if is_first_line {
23862                    first_line_prefix_len
23863                } else {
23864                    subsequent_lines_prefix_len
23865                };
23866                if preserve_existing_whitespace {
23867                    wrapped_text.push_str(current_line.trim_end());
23868                    wrapped_text.push('\n');
23869                    is_first_line = false;
23870                    current_line = subsequent_lines_prefix.clone();
23871                    current_line_len = subsequent_lines_prefix_len;
23872                } else if have_preceding_whitespace {
23873                    continue;
23874                } else if current_line_len + 1 > wrap_column
23875                    && current_line_len != current_prefix_len
23876                {
23877                    wrapped_text.push_str(current_line.trim_end());
23878                    wrapped_text.push('\n');
23879                    is_first_line = false;
23880                    current_line = subsequent_lines_prefix.clone();
23881                    current_line_len = subsequent_lines_prefix_len;
23882                } else if current_line_len != current_prefix_len {
23883                    current_line.push(' ');
23884                    current_line_len += 1;
23885                }
23886            }
23887        }
23888    }
23889
23890    if !current_line.is_empty() {
23891        wrapped_text.push_str(&current_line);
23892    }
23893    wrapped_text
23894}
23895
23896#[test]
23897fn test_wrap_with_prefix() {
23898    assert_eq!(
23899        wrap_with_prefix(
23900            "# ".to_string(),
23901            "# ".to_string(),
23902            "abcdefg".to_string(),
23903            4,
23904            NonZeroU32::new(4).unwrap(),
23905            false,
23906        ),
23907        "# abcdefg"
23908    );
23909    assert_eq!(
23910        wrap_with_prefix(
23911            "".to_string(),
23912            "".to_string(),
23913            "\thello world".to_string(),
23914            8,
23915            NonZeroU32::new(4).unwrap(),
23916            false,
23917        ),
23918        "hello\nworld"
23919    );
23920    assert_eq!(
23921        wrap_with_prefix(
23922            "// ".to_string(),
23923            "// ".to_string(),
23924            "xx \nyy zz aa bb cc".to_string(),
23925            12,
23926            NonZeroU32::new(4).unwrap(),
23927            false,
23928        ),
23929        "// xx yy zz\n// aa bb cc"
23930    );
23931    assert_eq!(
23932        wrap_with_prefix(
23933            String::new(),
23934            String::new(),
23935            "这是什么 \n 钢笔".to_string(),
23936            3,
23937            NonZeroU32::new(4).unwrap(),
23938            false,
23939        ),
23940        "这是什\n么 钢\n"
23941    );
23942    assert_eq!(
23943        wrap_with_prefix(
23944            String::new(),
23945            String::new(),
23946            format!("foo{}bar", '\u{2009}'), // thin space
23947            80,
23948            NonZeroU32::new(4).unwrap(),
23949            false,
23950        ),
23951        format!("foo{}bar", '\u{2009}')
23952    );
23953}
23954
23955pub trait CollaborationHub {
23956    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
23957    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
23958    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
23959}
23960
23961impl CollaborationHub for Entity<Project> {
23962    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
23963        self.read(cx).collaborators()
23964    }
23965
23966    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
23967        self.read(cx).user_store().read(cx).participant_indices()
23968    }
23969
23970    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
23971        let this = self.read(cx);
23972        let user_ids = this.collaborators().values().map(|c| c.user_id);
23973        this.user_store().read(cx).participant_names(user_ids, cx)
23974    }
23975}
23976
23977pub trait SemanticsProvider {
23978    fn hover(
23979        &self,
23980        buffer: &Entity<Buffer>,
23981        position: text::Anchor,
23982        cx: &mut App,
23983    ) -> Option<Task<Option<Vec<project::Hover>>>>;
23984
23985    fn inline_values(
23986        &self,
23987        buffer_handle: Entity<Buffer>,
23988        range: Range<text::Anchor>,
23989        cx: &mut App,
23990    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
23991
23992    fn applicable_inlay_chunks(
23993        &self,
23994        buffer: &Entity<Buffer>,
23995        ranges: &[Range<text::Anchor>],
23996        cx: &mut App,
23997    ) -> Vec<Range<BufferRow>>;
23998
23999    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
24000
24001    fn inlay_hints(
24002        &self,
24003        invalidate: InvalidationStrategy,
24004        buffer: Entity<Buffer>,
24005        ranges: Vec<Range<text::Anchor>>,
24006        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
24007        cx: &mut App,
24008    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
24009
24010    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
24011
24012    fn document_highlights(
24013        &self,
24014        buffer: &Entity<Buffer>,
24015        position: text::Anchor,
24016        cx: &mut App,
24017    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
24018
24019    fn definitions(
24020        &self,
24021        buffer: &Entity<Buffer>,
24022        position: text::Anchor,
24023        kind: GotoDefinitionKind,
24024        cx: &mut App,
24025    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
24026
24027    fn range_for_rename(
24028        &self,
24029        buffer: &Entity<Buffer>,
24030        position: text::Anchor,
24031        cx: &mut App,
24032    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
24033
24034    fn perform_rename(
24035        &self,
24036        buffer: &Entity<Buffer>,
24037        position: text::Anchor,
24038        new_name: String,
24039        cx: &mut App,
24040    ) -> Option<Task<Result<ProjectTransaction>>>;
24041}
24042
24043pub trait CompletionProvider {
24044    fn completions(
24045        &self,
24046        excerpt_id: ExcerptId,
24047        buffer: &Entity<Buffer>,
24048        buffer_position: text::Anchor,
24049        trigger: CompletionContext,
24050        window: &mut Window,
24051        cx: &mut Context<Editor>,
24052    ) -> Task<Result<Vec<CompletionResponse>>>;
24053
24054    fn resolve_completions(
24055        &self,
24056        _buffer: Entity<Buffer>,
24057        _completion_indices: Vec<usize>,
24058        _completions: Rc<RefCell<Box<[Completion]>>>,
24059        _cx: &mut Context<Editor>,
24060    ) -> Task<Result<bool>> {
24061        Task::ready(Ok(false))
24062    }
24063
24064    fn apply_additional_edits_for_completion(
24065        &self,
24066        _buffer: Entity<Buffer>,
24067        _completions: Rc<RefCell<Box<[Completion]>>>,
24068        _completion_index: usize,
24069        _push_to_history: bool,
24070        _cx: &mut Context<Editor>,
24071    ) -> Task<Result<Option<language::Transaction>>> {
24072        Task::ready(Ok(None))
24073    }
24074
24075    fn is_completion_trigger(
24076        &self,
24077        buffer: &Entity<Buffer>,
24078        position: language::Anchor,
24079        text: &str,
24080        trigger_in_words: bool,
24081        cx: &mut Context<Editor>,
24082    ) -> bool;
24083
24084    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
24085
24086    fn sort_completions(&self) -> bool {
24087        true
24088    }
24089
24090    fn filter_completions(&self) -> bool {
24091        true
24092    }
24093
24094    fn show_snippets(&self) -> bool {
24095        false
24096    }
24097}
24098
24099pub trait CodeActionProvider {
24100    fn id(&self) -> Arc<str>;
24101
24102    fn code_actions(
24103        &self,
24104        buffer: &Entity<Buffer>,
24105        range: Range<text::Anchor>,
24106        window: &mut Window,
24107        cx: &mut App,
24108    ) -> Task<Result<Vec<CodeAction>>>;
24109
24110    fn apply_code_action(
24111        &self,
24112        buffer_handle: Entity<Buffer>,
24113        action: CodeAction,
24114        excerpt_id: ExcerptId,
24115        push_to_history: bool,
24116        window: &mut Window,
24117        cx: &mut App,
24118    ) -> Task<Result<ProjectTransaction>>;
24119}
24120
24121impl CodeActionProvider for Entity<Project> {
24122    fn id(&self) -> Arc<str> {
24123        "project".into()
24124    }
24125
24126    fn code_actions(
24127        &self,
24128        buffer: &Entity<Buffer>,
24129        range: Range<text::Anchor>,
24130        _window: &mut Window,
24131        cx: &mut App,
24132    ) -> Task<Result<Vec<CodeAction>>> {
24133        self.update(cx, |project, cx| {
24134            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
24135            let code_actions = project.code_actions(buffer, range, None, cx);
24136            cx.background_spawn(async move {
24137                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
24138                Ok(code_lens_actions
24139                    .context("code lens fetch")?
24140                    .into_iter()
24141                    .flatten()
24142                    .chain(
24143                        code_actions
24144                            .context("code action fetch")?
24145                            .into_iter()
24146                            .flatten(),
24147                    )
24148                    .collect())
24149            })
24150        })
24151    }
24152
24153    fn apply_code_action(
24154        &self,
24155        buffer_handle: Entity<Buffer>,
24156        action: CodeAction,
24157        _excerpt_id: ExcerptId,
24158        push_to_history: bool,
24159        _window: &mut Window,
24160        cx: &mut App,
24161    ) -> Task<Result<ProjectTransaction>> {
24162        self.update(cx, |project, cx| {
24163            project.apply_code_action(buffer_handle, action, push_to_history, cx)
24164        })
24165    }
24166}
24167
24168fn snippet_completions(
24169    project: &Project,
24170    buffer: &Entity<Buffer>,
24171    buffer_anchor: text::Anchor,
24172    classifier: CharClassifier,
24173    cx: &mut App,
24174) -> Task<Result<CompletionResponse>> {
24175    let languages = buffer.read(cx).languages_at(buffer_anchor);
24176    let snippet_store = project.snippets().read(cx);
24177
24178    let scopes: Vec<_> = languages
24179        .iter()
24180        .filter_map(|language| {
24181            let language_name = language.lsp_id();
24182            let snippets = snippet_store.snippets_for(Some(language_name), cx);
24183
24184            if snippets.is_empty() {
24185                None
24186            } else {
24187                Some((language.default_scope(), snippets))
24188            }
24189        })
24190        .collect();
24191
24192    if scopes.is_empty() {
24193        return Task::ready(Ok(CompletionResponse {
24194            completions: vec![],
24195            display_options: CompletionDisplayOptions::default(),
24196            is_incomplete: false,
24197        }));
24198    }
24199
24200    let snapshot = buffer.read(cx).text_snapshot();
24201    let executor = cx.background_executor().clone();
24202
24203    cx.background_spawn(async move {
24204        let is_word_char = |c| classifier.is_word(c);
24205
24206        let mut is_incomplete = false;
24207        let mut completions: Vec<Completion> = Vec::new();
24208
24209        const MAX_PREFIX_LEN: usize = 128;
24210        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
24211        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
24212        let window_start = snapshot.clip_offset(window_start, Bias::Left);
24213
24214        let max_buffer_window: String = snapshot
24215            .text_for_range(window_start..buffer_offset)
24216            .collect();
24217
24218        if max_buffer_window.is_empty() {
24219            return Ok(CompletionResponse {
24220                completions: vec![],
24221                display_options: CompletionDisplayOptions::default(),
24222                is_incomplete: true,
24223            });
24224        }
24225
24226        for (_scope, snippets) in scopes.into_iter() {
24227            // Sort snippets by word count to match longer snippet prefixes first.
24228            let mut sorted_snippet_candidates = snippets
24229                .iter()
24230                .enumerate()
24231                .flat_map(|(snippet_ix, snippet)| {
24232                    snippet
24233                        .prefix
24234                        .iter()
24235                        .enumerate()
24236                        .map(move |(prefix_ix, prefix)| {
24237                            let word_count =
24238                                snippet_candidate_suffixes(prefix, is_word_char).count();
24239                            ((snippet_ix, prefix_ix), prefix, word_count)
24240                        })
24241                })
24242                .collect_vec();
24243            sorted_snippet_candidates
24244                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
24245
24246            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
24247
24248            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, is_word_char)
24249                .take(
24250                    sorted_snippet_candidates
24251                        .first()
24252                        .map(|(_, _, word_count)| *word_count)
24253                        .unwrap_or_default(),
24254                )
24255                .collect_vec();
24256
24257            const MAX_RESULTS: usize = 100;
24258            // Each match also remembers how many characters from the buffer it consumed
24259            let mut matches: Vec<(StringMatch, usize)> = vec![];
24260
24261            let mut snippet_list_cutoff_index = 0;
24262            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
24263                let word_count = buffer_index + 1;
24264                // Increase `snippet_list_cutoff_index` until we have all of the
24265                // snippets with sufficiently many words.
24266                while sorted_snippet_candidates
24267                    .get(snippet_list_cutoff_index)
24268                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
24269                        *snippet_word_count >= word_count
24270                    })
24271                {
24272                    snippet_list_cutoff_index += 1;
24273                }
24274
24275                // Take only the candidates with at least `word_count` many words
24276                let snippet_candidates_at_word_len =
24277                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
24278
24279                let candidates = snippet_candidates_at_word_len
24280                    .iter()
24281                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
24282                    .enumerate() // index in `sorted_snippet_candidates`
24283                    // First char must match
24284                    .filter(|(_ix, prefix)| {
24285                        itertools::equal(
24286                            prefix
24287                                .chars()
24288                                .next()
24289                                .into_iter()
24290                                .flat_map(|c| c.to_lowercase()),
24291                            buffer_window
24292                                .chars()
24293                                .next()
24294                                .into_iter()
24295                                .flat_map(|c| c.to_lowercase()),
24296                        )
24297                    })
24298                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
24299                    .collect::<Vec<StringMatchCandidate>>();
24300
24301                matches.extend(
24302                    fuzzy::match_strings(
24303                        &candidates,
24304                        &buffer_window,
24305                        buffer_window.chars().any(|c| c.is_uppercase()),
24306                        true,
24307                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
24308                        &Default::default(),
24309                        executor.clone(),
24310                    )
24311                    .await
24312                    .into_iter()
24313                    .map(|string_match| (string_match, buffer_window.len())),
24314                );
24315
24316                if matches.len() >= MAX_RESULTS {
24317                    break;
24318                }
24319            }
24320
24321            let to_lsp = |point: &text::Anchor| {
24322                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
24323                point_to_lsp(end)
24324            };
24325            let lsp_end = to_lsp(&buffer_anchor);
24326
24327            if matches.len() >= MAX_RESULTS {
24328                is_incomplete = true;
24329            }
24330
24331            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
24332                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
24333                    sorted_snippet_candidates[string_match.candidate_id];
24334                let snippet = &snippets[snippet_index];
24335                let start = buffer_offset - buffer_window_len;
24336                let start = snapshot.anchor_before(start);
24337                let range = start..buffer_anchor;
24338                let lsp_start = to_lsp(&start);
24339                let lsp_range = lsp::Range {
24340                    start: lsp_start,
24341                    end: lsp_end,
24342                };
24343                Completion {
24344                    replace_range: range,
24345                    new_text: snippet.body.clone(),
24346                    source: CompletionSource::Lsp {
24347                        insert_range: None,
24348                        server_id: LanguageServerId(usize::MAX),
24349                        resolved: true,
24350                        lsp_completion: Box::new(lsp::CompletionItem {
24351                            label: snippet.prefix.first().unwrap().clone(),
24352                            kind: Some(CompletionItemKind::SNIPPET),
24353                            label_details: snippet.description.as_ref().map(|description| {
24354                                lsp::CompletionItemLabelDetails {
24355                                    detail: Some(description.clone()),
24356                                    description: None,
24357                                }
24358                            }),
24359                            insert_text_format: Some(InsertTextFormat::SNIPPET),
24360                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
24361                                lsp::InsertReplaceEdit {
24362                                    new_text: snippet.body.clone(),
24363                                    insert: lsp_range,
24364                                    replace: lsp_range,
24365                                },
24366                            )),
24367                            filter_text: Some(snippet.body.clone()),
24368                            sort_text: Some(char::MAX.to_string()),
24369                            ..lsp::CompletionItem::default()
24370                        }),
24371                        lsp_defaults: None,
24372                    },
24373                    label: CodeLabel {
24374                        text: matching_prefix.clone(),
24375                        runs: Vec::new(),
24376                        filter_range: 0..matching_prefix.len(),
24377                    },
24378                    icon_path: None,
24379                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
24380                        single_line: snippet.name.clone().into(),
24381                        plain_text: snippet
24382                            .description
24383                            .clone()
24384                            .map(|description| description.into()),
24385                    }),
24386                    insert_text_mode: None,
24387                    confirm: None,
24388                    match_start: Some(start),
24389                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
24390                }
24391            }));
24392        }
24393
24394        Ok(CompletionResponse {
24395            completions,
24396            display_options: CompletionDisplayOptions::default(),
24397            is_incomplete,
24398        })
24399    })
24400}
24401
24402impl CompletionProvider for Entity<Project> {
24403    fn completions(
24404        &self,
24405        _excerpt_id: ExcerptId,
24406        buffer: &Entity<Buffer>,
24407        buffer_position: text::Anchor,
24408        options: CompletionContext,
24409        _window: &mut Window,
24410        cx: &mut Context<Editor>,
24411    ) -> Task<Result<Vec<CompletionResponse>>> {
24412        self.update(cx, |project, cx| {
24413            let task = project.completions(buffer, buffer_position, options, cx);
24414            cx.background_spawn(task)
24415        })
24416    }
24417
24418    fn resolve_completions(
24419        &self,
24420        buffer: Entity<Buffer>,
24421        completion_indices: Vec<usize>,
24422        completions: Rc<RefCell<Box<[Completion]>>>,
24423        cx: &mut Context<Editor>,
24424    ) -> Task<Result<bool>> {
24425        self.update(cx, |project, cx| {
24426            project.lsp_store().update(cx, |lsp_store, cx| {
24427                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
24428            })
24429        })
24430    }
24431
24432    fn apply_additional_edits_for_completion(
24433        &self,
24434        buffer: Entity<Buffer>,
24435        completions: Rc<RefCell<Box<[Completion]>>>,
24436        completion_index: usize,
24437        push_to_history: bool,
24438        cx: &mut Context<Editor>,
24439    ) -> Task<Result<Option<language::Transaction>>> {
24440        self.update(cx, |project, cx| {
24441            project.lsp_store().update(cx, |lsp_store, cx| {
24442                lsp_store.apply_additional_edits_for_completion(
24443                    buffer,
24444                    completions,
24445                    completion_index,
24446                    push_to_history,
24447                    cx,
24448                )
24449            })
24450        })
24451    }
24452
24453    fn is_completion_trigger(
24454        &self,
24455        buffer: &Entity<Buffer>,
24456        position: language::Anchor,
24457        text: &str,
24458        trigger_in_words: bool,
24459        cx: &mut Context<Editor>,
24460    ) -> bool {
24461        let mut chars = text.chars();
24462        let char = if let Some(char) = chars.next() {
24463            char
24464        } else {
24465            return false;
24466        };
24467        if chars.next().is_some() {
24468            return false;
24469        }
24470
24471        let buffer = buffer.read(cx);
24472        let snapshot = buffer.snapshot();
24473        let classifier = snapshot
24474            .char_classifier_at(position)
24475            .scope_context(Some(CharScopeContext::Completion));
24476        if trigger_in_words && classifier.is_word(char) {
24477            return true;
24478        }
24479
24480        buffer.completion_triggers().contains(text)
24481    }
24482
24483    fn show_snippets(&self) -> bool {
24484        true
24485    }
24486}
24487
24488impl SemanticsProvider for Entity<Project> {
24489    fn hover(
24490        &self,
24491        buffer: &Entity<Buffer>,
24492        position: text::Anchor,
24493        cx: &mut App,
24494    ) -> Option<Task<Option<Vec<project::Hover>>>> {
24495        Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
24496    }
24497
24498    fn document_highlights(
24499        &self,
24500        buffer: &Entity<Buffer>,
24501        position: text::Anchor,
24502        cx: &mut App,
24503    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
24504        Some(self.update(cx, |project, cx| {
24505            project.document_highlights(buffer, position, cx)
24506        }))
24507    }
24508
24509    fn definitions(
24510        &self,
24511        buffer: &Entity<Buffer>,
24512        position: text::Anchor,
24513        kind: GotoDefinitionKind,
24514        cx: &mut App,
24515    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
24516        Some(self.update(cx, |project, cx| match kind {
24517            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
24518            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
24519            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
24520            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
24521        }))
24522    }
24523
24524    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
24525        self.update(cx, |project, cx| {
24526            if project
24527                .active_debug_session(cx)
24528                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
24529            {
24530                return true;
24531            }
24532
24533            buffer.update(cx, |buffer, cx| {
24534                project.any_language_server_supports_inlay_hints(buffer, cx)
24535            })
24536        })
24537    }
24538
24539    fn inline_values(
24540        &self,
24541        buffer_handle: Entity<Buffer>,
24542        range: Range<text::Anchor>,
24543        cx: &mut App,
24544    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
24545        self.update(cx, |project, cx| {
24546            let (session, active_stack_frame) = project.active_debug_session(cx)?;
24547
24548            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
24549        })
24550    }
24551
24552    fn applicable_inlay_chunks(
24553        &self,
24554        buffer: &Entity<Buffer>,
24555        ranges: &[Range<text::Anchor>],
24556        cx: &mut App,
24557    ) -> Vec<Range<BufferRow>> {
24558        self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
24559            lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
24560        })
24561    }
24562
24563    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
24564        self.read(cx).lsp_store().update(cx, |lsp_store, _| {
24565            lsp_store.invalidate_inlay_hints(for_buffers)
24566        });
24567    }
24568
24569    fn inlay_hints(
24570        &self,
24571        invalidate: InvalidationStrategy,
24572        buffer: Entity<Buffer>,
24573        ranges: Vec<Range<text::Anchor>>,
24574        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
24575        cx: &mut App,
24576    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
24577        Some(self.read(cx).lsp_store().update(cx, |lsp_store, cx| {
24578            lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
24579        }))
24580    }
24581
24582    fn range_for_rename(
24583        &self,
24584        buffer: &Entity<Buffer>,
24585        position: text::Anchor,
24586        cx: &mut App,
24587    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
24588        Some(self.update(cx, |project, cx| {
24589            let buffer = buffer.clone();
24590            let task = project.prepare_rename(buffer.clone(), position, cx);
24591            cx.spawn(async move |_, cx| {
24592                Ok(match task.await? {
24593                    PrepareRenameResponse::Success(range) => Some(range),
24594                    PrepareRenameResponse::InvalidPosition => None,
24595                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
24596                        // Fallback on using TreeSitter info to determine identifier range
24597                        buffer.read_with(cx, |buffer, _| {
24598                            let snapshot = buffer.snapshot();
24599                            let (range, kind) = snapshot.surrounding_word(position, None);
24600                            if kind != Some(CharKind::Word) {
24601                                return None;
24602                            }
24603                            Some(
24604                                snapshot.anchor_before(range.start)
24605                                    ..snapshot.anchor_after(range.end),
24606                            )
24607                        })?
24608                    }
24609                })
24610            })
24611        }))
24612    }
24613
24614    fn perform_rename(
24615        &self,
24616        buffer: &Entity<Buffer>,
24617        position: text::Anchor,
24618        new_name: String,
24619        cx: &mut App,
24620    ) -> Option<Task<Result<ProjectTransaction>>> {
24621        Some(self.update(cx, |project, cx| {
24622            project.perform_rename(buffer.clone(), position, new_name, cx)
24623        }))
24624    }
24625}
24626
24627fn consume_contiguous_rows(
24628    contiguous_row_selections: &mut Vec<Selection<Point>>,
24629    selection: &Selection<Point>,
24630    display_map: &DisplaySnapshot,
24631    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
24632) -> (MultiBufferRow, MultiBufferRow) {
24633    contiguous_row_selections.push(selection.clone());
24634    let start_row = starting_row(selection, display_map);
24635    let mut end_row = ending_row(selection, display_map);
24636
24637    while let Some(next_selection) = selections.peek() {
24638        if next_selection.start.row <= end_row.0 {
24639            end_row = ending_row(next_selection, display_map);
24640            contiguous_row_selections.push(selections.next().unwrap().clone());
24641        } else {
24642            break;
24643        }
24644    }
24645    (start_row, end_row)
24646}
24647
24648fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
24649    if selection.start.column > 0 {
24650        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
24651    } else {
24652        MultiBufferRow(selection.start.row)
24653    }
24654}
24655
24656fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
24657    if next_selection.end.column > 0 || next_selection.is_empty() {
24658        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
24659    } else {
24660        MultiBufferRow(next_selection.end.row)
24661    }
24662}
24663
24664impl EditorSnapshot {
24665    pub fn remote_selections_in_range<'a>(
24666        &'a self,
24667        range: &'a Range<Anchor>,
24668        collaboration_hub: &dyn CollaborationHub,
24669        cx: &'a App,
24670    ) -> impl 'a + Iterator<Item = RemoteSelection> {
24671        let participant_names = collaboration_hub.user_names(cx);
24672        let participant_indices = collaboration_hub.user_participant_indices(cx);
24673        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
24674        let collaborators_by_replica_id = collaborators_by_peer_id
24675            .values()
24676            .map(|collaborator| (collaborator.replica_id, collaborator))
24677            .collect::<HashMap<_, _>>();
24678        self.buffer_snapshot()
24679            .selections_in_range(range, false)
24680            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
24681                if replica_id == ReplicaId::AGENT {
24682                    Some(RemoteSelection {
24683                        replica_id,
24684                        selection,
24685                        cursor_shape,
24686                        line_mode,
24687                        collaborator_id: CollaboratorId::Agent,
24688                        user_name: Some("Agent".into()),
24689                        color: cx.theme().players().agent(),
24690                    })
24691                } else {
24692                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
24693                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
24694                    let user_name = participant_names.get(&collaborator.user_id).cloned();
24695                    Some(RemoteSelection {
24696                        replica_id,
24697                        selection,
24698                        cursor_shape,
24699                        line_mode,
24700                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
24701                        user_name,
24702                        color: if let Some(index) = participant_index {
24703                            cx.theme().players().color_for_participant(index.0)
24704                        } else {
24705                            cx.theme().players().absent()
24706                        },
24707                    })
24708                }
24709            })
24710    }
24711
24712    pub fn hunks_for_ranges(
24713        &self,
24714        ranges: impl IntoIterator<Item = Range<Point>>,
24715    ) -> Vec<MultiBufferDiffHunk> {
24716        let mut hunks = Vec::new();
24717        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
24718            HashMap::default();
24719        for query_range in ranges {
24720            let query_rows =
24721                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
24722            for hunk in self.buffer_snapshot().diff_hunks_in_range(
24723                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
24724            ) {
24725                // Include deleted hunks that are adjacent to the query range, because
24726                // otherwise they would be missed.
24727                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
24728                if hunk.status().is_deleted() {
24729                    intersects_range |= hunk.row_range.start == query_rows.end;
24730                    intersects_range |= hunk.row_range.end == query_rows.start;
24731                }
24732                if intersects_range {
24733                    if !processed_buffer_rows
24734                        .entry(hunk.buffer_id)
24735                        .or_default()
24736                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
24737                    {
24738                        continue;
24739                    }
24740                    hunks.push(hunk);
24741                }
24742            }
24743        }
24744
24745        hunks
24746    }
24747
24748    fn display_diff_hunks_for_rows<'a>(
24749        &'a self,
24750        display_rows: Range<DisplayRow>,
24751        folded_buffers: &'a HashSet<BufferId>,
24752    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
24753        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
24754        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
24755
24756        self.buffer_snapshot()
24757            .diff_hunks_in_range(buffer_start..buffer_end)
24758            .filter_map(|hunk| {
24759                if folded_buffers.contains(&hunk.buffer_id) {
24760                    return None;
24761                }
24762
24763                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
24764                let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
24765
24766                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
24767                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
24768
24769                let display_hunk = if hunk_display_start.column() != 0 {
24770                    DisplayDiffHunk::Folded {
24771                        display_row: hunk_display_start.row(),
24772                    }
24773                } else {
24774                    let mut end_row = hunk_display_end.row();
24775                    if hunk_display_end.column() > 0 {
24776                        end_row.0 += 1;
24777                    }
24778                    let is_created_file = hunk.is_created_file();
24779
24780                    DisplayDiffHunk::Unfolded {
24781                        status: hunk.status(),
24782                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
24783                            ..hunk.diff_base_byte_range.end.0,
24784                        word_diffs: hunk.word_diffs,
24785                        display_row_range: hunk_display_start.row()..end_row,
24786                        multi_buffer_range: Anchor::range_in_buffer(
24787                            hunk.excerpt_id,
24788                            hunk.buffer_range,
24789                        ),
24790                        is_created_file,
24791                    }
24792                };
24793
24794                Some(display_hunk)
24795            })
24796    }
24797
24798    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
24799        self.display_snapshot
24800            .buffer_snapshot()
24801            .language_at(position)
24802    }
24803
24804    pub fn is_focused(&self) -> bool {
24805        self.is_focused
24806    }
24807
24808    pub fn placeholder_text(&self) -> Option<String> {
24809        self.placeholder_display_snapshot
24810            .as_ref()
24811            .map(|display_map| display_map.text())
24812    }
24813
24814    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
24815        self.scroll_anchor.scroll_position(&self.display_snapshot)
24816    }
24817
24818    pub fn gutter_dimensions(
24819        &self,
24820        font_id: FontId,
24821        font_size: Pixels,
24822        style: &EditorStyle,
24823        window: &mut Window,
24824        cx: &App,
24825    ) -> GutterDimensions {
24826        if self.show_gutter
24827            && let Some(ch_width) = cx.text_system().ch_width(font_id, font_size).log_err()
24828            && let Some(ch_advance) = cx.text_system().ch_advance(font_id, font_size).log_err()
24829        {
24830            let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
24831                matches!(
24832                    ProjectSettings::get_global(cx).git.git_gutter,
24833                    GitGutterSetting::TrackedFiles
24834                )
24835            });
24836            let gutter_settings = EditorSettings::get_global(cx).gutter;
24837            let show_line_numbers = self
24838                .show_line_numbers
24839                .unwrap_or(gutter_settings.line_numbers);
24840            let line_gutter_width = if show_line_numbers {
24841                // Avoid flicker-like gutter resizes when the line number gains another digit by
24842                // only resizing the gutter on files with > 10**min_line_number_digits lines.
24843                let min_width_for_number_on_gutter =
24844                    ch_advance * gutter_settings.min_line_number_digits as f32;
24845                self.max_line_number_width(style, window)
24846                    .max(min_width_for_number_on_gutter)
24847            } else {
24848                0.0.into()
24849            };
24850
24851            let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
24852            let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
24853
24854            let git_blame_entries_width =
24855                self.git_blame_gutter_max_author_length
24856                    .map(|max_author_length| {
24857                        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
24858                        const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
24859
24860                        /// The number of characters to dedicate to gaps and margins.
24861                        const SPACING_WIDTH: usize = 4;
24862
24863                        let max_char_count = max_author_length.min(renderer.max_author_length())
24864                            + ::git::SHORT_SHA_LENGTH
24865                            + MAX_RELATIVE_TIMESTAMP.len()
24866                            + SPACING_WIDTH;
24867
24868                        ch_advance * max_char_count
24869                    });
24870
24871            let is_singleton = self.buffer_snapshot().is_singleton();
24872
24873            let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
24874            left_padding += if !is_singleton {
24875                ch_width * 4.0
24876            } else if show_runnables || show_breakpoints {
24877                ch_width * 3.0
24878            } else if show_git_gutter && show_line_numbers {
24879                ch_width * 2.0
24880            } else if show_git_gutter || show_line_numbers {
24881                ch_width
24882            } else {
24883                px(0.)
24884            };
24885
24886            let shows_folds = is_singleton && gutter_settings.folds;
24887
24888            let right_padding = if shows_folds && show_line_numbers {
24889                ch_width * 4.0
24890            } else if shows_folds || (!is_singleton && show_line_numbers) {
24891                ch_width * 3.0
24892            } else if show_line_numbers {
24893                ch_width
24894            } else {
24895                px(0.)
24896            };
24897
24898            GutterDimensions {
24899                left_padding,
24900                right_padding,
24901                width: line_gutter_width + left_padding + right_padding,
24902                margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
24903                git_blame_entries_width,
24904            }
24905        } else if self.offset_content {
24906            GutterDimensions::default_with_margin(font_id, font_size, cx)
24907        } else {
24908            GutterDimensions::default()
24909        }
24910    }
24911
24912    pub fn render_crease_toggle(
24913        &self,
24914        buffer_row: MultiBufferRow,
24915        row_contains_cursor: bool,
24916        editor: Entity<Editor>,
24917        window: &mut Window,
24918        cx: &mut App,
24919    ) -> Option<AnyElement> {
24920        let folded = self.is_line_folded(buffer_row);
24921        let mut is_foldable = false;
24922
24923        if let Some(crease) = self
24924            .crease_snapshot
24925            .query_row(buffer_row, self.buffer_snapshot())
24926        {
24927            is_foldable = true;
24928            match crease {
24929                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
24930                    if let Some(render_toggle) = render_toggle {
24931                        let toggle_callback =
24932                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
24933                                if folded {
24934                                    editor.update(cx, |editor, cx| {
24935                                        editor.fold_at(buffer_row, window, cx)
24936                                    });
24937                                } else {
24938                                    editor.update(cx, |editor, cx| {
24939                                        editor.unfold_at(buffer_row, window, cx)
24940                                    });
24941                                }
24942                            });
24943                        return Some((render_toggle)(
24944                            buffer_row,
24945                            folded,
24946                            toggle_callback,
24947                            window,
24948                            cx,
24949                        ));
24950                    }
24951                }
24952            }
24953        }
24954
24955        is_foldable |= self.starts_indent(buffer_row);
24956
24957        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
24958            Some(
24959                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
24960                    .toggle_state(folded)
24961                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
24962                        if folded {
24963                            this.unfold_at(buffer_row, window, cx);
24964                        } else {
24965                            this.fold_at(buffer_row, window, cx);
24966                        }
24967                    }))
24968                    .into_any_element(),
24969            )
24970        } else {
24971            None
24972        }
24973    }
24974
24975    pub fn render_crease_trailer(
24976        &self,
24977        buffer_row: MultiBufferRow,
24978        window: &mut Window,
24979        cx: &mut App,
24980    ) -> Option<AnyElement> {
24981        let folded = self.is_line_folded(buffer_row);
24982        if let Crease::Inline { render_trailer, .. } = self
24983            .crease_snapshot
24984            .query_row(buffer_row, self.buffer_snapshot())?
24985        {
24986            let render_trailer = render_trailer.as_ref()?;
24987            Some(render_trailer(buffer_row, folded, window, cx))
24988        } else {
24989            None
24990        }
24991    }
24992
24993    pub fn max_line_number_width(&self, style: &EditorStyle, window: &mut Window) -> Pixels {
24994        let digit_count = self.widest_line_number().ilog10() + 1;
24995        column_pixels(style, digit_count as usize, window)
24996    }
24997}
24998
24999pub fn column_pixels(style: &EditorStyle, column: usize, window: &Window) -> Pixels {
25000    let font_size = style.text.font_size.to_pixels(window.rem_size());
25001    let layout = window.text_system().shape_line(
25002        SharedString::from(" ".repeat(column)),
25003        font_size,
25004        &[TextRun {
25005            len: column,
25006            font: style.text.font(),
25007            color: Hsla::default(),
25008            ..Default::default()
25009        }],
25010        None,
25011    );
25012
25013    layout.width
25014}
25015
25016impl Deref for EditorSnapshot {
25017    type Target = DisplaySnapshot;
25018
25019    fn deref(&self) -> &Self::Target {
25020        &self.display_snapshot
25021    }
25022}
25023
25024#[derive(Clone, Debug, PartialEq, Eq)]
25025pub enum EditorEvent {
25026    InputIgnored {
25027        text: Arc<str>,
25028    },
25029    InputHandled {
25030        utf16_range_to_replace: Option<Range<isize>>,
25031        text: Arc<str>,
25032    },
25033    ExcerptsAdded {
25034        buffer: Entity<Buffer>,
25035        predecessor: ExcerptId,
25036        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
25037    },
25038    ExcerptsRemoved {
25039        ids: Vec<ExcerptId>,
25040        removed_buffer_ids: Vec<BufferId>,
25041    },
25042    BufferFoldToggled {
25043        ids: Vec<ExcerptId>,
25044        folded: bool,
25045    },
25046    ExcerptsEdited {
25047        ids: Vec<ExcerptId>,
25048    },
25049    ExcerptsExpanded {
25050        ids: Vec<ExcerptId>,
25051    },
25052    BufferEdited,
25053    Edited {
25054        transaction_id: clock::Lamport,
25055    },
25056    Reparsed(BufferId),
25057    Focused,
25058    FocusedIn,
25059    Blurred,
25060    DirtyChanged,
25061    Saved,
25062    TitleChanged,
25063    SelectionsChanged {
25064        local: bool,
25065    },
25066    ScrollPositionChanged {
25067        local: bool,
25068        autoscroll: bool,
25069    },
25070    TransactionUndone {
25071        transaction_id: clock::Lamport,
25072    },
25073    TransactionBegun {
25074        transaction_id: clock::Lamport,
25075    },
25076    CursorShapeChanged,
25077    BreadcrumbsChanged,
25078    PushedToNavHistory {
25079        anchor: Anchor,
25080        is_deactivate: bool,
25081    },
25082}
25083
25084impl EventEmitter<EditorEvent> for Editor {}
25085
25086impl Focusable for Editor {
25087    fn focus_handle(&self, _cx: &App) -> FocusHandle {
25088        self.focus_handle.clone()
25089    }
25090}
25091
25092impl Render for Editor {
25093    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25094        EditorElement::new(&cx.entity(), self.create_style(cx))
25095    }
25096}
25097
25098impl EntityInputHandler for Editor {
25099    fn text_for_range(
25100        &mut self,
25101        range_utf16: Range<usize>,
25102        adjusted_range: &mut Option<Range<usize>>,
25103        _: &mut Window,
25104        cx: &mut Context<Self>,
25105    ) -> Option<String> {
25106        let snapshot = self.buffer.read(cx).read(cx);
25107        let start = snapshot.clip_offset_utf16(
25108            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)),
25109            Bias::Left,
25110        );
25111        let end = snapshot.clip_offset_utf16(
25112            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end)),
25113            Bias::Right,
25114        );
25115        if (start.0.0..end.0.0) != range_utf16 {
25116            adjusted_range.replace(start.0.0..end.0.0);
25117        }
25118        Some(snapshot.text_for_range(start..end).collect())
25119    }
25120
25121    fn selected_text_range(
25122        &mut self,
25123        ignore_disabled_input: bool,
25124        _: &mut Window,
25125        cx: &mut Context<Self>,
25126    ) -> Option<UTF16Selection> {
25127        // Prevent the IME menu from appearing when holding down an alphabetic key
25128        // while input is disabled.
25129        if !ignore_disabled_input && !self.input_enabled {
25130            return None;
25131        }
25132
25133        let selection = self
25134            .selections
25135            .newest::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
25136        let range = selection.range();
25137
25138        Some(UTF16Selection {
25139            range: range.start.0.0..range.end.0.0,
25140            reversed: selection.reversed,
25141        })
25142    }
25143
25144    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
25145        let snapshot = self.buffer.read(cx).read(cx);
25146        let range = self.text_highlights::<InputComposition>(cx)?.1.first()?;
25147        Some(range.start.to_offset_utf16(&snapshot).0.0..range.end.to_offset_utf16(&snapshot).0.0)
25148    }
25149
25150    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
25151        self.clear_highlights::<InputComposition>(cx);
25152        self.ime_transaction.take();
25153    }
25154
25155    fn replace_text_in_range(
25156        &mut self,
25157        range_utf16: Option<Range<usize>>,
25158        text: &str,
25159        window: &mut Window,
25160        cx: &mut Context<Self>,
25161    ) {
25162        if !self.input_enabled {
25163            cx.emit(EditorEvent::InputIgnored { text: text.into() });
25164            return;
25165        }
25166
25167        self.transact(window, cx, |this, window, cx| {
25168            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
25169                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
25170                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
25171                Some(this.selection_replacement_ranges(range_utf16, cx))
25172            } else {
25173                this.marked_text_ranges(cx)
25174            };
25175
25176            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
25177                let newest_selection_id = this.selections.newest_anchor().id;
25178                this.selections
25179                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
25180                    .iter()
25181                    .zip(ranges_to_replace.iter())
25182                    .find_map(|(selection, range)| {
25183                        if selection.id == newest_selection_id {
25184                            Some(
25185                                (range.start.0.0 as isize - selection.head().0.0 as isize)
25186                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
25187                            )
25188                        } else {
25189                            None
25190                        }
25191                    })
25192            });
25193
25194            cx.emit(EditorEvent::InputHandled {
25195                utf16_range_to_replace: range_to_replace,
25196                text: text.into(),
25197            });
25198
25199            if let Some(new_selected_ranges) = new_selected_ranges {
25200                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
25201                    selections.select_ranges(new_selected_ranges)
25202                });
25203                this.backspace(&Default::default(), window, cx);
25204            }
25205
25206            this.handle_input(text, window, cx);
25207        });
25208
25209        if let Some(transaction) = self.ime_transaction {
25210            self.buffer.update(cx, |buffer, cx| {
25211                buffer.group_until_transaction(transaction, cx);
25212            });
25213        }
25214
25215        self.unmark_text(window, cx);
25216    }
25217
25218    fn replace_and_mark_text_in_range(
25219        &mut self,
25220        range_utf16: Option<Range<usize>>,
25221        text: &str,
25222        new_selected_range_utf16: Option<Range<usize>>,
25223        window: &mut Window,
25224        cx: &mut Context<Self>,
25225    ) {
25226        if !self.input_enabled {
25227            return;
25228        }
25229
25230        let transaction = self.transact(window, cx, |this, window, cx| {
25231            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
25232                let snapshot = this.buffer.read(cx).read(cx);
25233                if let Some(relative_range_utf16) = range_utf16.as_ref() {
25234                    for marked_range in &mut marked_ranges {
25235                        marked_range.end = marked_range.start + relative_range_utf16.end;
25236                        marked_range.start += relative_range_utf16.start;
25237                        marked_range.start =
25238                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
25239                        marked_range.end =
25240                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
25241                    }
25242                }
25243                Some(marked_ranges)
25244            } else if let Some(range_utf16) = range_utf16 {
25245                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
25246                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
25247                Some(this.selection_replacement_ranges(range_utf16, cx))
25248            } else {
25249                None
25250            };
25251
25252            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
25253                let newest_selection_id = this.selections.newest_anchor().id;
25254                this.selections
25255                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
25256                    .iter()
25257                    .zip(ranges_to_replace.iter())
25258                    .find_map(|(selection, range)| {
25259                        if selection.id == newest_selection_id {
25260                            Some(
25261                                (range.start.0.0 as isize - selection.head().0.0 as isize)
25262                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
25263                            )
25264                        } else {
25265                            None
25266                        }
25267                    })
25268            });
25269
25270            cx.emit(EditorEvent::InputHandled {
25271                utf16_range_to_replace: range_to_replace,
25272                text: text.into(),
25273            });
25274
25275            if let Some(ranges) = ranges_to_replace {
25276                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
25277                    s.select_ranges(ranges)
25278                });
25279            }
25280
25281            let marked_ranges = {
25282                let snapshot = this.buffer.read(cx).read(cx);
25283                this.selections
25284                    .disjoint_anchors_arc()
25285                    .iter()
25286                    .map(|selection| {
25287                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
25288                    })
25289                    .collect::<Vec<_>>()
25290            };
25291
25292            if text.is_empty() {
25293                this.unmark_text(window, cx);
25294            } else {
25295                this.highlight_text::<InputComposition>(
25296                    marked_ranges.clone(),
25297                    HighlightStyle {
25298                        underline: Some(UnderlineStyle {
25299                            thickness: px(1.),
25300                            color: None,
25301                            wavy: false,
25302                        }),
25303                        ..Default::default()
25304                    },
25305                    cx,
25306                );
25307            }
25308
25309            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
25310            let use_autoclose = this.use_autoclose;
25311            let use_auto_surround = this.use_auto_surround;
25312            this.set_use_autoclose(false);
25313            this.set_use_auto_surround(false);
25314            this.handle_input(text, window, cx);
25315            this.set_use_autoclose(use_autoclose);
25316            this.set_use_auto_surround(use_auto_surround);
25317
25318            if let Some(new_selected_range) = new_selected_range_utf16 {
25319                let snapshot = this.buffer.read(cx).read(cx);
25320                let new_selected_ranges = marked_ranges
25321                    .into_iter()
25322                    .map(|marked_range| {
25323                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
25324                        let new_start = MultiBufferOffsetUtf16(OffsetUtf16(
25325                            insertion_start.0 + new_selected_range.start,
25326                        ));
25327                        let new_end = MultiBufferOffsetUtf16(OffsetUtf16(
25328                            insertion_start.0 + new_selected_range.end,
25329                        ));
25330                        snapshot.clip_offset_utf16(new_start, Bias::Left)
25331                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
25332                    })
25333                    .collect::<Vec<_>>();
25334
25335                drop(snapshot);
25336                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
25337                    selections.select_ranges(new_selected_ranges)
25338                });
25339            }
25340        });
25341
25342        self.ime_transaction = self.ime_transaction.or(transaction);
25343        if let Some(transaction) = self.ime_transaction {
25344            self.buffer.update(cx, |buffer, cx| {
25345                buffer.group_until_transaction(transaction, cx);
25346            });
25347        }
25348
25349        if self.text_highlights::<InputComposition>(cx).is_none() {
25350            self.ime_transaction.take();
25351        }
25352    }
25353
25354    fn bounds_for_range(
25355        &mut self,
25356        range_utf16: Range<usize>,
25357        element_bounds: gpui::Bounds<Pixels>,
25358        window: &mut Window,
25359        cx: &mut Context<Self>,
25360    ) -> Option<gpui::Bounds<Pixels>> {
25361        let text_layout_details = self.text_layout_details(window);
25362        let CharacterDimensions {
25363            em_width,
25364            em_advance,
25365            line_height,
25366        } = self.character_dimensions(window);
25367
25368        let snapshot = self.snapshot(window, cx);
25369        let scroll_position = snapshot.scroll_position();
25370        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
25371
25372        let start =
25373            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)).to_display_point(&snapshot);
25374        let x = Pixels::from(
25375            ScrollOffset::from(
25376                snapshot.x_for_display_point(start, &text_layout_details)
25377                    + self.gutter_dimensions.full_width(),
25378            ) - scroll_left,
25379        );
25380        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
25381
25382        Some(Bounds {
25383            origin: element_bounds.origin + point(x, y),
25384            size: size(em_width, line_height),
25385        })
25386    }
25387
25388    fn character_index_for_point(
25389        &mut self,
25390        point: gpui::Point<Pixels>,
25391        _window: &mut Window,
25392        _cx: &mut Context<Self>,
25393    ) -> Option<usize> {
25394        let position_map = self.last_position_map.as_ref()?;
25395        if !position_map.text_hitbox.contains(&point) {
25396            return None;
25397        }
25398        let display_point = position_map.point_for_position(point).previous_valid;
25399        let anchor = position_map
25400            .snapshot
25401            .display_point_to_anchor(display_point, Bias::Left);
25402        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
25403        Some(utf16_offset.0.0)
25404    }
25405
25406    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
25407        self.input_enabled
25408    }
25409}
25410
25411trait SelectionExt {
25412    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
25413    fn spanned_rows(
25414        &self,
25415        include_end_if_at_line_start: bool,
25416        map: &DisplaySnapshot,
25417    ) -> Range<MultiBufferRow>;
25418}
25419
25420impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
25421    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
25422        let start = self
25423            .start
25424            .to_point(map.buffer_snapshot())
25425            .to_display_point(map);
25426        let end = self
25427            .end
25428            .to_point(map.buffer_snapshot())
25429            .to_display_point(map);
25430        if self.reversed {
25431            end..start
25432        } else {
25433            start..end
25434        }
25435    }
25436
25437    fn spanned_rows(
25438        &self,
25439        include_end_if_at_line_start: bool,
25440        map: &DisplaySnapshot,
25441    ) -> Range<MultiBufferRow> {
25442        let start = self.start.to_point(map.buffer_snapshot());
25443        let mut end = self.end.to_point(map.buffer_snapshot());
25444        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
25445            end.row -= 1;
25446        }
25447
25448        let buffer_start = map.prev_line_boundary(start).0;
25449        let buffer_end = map.next_line_boundary(end).0;
25450        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
25451    }
25452}
25453
25454impl<T: InvalidationRegion> InvalidationStack<T> {
25455    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
25456    where
25457        S: Clone + ToOffset,
25458    {
25459        while let Some(region) = self.last() {
25460            let all_selections_inside_invalidation_ranges =
25461                if selections.len() == region.ranges().len() {
25462                    selections
25463                        .iter()
25464                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
25465                        .all(|(selection, invalidation_range)| {
25466                            let head = selection.head().to_offset(buffer);
25467                            invalidation_range.start <= head && invalidation_range.end >= head
25468                        })
25469                } else {
25470                    false
25471                };
25472
25473            if all_selections_inside_invalidation_ranges {
25474                break;
25475            } else {
25476                self.pop();
25477            }
25478        }
25479    }
25480}
25481
25482impl<T> Default for InvalidationStack<T> {
25483    fn default() -> Self {
25484        Self(Default::default())
25485    }
25486}
25487
25488impl<T> Deref for InvalidationStack<T> {
25489    type Target = Vec<T>;
25490
25491    fn deref(&self) -> &Self::Target {
25492        &self.0
25493    }
25494}
25495
25496impl<T> DerefMut for InvalidationStack<T> {
25497    fn deref_mut(&mut self) -> &mut Self::Target {
25498        &mut self.0
25499    }
25500}
25501
25502impl InvalidationRegion for SnippetState {
25503    fn ranges(&self) -> &[Range<Anchor>] {
25504        &self.ranges[self.active_index]
25505    }
25506}
25507
25508fn edit_prediction_edit_text(
25509    current_snapshot: &BufferSnapshot,
25510    edits: &[(Range<Anchor>, impl AsRef<str>)],
25511    edit_preview: &EditPreview,
25512    include_deletions: bool,
25513    cx: &App,
25514) -> HighlightedText {
25515    let edits = edits
25516        .iter()
25517        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
25518        .collect::<Vec<_>>();
25519
25520    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
25521}
25522
25523fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
25524    // Fallback for providers that don't provide edit_preview (like Copilot/Supermaven)
25525    // Just show the raw edit text with basic styling
25526    let mut text = String::new();
25527    let mut highlights = Vec::new();
25528
25529    let insertion_highlight_style = HighlightStyle {
25530        color: Some(cx.theme().colors().text),
25531        ..Default::default()
25532    };
25533
25534    for (_, edit_text) in edits {
25535        let start_offset = text.len();
25536        text.push_str(edit_text);
25537        let end_offset = text.len();
25538
25539        if start_offset < end_offset {
25540            highlights.push((start_offset..end_offset, insertion_highlight_style));
25541        }
25542    }
25543
25544    HighlightedText {
25545        text: text.into(),
25546        highlights,
25547    }
25548}
25549
25550pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
25551    match severity {
25552        lsp::DiagnosticSeverity::ERROR => colors.error,
25553        lsp::DiagnosticSeverity::WARNING => colors.warning,
25554        lsp::DiagnosticSeverity::INFORMATION => colors.info,
25555        lsp::DiagnosticSeverity::HINT => colors.info,
25556        _ => colors.ignored,
25557    }
25558}
25559
25560pub fn styled_runs_for_code_label<'a>(
25561    label: &'a CodeLabel,
25562    syntax_theme: &'a theme::SyntaxTheme,
25563    local_player: &'a theme::PlayerColor,
25564) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
25565    let fade_out = HighlightStyle {
25566        fade_out: Some(0.35),
25567        ..Default::default()
25568    };
25569
25570    let mut prev_end = label.filter_range.end;
25571    label
25572        .runs
25573        .iter()
25574        .enumerate()
25575        .flat_map(move |(ix, (range, highlight_id))| {
25576            let style = if *highlight_id == language::HighlightId::TABSTOP_INSERT_ID {
25577                HighlightStyle {
25578                    color: Some(local_player.cursor),
25579                    ..Default::default()
25580                }
25581            } else if *highlight_id == language::HighlightId::TABSTOP_REPLACE_ID {
25582                HighlightStyle {
25583                    background_color: Some(local_player.selection),
25584                    ..Default::default()
25585                }
25586            } else if let Some(style) = highlight_id.style(syntax_theme) {
25587                style
25588            } else {
25589                return Default::default();
25590            };
25591            let muted_style = style.highlight(fade_out);
25592
25593            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
25594            if range.start >= label.filter_range.end {
25595                if range.start > prev_end {
25596                    runs.push((prev_end..range.start, fade_out));
25597                }
25598                runs.push((range.clone(), muted_style));
25599            } else if range.end <= label.filter_range.end {
25600                runs.push((range.clone(), style));
25601            } else {
25602                runs.push((range.start..label.filter_range.end, style));
25603                runs.push((label.filter_range.end..range.end, muted_style));
25604            }
25605            prev_end = cmp::max(prev_end, range.end);
25606
25607            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
25608                runs.push((prev_end..label.text.len(), fade_out));
25609            }
25610
25611            runs
25612        })
25613}
25614
25615pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
25616    let mut prev_index = 0;
25617    let mut prev_codepoint: Option<char> = None;
25618    text.char_indices()
25619        .chain([(text.len(), '\0')])
25620        .filter_map(move |(index, codepoint)| {
25621            let prev_codepoint = prev_codepoint.replace(codepoint)?;
25622            let is_boundary = index == text.len()
25623                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
25624                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
25625            if is_boundary {
25626                let chunk = &text[prev_index..index];
25627                prev_index = index;
25628                Some(chunk)
25629            } else {
25630                None
25631            }
25632        })
25633}
25634
25635/// Given a string of text immediately before the cursor, iterates over possible
25636/// strings a snippet could match to. More precisely: returns an iterator over
25637/// suffixes of `text` created by splitting at word boundaries (before & after
25638/// every non-word character).
25639///
25640/// Shorter suffixes are returned first.
25641pub(crate) fn snippet_candidate_suffixes(
25642    text: &str,
25643    is_word_char: impl Fn(char) -> bool,
25644) -> impl std::iter::Iterator<Item = &str> {
25645    let mut prev_index = text.len();
25646    let mut prev_codepoint = None;
25647    text.char_indices()
25648        .rev()
25649        .chain([(0, '\0')])
25650        .filter_map(move |(index, codepoint)| {
25651            let prev_index = std::mem::replace(&mut prev_index, index);
25652            let prev_codepoint = prev_codepoint.replace(codepoint)?;
25653            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
25654                None
25655            } else {
25656                let chunk = &text[prev_index..]; // go to end of string
25657                Some(chunk)
25658            }
25659        })
25660}
25661
25662pub trait RangeToAnchorExt: Sized {
25663    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
25664
25665    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
25666        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
25667        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
25668    }
25669}
25670
25671impl<T: ToOffset> RangeToAnchorExt for Range<T> {
25672    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
25673        let start_offset = self.start.to_offset(snapshot);
25674        let end_offset = self.end.to_offset(snapshot);
25675        if start_offset == end_offset {
25676            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
25677        } else {
25678            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
25679        }
25680    }
25681}
25682
25683pub trait RowExt {
25684    fn as_f64(&self) -> f64;
25685
25686    fn next_row(&self) -> Self;
25687
25688    fn previous_row(&self) -> Self;
25689
25690    fn minus(&self, other: Self) -> u32;
25691}
25692
25693impl RowExt for DisplayRow {
25694    fn as_f64(&self) -> f64 {
25695        self.0 as _
25696    }
25697
25698    fn next_row(&self) -> Self {
25699        Self(self.0 + 1)
25700    }
25701
25702    fn previous_row(&self) -> Self {
25703        Self(self.0.saturating_sub(1))
25704    }
25705
25706    fn minus(&self, other: Self) -> u32 {
25707        self.0 - other.0
25708    }
25709}
25710
25711impl RowExt for MultiBufferRow {
25712    fn as_f64(&self) -> f64 {
25713        self.0 as _
25714    }
25715
25716    fn next_row(&self) -> Self {
25717        Self(self.0 + 1)
25718    }
25719
25720    fn previous_row(&self) -> Self {
25721        Self(self.0.saturating_sub(1))
25722    }
25723
25724    fn minus(&self, other: Self) -> u32 {
25725        self.0 - other.0
25726    }
25727}
25728
25729trait RowRangeExt {
25730    type Row;
25731
25732    fn len(&self) -> usize;
25733
25734    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
25735}
25736
25737impl RowRangeExt for Range<MultiBufferRow> {
25738    type Row = MultiBufferRow;
25739
25740    fn len(&self) -> usize {
25741        (self.end.0 - self.start.0) as usize
25742    }
25743
25744    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
25745        (self.start.0..self.end.0).map(MultiBufferRow)
25746    }
25747}
25748
25749impl RowRangeExt for Range<DisplayRow> {
25750    type Row = DisplayRow;
25751
25752    fn len(&self) -> usize {
25753        (self.end.0 - self.start.0) as usize
25754    }
25755
25756    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
25757        (self.start.0..self.end.0).map(DisplayRow)
25758    }
25759}
25760
25761/// If select range has more than one line, we
25762/// just point the cursor to range.start.
25763fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
25764    if range.start.row == range.end.row {
25765        range
25766    } else {
25767        range.start..range.start
25768    }
25769}
25770pub struct KillRing(ClipboardItem);
25771impl Global for KillRing {}
25772
25773const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
25774
25775enum BreakpointPromptEditAction {
25776    Log,
25777    Condition,
25778    HitCondition,
25779}
25780
25781struct BreakpointPromptEditor {
25782    pub(crate) prompt: Entity<Editor>,
25783    editor: WeakEntity<Editor>,
25784    breakpoint_anchor: Anchor,
25785    breakpoint: Breakpoint,
25786    edit_action: BreakpointPromptEditAction,
25787    block_ids: HashSet<CustomBlockId>,
25788    editor_margins: Arc<Mutex<EditorMargins>>,
25789    _subscriptions: Vec<Subscription>,
25790}
25791
25792impl BreakpointPromptEditor {
25793    const MAX_LINES: u8 = 4;
25794
25795    fn new(
25796        editor: WeakEntity<Editor>,
25797        breakpoint_anchor: Anchor,
25798        breakpoint: Breakpoint,
25799        edit_action: BreakpointPromptEditAction,
25800        window: &mut Window,
25801        cx: &mut Context<Self>,
25802    ) -> Self {
25803        let base_text = match edit_action {
25804            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
25805            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
25806            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
25807        }
25808        .map(|msg| msg.to_string())
25809        .unwrap_or_default();
25810
25811        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
25812        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
25813
25814        let prompt = cx.new(|cx| {
25815            let mut prompt = Editor::new(
25816                EditorMode::AutoHeight {
25817                    min_lines: 1,
25818                    max_lines: Some(Self::MAX_LINES as usize),
25819                },
25820                buffer,
25821                None,
25822                window,
25823                cx,
25824            );
25825            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
25826            prompt.set_show_cursor_when_unfocused(false, cx);
25827            prompt.set_placeholder_text(
25828                match edit_action {
25829                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
25830                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
25831                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
25832                },
25833                window,
25834                cx,
25835            );
25836
25837            prompt
25838        });
25839
25840        Self {
25841            prompt,
25842            editor,
25843            breakpoint_anchor,
25844            breakpoint,
25845            edit_action,
25846            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
25847            block_ids: Default::default(),
25848            _subscriptions: vec![],
25849        }
25850    }
25851
25852    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
25853        self.block_ids.extend(block_ids)
25854    }
25855
25856    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
25857        if let Some(editor) = self.editor.upgrade() {
25858            let message = self
25859                .prompt
25860                .read(cx)
25861                .buffer
25862                .read(cx)
25863                .as_singleton()
25864                .expect("A multi buffer in breakpoint prompt isn't possible")
25865                .read(cx)
25866                .as_rope()
25867                .to_string();
25868
25869            editor.update(cx, |editor, cx| {
25870                editor.edit_breakpoint_at_anchor(
25871                    self.breakpoint_anchor,
25872                    self.breakpoint.clone(),
25873                    match self.edit_action {
25874                        BreakpointPromptEditAction::Log => {
25875                            BreakpointEditAction::EditLogMessage(message.into())
25876                        }
25877                        BreakpointPromptEditAction::Condition => {
25878                            BreakpointEditAction::EditCondition(message.into())
25879                        }
25880                        BreakpointPromptEditAction::HitCondition => {
25881                            BreakpointEditAction::EditHitCondition(message.into())
25882                        }
25883                    },
25884                    cx,
25885                );
25886
25887                editor.remove_blocks(self.block_ids.clone(), None, cx);
25888                cx.focus_self(window);
25889            });
25890        }
25891    }
25892
25893    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
25894        self.editor
25895            .update(cx, |editor, cx| {
25896                editor.remove_blocks(self.block_ids.clone(), None, cx);
25897                window.focus(&editor.focus_handle);
25898            })
25899            .log_err();
25900    }
25901
25902    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
25903        let settings = ThemeSettings::get_global(cx);
25904        let text_style = TextStyle {
25905            color: if self.prompt.read(cx).read_only(cx) {
25906                cx.theme().colors().text_disabled
25907            } else {
25908                cx.theme().colors().text
25909            },
25910            font_family: settings.buffer_font.family.clone(),
25911            font_fallbacks: settings.buffer_font.fallbacks.clone(),
25912            font_size: settings.buffer_font_size(cx).into(),
25913            font_weight: settings.buffer_font.weight,
25914            line_height: relative(settings.buffer_line_height.value()),
25915            ..Default::default()
25916        };
25917        EditorElement::new(
25918            &self.prompt,
25919            EditorStyle {
25920                background: cx.theme().colors().editor_background,
25921                local_player: cx.theme().players().local(),
25922                text: text_style,
25923                ..Default::default()
25924            },
25925        )
25926    }
25927}
25928
25929impl Render for BreakpointPromptEditor {
25930    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25931        let editor_margins = *self.editor_margins.lock();
25932        let gutter_dimensions = editor_margins.gutter;
25933        h_flex()
25934            .key_context("Editor")
25935            .bg(cx.theme().colors().editor_background)
25936            .border_y_1()
25937            .border_color(cx.theme().status().info_border)
25938            .size_full()
25939            .py(window.line_height() / 2.5)
25940            .on_action(cx.listener(Self::confirm))
25941            .on_action(cx.listener(Self::cancel))
25942            .child(h_flex().w(gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0)))
25943            .child(div().flex_1().child(self.render_prompt_editor(cx)))
25944    }
25945}
25946
25947impl Focusable for BreakpointPromptEditor {
25948    fn focus_handle(&self, cx: &App) -> FocusHandle {
25949        self.prompt.focus_handle(cx)
25950    }
25951}
25952
25953fn all_edits_insertions_or_deletions(
25954    edits: &Vec<(Range<Anchor>, Arc<str>)>,
25955    snapshot: &MultiBufferSnapshot,
25956) -> bool {
25957    let mut all_insertions = true;
25958    let mut all_deletions = true;
25959
25960    for (range, new_text) in edits.iter() {
25961        let range_is_empty = range.to_offset(snapshot).is_empty();
25962        let text_is_empty = new_text.is_empty();
25963
25964        if range_is_empty != text_is_empty {
25965            if range_is_empty {
25966                all_deletions = false;
25967            } else {
25968                all_insertions = false;
25969            }
25970        } else {
25971            return false;
25972        }
25973
25974        if !all_insertions && !all_deletions {
25975            return false;
25976        }
25977    }
25978    all_insertions || all_deletions
25979}
25980
25981struct MissingEditPredictionKeybindingTooltip;
25982
25983impl Render for MissingEditPredictionKeybindingTooltip {
25984    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
25985        ui::tooltip_container(cx, |container, cx| {
25986            container
25987                .flex_shrink_0()
25988                .max_w_80()
25989                .min_h(rems_from_px(124.))
25990                .justify_between()
25991                .child(
25992                    v_flex()
25993                        .flex_1()
25994                        .text_ui_sm(cx)
25995                        .child(Label::new("Conflict with Accept Keybinding"))
25996                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
25997                )
25998                .child(
25999                    h_flex()
26000                        .pb_1()
26001                        .gap_1()
26002                        .items_end()
26003                        .w_full()
26004                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
26005                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
26006                        }))
26007                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
26008                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
26009                        })),
26010                )
26011        })
26012    }
26013}
26014
26015#[derive(Debug, Clone, Copy, PartialEq)]
26016pub struct LineHighlight {
26017    pub background: Background,
26018    pub border: Option<gpui::Hsla>,
26019    pub include_gutter: bool,
26020    pub type_id: Option<TypeId>,
26021}
26022
26023struct LineManipulationResult {
26024    pub new_text: String,
26025    pub line_count_before: usize,
26026    pub line_count_after: usize,
26027}
26028
26029fn render_diff_hunk_controls(
26030    row: u32,
26031    status: &DiffHunkStatus,
26032    hunk_range: Range<Anchor>,
26033    is_created_file: bool,
26034    line_height: Pixels,
26035    editor: &Entity<Editor>,
26036    _window: &mut Window,
26037    cx: &mut App,
26038) -> AnyElement {
26039    h_flex()
26040        .h(line_height)
26041        .mr_1()
26042        .gap_1()
26043        .px_0p5()
26044        .pb_1()
26045        .border_x_1()
26046        .border_b_1()
26047        .border_color(cx.theme().colors().border_variant)
26048        .rounded_b_lg()
26049        .bg(cx.theme().colors().editor_background)
26050        .gap_1()
26051        .block_mouse_except_scroll()
26052        .shadow_md()
26053        .child(if status.has_secondary_hunk() {
26054            Button::new(("stage", row as u64), "Stage")
26055                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
26056                .tooltip({
26057                    let focus_handle = editor.focus_handle(cx);
26058                    move |_window, cx| {
26059                        Tooltip::for_action_in(
26060                            "Stage Hunk",
26061                            &::git::ToggleStaged,
26062                            &focus_handle,
26063                            cx,
26064                        )
26065                    }
26066                })
26067                .on_click({
26068                    let editor = editor.clone();
26069                    move |_event, _window, cx| {
26070                        editor.update(cx, |editor, cx| {
26071                            editor.stage_or_unstage_diff_hunks(
26072                                true,
26073                                vec![hunk_range.start..hunk_range.start],
26074                                cx,
26075                            );
26076                        });
26077                    }
26078                })
26079        } else {
26080            Button::new(("unstage", row as u64), "Unstage")
26081                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
26082                .tooltip({
26083                    let focus_handle = editor.focus_handle(cx);
26084                    move |_window, cx| {
26085                        Tooltip::for_action_in(
26086                            "Unstage Hunk",
26087                            &::git::ToggleStaged,
26088                            &focus_handle,
26089                            cx,
26090                        )
26091                    }
26092                })
26093                .on_click({
26094                    let editor = editor.clone();
26095                    move |_event, _window, cx| {
26096                        editor.update(cx, |editor, cx| {
26097                            editor.stage_or_unstage_diff_hunks(
26098                                false,
26099                                vec![hunk_range.start..hunk_range.start],
26100                                cx,
26101                            );
26102                        });
26103                    }
26104                })
26105        })
26106        .child(
26107            Button::new(("restore", row as u64), "Restore")
26108                .tooltip({
26109                    let focus_handle = editor.focus_handle(cx);
26110                    move |_window, cx| {
26111                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
26112                    }
26113                })
26114                .on_click({
26115                    let editor = editor.clone();
26116                    move |_event, window, cx| {
26117                        editor.update(cx, |editor, cx| {
26118                            let snapshot = editor.snapshot(window, cx);
26119                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
26120                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
26121                        });
26122                    }
26123                })
26124                .disabled(is_created_file),
26125        )
26126        .when(
26127            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
26128            |el| {
26129                el.child(
26130                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
26131                        .shape(IconButtonShape::Square)
26132                        .icon_size(IconSize::Small)
26133                        // .disabled(!has_multiple_hunks)
26134                        .tooltip({
26135                            let focus_handle = editor.focus_handle(cx);
26136                            move |_window, cx| {
26137                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
26138                            }
26139                        })
26140                        .on_click({
26141                            let editor = editor.clone();
26142                            move |_event, window, cx| {
26143                                editor.update(cx, |editor, cx| {
26144                                    let snapshot = editor.snapshot(window, cx);
26145                                    let position =
26146                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
26147                                    editor.go_to_hunk_before_or_after_position(
26148                                        &snapshot,
26149                                        position,
26150                                        Direction::Next,
26151                                        window,
26152                                        cx,
26153                                    );
26154                                    editor.expand_selected_diff_hunks(cx);
26155                                });
26156                            }
26157                        }),
26158                )
26159                .child(
26160                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
26161                        .shape(IconButtonShape::Square)
26162                        .icon_size(IconSize::Small)
26163                        // .disabled(!has_multiple_hunks)
26164                        .tooltip({
26165                            let focus_handle = editor.focus_handle(cx);
26166                            move |_window, cx| {
26167                                Tooltip::for_action_in(
26168                                    "Previous Hunk",
26169                                    &GoToPreviousHunk,
26170                                    &focus_handle,
26171                                    cx,
26172                                )
26173                            }
26174                        })
26175                        .on_click({
26176                            let editor = editor.clone();
26177                            move |_event, window, cx| {
26178                                editor.update(cx, |editor, cx| {
26179                                    let snapshot = editor.snapshot(window, cx);
26180                                    let point =
26181                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
26182                                    editor.go_to_hunk_before_or_after_position(
26183                                        &snapshot,
26184                                        point,
26185                                        Direction::Prev,
26186                                        window,
26187                                        cx,
26188                                    );
26189                                    editor.expand_selected_diff_hunks(cx);
26190                                });
26191                            }
26192                        }),
26193                )
26194            },
26195        )
26196        .into_any_element()
26197}
26198
26199pub fn multibuffer_context_lines(cx: &App) -> u32 {
26200    EditorSettings::try_get(cx)
26201        .map(|settings| settings.excerpt_context_lines)
26202        .unwrap_or(2)
26203        .min(32)
26204}